Skip to content

v0.3.1

Choose a tag to compare

@jin-bo jin-bo released this 01 May 01:50
· 146 commits to main since this release

Agentao 0.3.1

Lands the embedded harness contract — the stable host-facing
API surface for embedding Agentao inside another application. Hosts
can now subscribe to a typed event stream, read a JSON-safe snapshot
of the active permission policy, and rely on checked-in JSON schema
snapshots that protect both the public events and the ACP payloads
across releases. This is an Added-only patch in the 0.3.x
series; no required code change to upgrade from 0.3.0. CLI and ACP
behavior is unchanged because both consume the same public surface.

Highlights

  • agentao.harness public package — the host-facing
    compatibility boundary. Exports ActivePermissions,
    ToolLifecycleEvent, SubagentLifecycleEvent,
    PermissionDecisionEvent, HarnessEvent (discriminated union),
    EventStream, StreamSubscribeError, RFC3339UTCString, and
    the schema export helpers. Internal runtime types
    (AgentEvent, ToolExecutionResult, PermissionEngine) are
    deliberately not re-exported — the harness package is the
    version-stable boundary. Hosts that target only agentao.harness
    (plus the Agentao(...) constructor and the two methods below)
    stay forward-compatible across releases.

  • Agentao.events(session_id=None) — async iterator over
    HarnessEvent. No replay; bounded backpressure; same-session
    ordering guaranteed; PermissionDecisionEvent precedes
    ToolLifecycleEvent(phase="started") for the same
    tool_call_id. MVP supports one consumer per Agentao
    instance. Public events deliberately omit raw tool args, raw
    stdout/stderr, raw diffs, and MCP raw responses — only
    redacted/truncated summary / task_summary / reason strings
    reach hosts.

  • Agentao.active_permissions() — JSON-safe snapshot of the
    active policy (mode, rules, loaded_sources). Cached; the
    cache invalidates on set_mode() and on add_loaded_source(...)
    with a new label. loaded_sources carries stable string labels
    (preset:<mode>, project:<path>, user:<path>,
    injected:<name>); MVP intentionally does not expose per-rule
    provenance — hosts that need it combine loaded_sources with
    their own injected metadata.

  • Schema snapshots and CI drift check — every release ships
    checked-in JSON schema snapshots
    (docs/schema/harness.events.v1.json,
    docs/schema/harness.acp.v1.json). Generated from the Pydantic
    models and byte-equality-checked by
    tests/test_harness_schema.py and tests/test_acp_schema.py. A
    new fast-fail step in CI Job 0
    (scripts/write_harness_schema.py --check) catches drift before
    the test matrix runs.

  • Three public lifecycle event familiesToolLifecycleEvent,
    SubagentLifecycleEvent, PermissionDecisionEvent. Tool
    cancellation surfaces as phase="failed", outcome="cancelled"; sub-agent cancellation surfaces as a
    distinct phase="cancelled" (lineage tracking benefits from the
    explicit phase). PermissionDecisionEvent fires on every
    decision — allow, deny, or prompt — not only on
    deny/prompt; consumers that don't render allow events still must
    drain the iterator to avoid backpressure.

  • CLI as the first hostcli /status now reads the
    permission-mode banner from agent.active_permissions() and
    displays loaded_sources for transparency. The CLI consumes the
    same public surface external embedders use; future hosts inherit
    the same behavior.

Tests

2229 passing on the post-release baseline (no regressions from
0.3.0). New harness-specific suites:

  • tests/test_harness_schema.py — byte-equality drift check
    between docs/schema/harness.events.v1.json and the generator
    output; discriminated-union validation; RFC 3339 UTC timestamp
    acceptance/rejection (canonical Z only, +00:00 rejected).
  • tests/test_acp_schema.py — same byte-equality check for
    docs/schema/harness.acp.v1.json plus payload coverage.
  • tests/test_active_permissions.py — project-only / user+project
    / preset-only / injected / no-engine fallback paths; cache
    invalidation; JSON-safety.
  • tests/test_harness_event_stream.py — ordering, no-subscriber
    drop, mid-turn subscription, bounded backpressure, cancellation
    cleanup, StreamSubscribeError on duplicate subscribe.
  • tests/test_harness_tool_events.py — sync + AsyncTool lifecycle;
    raw args/output not leaked; stable error_type identifiers;
    cancellation under phase="failed", outcome="cancelled".
  • tests/test_harness_permission_events.py — allow/deny/prompt
    fan-out; decision_id uniqueness; ordering vs tool lifecycle.
  • tests/test_harness_subagent_events.py — spawn-and-terminal
    pairing; cancelled phase; redacted task_summary.
  • tests/test_cli_harness_events.py — CLI rendering of public
    lifecycle events.

Companion fix: tests/test_outbound_sanitize.py adds
TestNormalizeToolCallsMissingId to lock the
missing-tool-call-id regression (see Changed below).

Upgrade (from 0.3.0)

0.3.1 is strictly backwards-compatible. No required code
change. Existing calls into Agentao(...),
build_from_environment(...), capability protocols, and the
transport layer keep working.

What's available to opt into:

from agentao.harness import (
    ToolLifecycleEvent,
    PermissionDecisionEvent,
    SubagentLifecycleEvent,
)

# Subscribe to lifecycle events
async for ev in agent.events():
    if isinstance(ev, ToolLifecycleEvent):
        ...

# Read the active policy snapshot
snap = agent.active_permissions()
print(snap.mode, snap.loaded_sources)

A runnable end-to-end demo lives at examples/harness_events.py.
The full embedding walkthrough is in docs/EMBEDDING.md §7
"Host-facing harness contract"; the API reference is at
docs/api/harness.md.

New dependency. pydantic>=2 is now a direct dependency. If
your environment pins Pydantic v1, lift the pin before upgrading.

What stays internal. agentao.transport.AgentEvent /
Transport.emit(...), agentao.runtime.identity.*, and
agentao.harness.projection.* are not part of the host-facing
contract and may change in any release. Production hosts should
target agentao.harness only.

SemVer note

0.3.1 is an Added-only patch — the 0.3.x series treats
additive public surfaces as patch-eligible during pre-1.0. Strict
SemVer consumers should read it as equivalent to a minor bump.
There are no removed fields, no renamed enum values, and no
changed semantics on existing surfaces.

Release Summary

  • Version: 0.3.1
  • Git tag: v0.3.1
  • GitHub release type: regular release, not pre-release
  • Publish workflow: .github/workflows/publish.yml

Install

pip install -U agentao

Maintainer Checklist

  1. Confirm agentao/__init__.py reports 0.3.1 (drop the .dev0
    suffix from 0.3.1.dev0).
  2. Run the smoke path:
    uv run python -m pytest tests/ \
      && uv run python scripts/write_harness_schema.py --check \
      && uv run python scripts/write_replay_schema.py --check \
      && uv build \
      && uv run twine check dist/*
  3. Push the tag:
    git push origin v0.3.1
  4. Create the GitHub release for v0.3.1.
  5. Leave Set as a pre-release unchecked so
    .github/workflows/publish.yml publishes to PyPI (the workflow's
    tag-vs-package version consistency check will validate alignment
    before upload).

Full Changelog

See CHANGELOG.md for the 0.3.1 entry.