docs(sdk): document stop_event parameter in CLAUDE.md, README, and __init__ #24
+22
-1
@@ -1,4 +1,4 @@
|
||||
name: Test
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -27,3 +27,24 @@ jobs:
|
||||
|
||||
- name: Lint
|
||||
run: pip install ruff && ruff check molecule_agent/ molecule_plugin/
|
||||
|
||||
all-required:
|
||||
name: all-required
|
||||
needs: [test]
|
||||
# required: all matrix variants must succeed
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Verify all required jobs passed
|
||||
run: |
|
||||
# Collect results from all test matrix variants
|
||||
results="${{ needs.test.result }}"
|
||||
echo "Matrix results: $results"
|
||||
# Any result that is not "success" is a failure condition
|
||||
if [[ "$results" == *"failure"* ]] || \
|
||||
[[ "$results" == *"cancelled"* ]] || \
|
||||
[[ "$results" == *"skipped"* ]]; then
|
||||
echo "One or more required jobs did not succeed: $results"
|
||||
exit 1
|
||||
fi
|
||||
echo "All required jobs passed."
|
||||
|
||||
@@ -219,6 +219,21 @@ python -m molecule_agent verify-sha256 ./my-plugin-dir
|
||||
shut the loop down cleanly. Cursor optionally persisted to `--cursor-file` so
|
||||
restarts resume from the last-seen activity row.
|
||||
|
||||
- **`run_heartbeat_loop(stop_event)` and `run_agent_loop(stop_event)`** (KI-009):
|
||||
Both loops accept an optional `threading.Event` parameter. When the event is set
|
||||
from another thread, the loop exits immediately with return value `"stopped"`.
|
||||
The check runs before `max_iterations` so a signal always wins. Useful for
|
||||
embedding the client in a long-running process that needs a clean shutdown path:
|
||||
```python
|
||||
import threading, time
|
||||
from molecule_agent import RemoteAgentClient
|
||||
stop = threading.Event()
|
||||
client = RemoteAgentClient(...)
|
||||
# Signal-safe: call stop.set() from any thread to stop the loop
|
||||
terminal = client.run_heartbeat_loop(stop_event=stop)
|
||||
# terminal == "stopped" if stop.set() was called, else "paused"/"deleted"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Relevant platform docs
|
||||
|
||||
@@ -54,8 +54,11 @@ secrets = client.pull_secrets()
|
||||
client.install_plugin("molecule-dev")
|
||||
client.install_plugin("my-plugin", source="github://acme/my-plugin")
|
||||
|
||||
# 4. Run the heartbeat + state-poll loop until the platform pauses/deletes us.
|
||||
terminal = client.run_heartbeat_loop()
|
||||
# 4. Run the heartbeat + state-poll loop until the platform pauses/deletes us
|
||||
# or until stop_event.set() is called from another thread.
|
||||
import threading
|
||||
stop = threading.Event()
|
||||
terminal = client.run_heartbeat_loop(stop_event=stop)
|
||||
print(f"loop exited: {terminal}")
|
||||
```
|
||||
|
||||
@@ -75,8 +78,8 @@ A runnable demo with full setup walkthrough lives at
|
||||
| `call_peer(target, message)` | 30.6 | Direct A2A with proxy fallback; response may be wrapped in OFFSEC-003 boundary markers — use ``strip_a2a_boundary()`` to remove them |
|
||||
| `fetch_inbound(since_id=…)` | 30.8c | One-shot poll of `/workspaces/:id/activity` for inbound A2A |
|
||||
| `reply(msg, text)` | 30.8c | Smart-routes reply to `/notify` (canvas user) or `/a2a` (peer) |
|
||||
| `run_heartbeat_loop()` | combo | Drives heartbeat + state-poll on a timer; exits on pause/delete |
|
||||
| `run_agent_loop(handler)` | combo | Heartbeat + state + **inbound dispatch**; exits on pause/delete |
|
||||
| `run_heartbeat_loop(stop_event=None)` | combo | Drives heartbeat + state-poll on a timer; exits on pause/delete or when `stop_event.set()` is called from another thread (KI-009) |
|
||||
| `run_agent_loop(handler, stop_event=None)` | combo | Heartbeat + state + **inbound dispatch**; exits on pause/delete or when `stop_event.set()` is called from another thread (KI-009) |
|
||||
|
||||
## Inbound delivery — push vs poll
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ and detect pause/resume/delete — all via the Phase 30.1–30.5 HTTP contract.
|
||||
|
||||
Intended usage::
|
||||
|
||||
import threading
|
||||
from molecule_agent import RemoteAgentClient
|
||||
|
||||
client = RemoteAgentClient(
|
||||
@@ -18,7 +19,8 @@ Intended usage::
|
||||
)
|
||||
client.register() # mints + persists the auth token
|
||||
env = client.pull_secrets() # decrypted secrets dict
|
||||
client.run_heartbeat_loop() # background heartbeat + state-poll
|
||||
stop = threading.Event()
|
||||
client.run_heartbeat_loop(stop_event=stop) # background heartbeat; stop.set() to exit cleanly
|
||||
|
||||
See ``sdk/python/examples/remote-agent/`` for a runnable demo.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user