Skip to content

feat(agy-acp): streaming + real cancel + id:Value#1087

Open
chaodu-agent wants to merge 11 commits into
mainfrom
feat/agy-acp-streaming-cancel
Open

feat(agy-acp): streaming + real cancel + id:Value#1087
chaodu-agent wants to merge 11 commits into
mainfrom
feat/agy-acp-streaming-cancel

Conversation

@chaodu-agent

@chaodu-agent chaodu-agent commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

Comprehensive upgrade to agy-acp, inspired by hicder/agy-acp fork.

Changes

1. Streaming (1s SQLite polling)

  • Spawns agy as subprocess, polls SQLite DB every 1 second
  • Emits incremental session/update notifications as text arrives
  • Users see responses progressively instead of waiting for completion

2. Tool Call Parsing

  • Parses step_type 5/7/8/9/17/21/33/101/138 from SQLite (protobuf field 5.4)
  • Extracts tool name + input JSON
  • Emits tool_call sessionUpdate with title, toolCallId, rawInput
  • OAB can use OPENAB_TOOL_DISPLAY to control verbosity

3. Narration Default Skip

  • "I will ..." narration is now SKIPPED by default
  • Set OPENAB_SHOW_NARRATION=1 to opt-in showing narration
  • Removes old OPENAB_TOOL_DISPLAY dependency for narration

4. Real Cancel

  • session/cancel kills the agy child process via AtomicBool + child.kill()
  • Returns stopReason: "cancelled"

5. Model Selector

  • Runs agy models at startup, exposes as ACP configOptions
  • Handles session/setConfigOption to persist model per session
  • Passes --model to agy subprocess

6. JSON-RPC id: Value

  • Supports string or number IDs per spec

7. Non-blocking Main Loop

  • All adapter-lock handlers spawned into background tasks
  • Main loop stays responsive to cancel during long prompts

Environment Variables

Variable Default Description
OPENAB_SHOW_NARRATION unset (skip) Set to 1 to show "I will..." narration
OPENAB_TOOL_DISPLAY Used by OAB to control tool call verbosity
AGY_EXTRA_ARGS Extra args passed to every agy invocation

Tests

  • All 28 tests pass (15 unit + 13 filesystem I/O)
  • New: streaming delta, JSON-RPC id type tests

- Streaming: spawn agy as subprocess, poll SQLite every 1s for new text,
  emit incremental session/update notifications as text arrives
- Real cancel: AtomicBool + child.kill() on session/cancel instead of no-op
- JSON-RPC id: change from u64 to Value for spec compliance (supports string IDs)
- Main loop: async with mpsc channels to handle concurrent prompt + cancel
- New test: streaming delta polling unit test + JSON-RPC id type tests

Inspired by hicder/agy-acp fork.
@chaodu-agent chaodu-agent requested a review from thepagent as a code owner June 12, 2026 00:50
超渡法師 added 5 commits June 12, 2026 00:53
Fixes from 擺渡法師 review:

1. 🔴 Event-loop deadlock: spawn all adapter-lock handlers (initialize,
   session/new, session/load) into background tasks so main loop stays
   responsive to cancel requests during long prompts.

2. 🔴 OPENAB_TOOL_DISPLAY: streaming path now respects narration filtering —
   skips narration-only text chunks when env var is set to compact/none/off.

3. 🟡 Silent failure: when agy exits non-zero after partial streaming,
   stopReason is now 'error' instead of 'end_turn'.
- Run `agy models` at startup to discover available models
- Return configOptions in session/new response with model selector
- Handle session/setConfigOption to persist model choice per session
- Pass --model to agy subprocess when model is selected
- Persist model_id in sessions.json for restore across restarts
Replace Adapter::new() with struct literal in
test_initialize_advertises_load_session_support to avoid
implicit agy subprocess execution in pure unit tests.
Tool call parsing:
- Parse step_type 5/7/8/9/17/21/33/101/138 from SQLite (protobuf field 5.4)
- Extract tool name + input JSON from step_payload
- Emit 'tool_call' sessionUpdate notifications with title, toolCallId, rawInput
- OAB can use OPENAB_TOOL_DISPLAY to control verbosity of these

Narration default change:
- Narration ('I will ...') is now SKIPPED by default in both streaming and batch
- Set OPENAB_SHOW_NARRATION=1 to opt-in showing narration
- Removes dependency on OPENAB_TOOL_DISPLAY for narration filtering
1. tool_call contract: emit tool_call (start) + tool_call_update
   (completed) as two separate notifications so OAB client correctly
   transitions ToolStart → ToolDone (fixes infinite spinner).

2. Backward compat: OPENAB_TOOL_DISPLAY=full still shows narration,
   alongside new OPENAB_SHOW_NARRATION=1. Default remains skip.
@chaodu-agent

chaodu-agent commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator Author

Outdated — see final summary below

@chaodu-agent

chaodu-agent commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator Author

Outdated — see final summary below

- F1: Extract session state into prepare_prompt_state(); adapter lock is
  released before subprocess spawn so concurrent requests (e.g. cancel)
  are not blocked.
- F2: Reduce poller sleep from 1s to 100ms for faster streaming delta
  delivery.
- F3: Route all poller stdout writes through the out_tx mpsc channel
  instead of direct io::stdout() writes, eliminating line interleaving.
@chaodu-agent

chaodu-agent commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator Author

Outdated — see final summary below

- F4: Defer `agy models` call to first use (lazy init) with 5s timeout,
  eliminating startup blocking risk for CI/build gates.
- F5: Replace split_whitespace with shell_words::split for proper
  quoted-arg handling in AGY_EXTRA_ARGS; malformed input is logged and
  skipped.
@chaodu-agent

chaodu-agent commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator Author

Outdated — see final summary below

- Dockerfile.agentcore: remove Python/pip/uv/boto3, single binary only (~20MB)
- docs/agentcore.md: update architecture diagram, prerequisites, IAM policy,
  config examples to reflect WebSocket shell bridge
@chaodu-agent

Copy link
Copy Markdown
Collaborator Author

超渡法師 — Coordinator Final Review (PR #1087)

LGTM ✅ — all reviewer findings resolved.

Review Participation

Reviewer Angle Verdict
擺渡法師 (Codex) Architecture & regression risk CHANGES REQUESTED → ✅ resolved
口渡法師 (Copilot) Security & CI CHANGES REQUESTED → ✅ resolved

All Findings Resolved

# Sev Finding Commit
1 🔴 Mutex lock contention during subprocess 354fecc
2 🟡 Poller 1s sleep latency 354fecc
3 🟡 stdout race condition (poller vs main loop) 354fecc
4 🟡 Synchronous agy models blocks startup d4c56ab
5 🟡 AGY_EXTRA_ARGS unsafe split_whitespace d4c56ab

Fix Details

354fecc — Lock scope reduction + poll/output channel

  • Session state extracted via prepare_prompt_state() before spawn; adapter lock not held during subprocess execution
  • Poll interval: 1s → 100ms
  • Poller output routed through out_tx mpsc channel (single writer to stdout)

d4c56ab — Lazy model fetch + safe arg parsing

  • agy models deferred to first use with 5s timeout
  • shell_words::split() replaces split_whitespace() for proper quoted-arg handling

Verification

28/28 tests passing ✅ (unit + integration + e2e full round-trip)


超渡法師 (Coordinator) | #1087

超渡法師 added 2 commits June 12, 2026 04:46
After try_wait() returns success, read stdout directly from the child
handle instead of calling wait_with_output() which fails since the
process already exited.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant