Compare commits

..

1 Commits

Author SHA1 Message Date
sdk-dev d6c2b701b6 fix(examples): correct stale import path in remote-agent/run.py
[Do] Merge queue: CI checks green, merge queue ready
sop-checklist / all-items-acked SOP checklist acknowledged
Test / test (3.12) (pull_request) Successful in 1m30s
Test / test (3.11) (pull_request) Successful in 1m45s
Test / test (3.13) (pull_request) Successful in 1m33s
The old path `sdk/python/` no longer exists in the standalone
molecule-sdk-python repo. Update the local-dev import path to add
the repo root to sys.path, which correctly resolves molecule_agent
when running the script from a repo checkout.

Also update the Usage section to use the correct relative path
(`examples/remote-agent/run.py` instead of `python3 run.py`)
and update the "What it doesn't do" docstring to reflect that
Phase 30.8b (inbound A2A) is now shipped.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 20:36:12 +00:00
5 changed files with 19 additions and 56 deletions
+1 -22
View File
@@ -1,4 +1,4 @@
name: CI
name: Test
on:
push:
@@ -27,24 +27,3 @@ 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."
-15
View File
@@ -219,21 +219,6 @@ 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
+13 -9
View File
@@ -8,9 +8,11 @@ What this does:
3. Runs a heartbeat + state-poll loop; exits cleanly when the platform
reports the workspace paused or deleted.
What it doesn't do (future 30.8b work):
- Host an inbound A2A server. Platform-initiated calls to this agent
won't reach it unless you expose one yourself.
What it doesn't do (see run_agent_loop for the full version):
- Host an inbound A2A server. Use run_agent_loop(handler) instead of
run_heartbeat_loop() to also receive inbound A2A messages and reply
via the platform's /notify (canvas user) and /a2a (peer agent) endpoints.
The reply transport is auto-selected based on message source.
Usage:
# One-time setup on the platform side:
@@ -26,7 +28,7 @@ Usage:
-d '{"key":"REMOTE_DEMO_KEY","value":"hello-from-remote"}'
# Now run this script from any machine that can reach the platform:
WORKSPACE_ID=<id> PLATFORM_URL=http://localhost:8080 python3 run.py
WORKSPACE_ID=<id> PLATFORM_URL=http://localhost:8080 python3 examples/remote-agent/run.py
Environment variables:
WORKSPACE_ID (required)
@@ -41,12 +43,14 @@ import os
import sys
# Local-dev import path — when installed via pip the molecule_agent package
# resolves normally; when running from the repo checkout we add sdk/python/
# to sys.path so you can run `python3 run.py` without a pip install.
# resolves normally; when running from the repo checkout we add the repo root
# to sys.path so you can run `python3 examples/remote-agent/run.py` without
# a pip install.
_here = os.path.dirname(os.path.abspath(__file__))
_sdk = os.path.join(_here, "..", "..", "sdk", "python")
if os.path.isdir(_sdk) and _sdk not in sys.path:
sys.path.insert(0, _sdk)
_repo_root = os.path.normpath(os.path.join(_here, "..", ".."))
_molecule_agent = os.path.join(_repo_root, "molecule_agent")
if os.path.isdir(_molecule_agent) and _repo_root not in sys.path:
sys.path.insert(0, _repo_root)
from molecule_agent import RemoteAgentClient # noqa: E402
+4 -7
View File
@@ -54,11 +54,8 @@ 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
# or until stop_event.set() is called from another thread.
import threading
stop = threading.Event()
terminal = client.run_heartbeat_loop(stop_event=stop)
# 4. Run the heartbeat + state-poll loop until the platform pauses/deletes us.
terminal = client.run_heartbeat_loop()
print(f"loop exited: {terminal}")
```
@@ -78,8 +75,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(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) |
| `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 |
## Inbound delivery — push vs poll
+1 -3
View File
@@ -9,7 +9,6 @@ and detect pause/resume/delete — all via the Phase 30.130.5 HTTP contract.
Intended usage::
import threading
from molecule_agent import RemoteAgentClient
client = RemoteAgentClient(
@@ -19,8 +18,7 @@ Intended usage::
)
client.register() # mints + persists the auth token
env = client.pull_secrets() # decrypted secrets dict
stop = threading.Event()
client.run_heartbeat_loop(stop_event=stop) # background heartbeat; stop.set() to exit cleanly
client.run_heartbeat_loop() # background heartbeat + state-poll
See ``sdk/python/examples/remote-agent/`` for a runnable demo.