Resolves KI-009. Both loops now accept a threading.Event that, when set,
causes immediate clean exit with return value "stopped". The check is
ordered before max_iterations so a signal always wins.
New tests:
- test_run_loop_exits_on_stop_event: event set before loop — 0 iterations
- test_run_loop_respects_stop_event_between_iterations: event set mid-run
- test_run_agent_loop_exits_on_stop_event: same for run_agent_loop
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Platform now wraps peer A2A responses in [A2A_RESULT_FROM_PEER]...
[/A2A_RESULT_FROM_PEER] markers (OFFSEC-003) to mark them as untrusted
third-party content. This change adds:
- strip_a2a_boundary(text): strips the wrapper and returns the interior
content. Safe on pre-OFFSEC-003 responses (returns input unchanged when
markers absent or malformed) and on None/empty.
Exported from molecule_agent/__init__.py and added to __all__.
README updated with a dedicated OFFSEC-003 section and call_peer() table
note pointing to strip_a2a_boundary().
8 new tests: basic, whitespace edges, no-markers passthrough, only-start,
only-end, empty/None, end-before-start edge case, multiline content.
305 total tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds optional org_id and origin constructor kwargs that inject
X-Molecule-Org-Id and Origin headers on every request, enabling
SDK use against multi-tenant SaaS deployments (*.moleculesai.app)
without needing a pre-configured requests.Session.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
KI-002: prevent duplicate delegation execution when a remote agent
container restarts mid-delegation. Remote agent clients now compute a
SHA-256 key from task_text + current wall-clock minute and POST it as
idempotency_key to /workspaces/:id/delegate.
The platform deduplicates requests sharing the same key within the
minute window. Callers can also pass an explicit idempotency_key to
override the auto-computed value.
New:
- make_idempotency_key(task_text) → str
- RemoteAgentClient.delegate(task, target_id, idempotency_key=None, timeout=300.0)
- 8 new unit tests covering headers, errors, explicit key override, and
make_idempotency_key invariants
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
_symlink entries in plugin tarballs are skipped (security posture, correct) but
now emit a logger.warning so operators can audit what was dropped:
"skipping symlink in plugin tarball (not supported for security): <name> -> <target>"
Added test_safe_extract_logs_warning_for_skipped_symlink asserting the warning
is present in caplog records at WARNING level. All 211 tests pass (+1 new).
known-issues.md updated.
* feat(security): add plugin content integrity verification (SHA256)
SDK-side follow-up to molecule-core PR #1019 (pinned-ref supply-chain fix).
Changes:
- verify_plugin_sha256(plugin_dir, expected_sha) — content-addressed manifest
hash over sorted (relpath, SHA256(content)) pairs; plugin.yaml excluded
from its own hash to avoid circular dependency
- _walk_files(root) / _sha256_file(path) — internal helpers
- install_plugin() calls verify_sha256 after atomic rename; on mismatch
deletes plugin dir and raises ValueError before setup.sh runs
- PLUGIN_YAML_SCHEMA gains optional sha256 field (64-char lowercase hex)
- validate_manifest() validates sha256 format when present
Tests (12 new):
- sha256_file correctness, walk_files ordering, verify_* (match/mismatch/invalid)
- install_plugin sha256 verified: setup.sh runs
- install_plugin sha256 mismatch: raises ValueError, setup.sh NOT run
- install_plugin no sha256: backward-compat, skips verification
- validate_manifest sha256: valid/invalid/non-hex/absent
Pre-existing: 4 async tests in test_sdk.py fail without pytest-asyncio
(not related to this change).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(tests): add pytest-asyncio markers to async adaptor tests
The 4 tests using async def were failing because pytest-asyncio was not
installed and pytest.ini set asyncio_mode=auto (which requires it). Add
@pytest.mark.asyncio to each async test and add pytest-asyncio as a
test optional dependency so CI gets the right extras when installing.
Fixes: 4 FAILED tests in test_sdk.py
---------
Co-authored-by: Molecule AI SDK-Dev <sdk-dev@agents.moleculesai.app>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>