Skip to content

feat(aop): unify agent transport end to end#62

Merged
M09Ic merged 69 commits into
masterfrom
feat/aop-single-transport
Jul 25, 2026
Merged

feat(aop): unify agent transport end to end#62
M09Ic merged 69 commits into
masterfrom
feat/aop-single-transport

Conversation

@M09Ic

@M09Ic M09Ic commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • make AOP the only aiscan agent activity transport; remove ChatEvent text/thinking/tool mappings and legacy SSE event types
  • remove protocol version fields and negotiation from the AOP envelope
  • persist raw AOP envelopes and replay them as named event: aop SSE frames
  • render text streaming, thinking, tool calls/results, usage, errors, and lifecycle directly through cyber-ui
  • retain only product-domain events such as scan/eval/compact outside AOP

Depends on chainreactors/cyber-ui#6.

Validation

  • go test ./pkg/aop ./pkg/web
  • npm run build in web/frontend

Generated web/static assets and unrelated local worktree changes are intentionally excluded.

M09Ic and others added 30 commits July 18, 2026 08:37
Introduce core/tool (shared tool contracts) and core/node (shared web
connectivity) to break cross-package dependencies:

- core/tool: ToolDefinition, Result, Executor, Tool interfaces with zero
  project dependencies. Renamed from core/toolapi with simplified names
  (tool.Definition, tool.Result, tool.Executor, tool.Tool).

- core/node: shared WebSocket connectivity extracted from pkg/webagent
  (1400→612 lines). Defines ConnectConfig + ChatHandler interface so
  both runner and agent connect to web via the same node.Connect().

- pkg/agent no longer imports pkg/commands (Config.Tools is now
  tool.Executor interface; LoopCommand accepts injected io.Writer).

- pkg/commands no longer imports pkg/agent/provider (types come from
  core/tool via aliases; pkg/tools/* need zero changes).

- cmd/runner no longer imports pkg/webagent (uses core/node directly).

- core/config no longer imports pkg/webproto (FetchRemoteConfig moved
  to pkg/webagent where the web dependency belongs).

- pkg/agent/probe no longer imports pkg/webproto (uses own ProbeConfig;
  pkg/web converts DistributeConfig at the boundary).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Agent Output Protocol (AOP):
- New pkg/aop/ package: Go types, agent.Event→AOP conversion, JSONL writer
- All event serialization paths switched to AOP v1 format
- Delete pkg/agent/event_json.go (old MarshalJSON no longer needed)
- Web hub forwardAgentEvent consumes AOP events directly
- Harness/timeline adapted to parse AOP JSONL

Chat unification:
- Local viewer component forks deleted (6 files)
- src/viewer/index.ts now re-exports from @cyber/viewer
- All chat rendering uses upstream viewer ChatPanel with variant/slot system
- aiscan-specific features (scan cards, eval badge, agent_joined) via extension registry

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Drop the webproto envelope from the stdio transport: stdin takes a
single StdioRequest and stdout is raw AOP JSONL, matching the unified
transport direction. Removes the now-unused aop writer and webagent
pipeline, and updates web/frontend panels accordingly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The bespoke pkg/cairnrunner protocol was a functional subset of the
existing webagent/webproto protocol. cmd/runner now connects as a
tool-only node through webagent.RunToolNode (no LLM provider, agent
loop, or IOA dependency); cairn's server absorbs the remaining
envelope differences.

webproto gains ExecResult (structured exec completion) and an optional
stream field on exec output messages, both additive for existing
consumers.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Runs RunToolNode against a mock hub speaking the register/connected +
exec + file.read dialect the cairn bridge now implements, asserting the
handshake identity, streamed exec output/result envelope, base64 file
reads, and tool.data call-ID correlation.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Lets the agent bound long-running commands explicitly instead of
relying solely on the 300s default.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The agent core now emits AOP natively (message/message.delta parts,
status+ext for eval/compact/token-budget/llm-request), replacing the
private agent.Event model and every boundary converter. stdio becomes
a persistent multi-session AOP host; the web hub dispatches user
messages as AOP, persists complete message events only, and replays
history over SSE; TUI, webagent, scan, and harness consume the raw
stream. The frontend reduces AOP directly — legacy chat timeline
fallbacks, ChatPayload, ResponseFormat, and the text event type are
gone. Also fixes compact/eval events previously emitted without a
session id, and stamps per-session seq numbers for replay dedup.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@M09Ic

M09Ic commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

本次改动已按统一语义方案完成收敛,核心模型为:

Session
  ├─ Run(API 操作,对应 AOP Turn)
  └─ Command(直接执行,不创建 Turn)

标识语义:

  • Run 只是 API 名,不存在独立的 Run identity。
  • 一次 Run 的唯一执行标识始终是 turn_id
  • WebSocket/stdio envelope、Run handle、Runtime 唯一性检查、取消和错误关联均只使用 turn_id
  • 协议中不存在 run_id,也不提供双字段兼容。
  • Command 和其他非 Run RPC 使用 task_id
  • Runner 身份使用注册消息中的 NodeRef.ID,属于节点路由身份,不与 turn_id 混用。

主要变化:

  • 一次 Run 表示一个完整 ReAct loop。
  • 每个 Run 恰好产生一组 turn.start / turn.end;内部多轮 LLM/tool 迭代不再重复产生 Turn 生命周期。
  • turn.end 是 Run 的唯一 terminal outcome;session.end 只表示真实 Session 关闭。
  • Session 改为显式 OpenSession / CloseSession,并提供可靠事件重放、Wait、context cancel、同 Session 有界 FIFO 和跨 Session 并发。
  • Command 成为唯一直接执行接口,不创建 Turn;输出写入 Session AOP history,但不进入 LLM transcript。
  • one-shot、scanner、local/remote REPL、stdio 和 WebSocket 均已迁移到 Session.Run / Session.Command
  • stdio 与 WebSocket 使用同一组语义帧:
    • session.open / session.opened
    • session.close / session.closed
    • run / run.cancel
    • command / command.result
    • aop / error
  • structured tool execution 已由 inbound AOP tool.call 改为 command / command.result
  • 删除旧 Runtime Execute / Submit / ExecuteLine / SubmitLine / Cancel / CancelSession 路径、agent.Inbound 用户输入路径和旧 RunControl / TurnData 语义。
  • Runtime 可变环境字段已私有化。
  • SQLite migration v2 会一次性清空旧 chat_aop_events,保留 sessions、messages、assets 和 records;旧事件无法安全重解释为新的 Session/Turn 边界。
  • e2e harness 已迁移为新的 Session/Run stdio 帧,并以匹配 turn_idturn.end 判断完成。
  • Agent Protocol schema、生成 TypeScript、fixtures 和 Web 前端消费逻辑已同步更新。
  • 架构与 breaking cutover 说明已补充到 docs/agent-runtime-multipath-analysis.md

新增/补强的回归覆盖包括:

  • Session/Run 生命周期以及唯一 turn_id
  • wire JSON 只包含 turn_id,不包含 run_id
  • Run 事件可靠重放和 Wait 顺序
  • Command 不污染 LLM transcript
  • active Run steering
  • idle asynchronous input 自动创建 Run
  • Session 隔离、pending limit 和跨 Session 并发
  • WebSocket 断开取消所属 Turn
  • stdio Run/Command correlation ID 边界
  • Runner NodeRef.ID 主路径

验证结果:

  • go test ./... -skip E2E -count=1 通过
  • go test -race ./core/runner ./pkg/webagent ./pkg/web -skip E2E -count=1 通过
  • go test -tags=e2e ./core/harness -count=1 通过
  • Agent Protocol TypeScript typecheck 通过
  • Web frontend production build 通过
  • 主仓库和协议子仓库 git diff --check 通过

已知的 TestE2ETerminalOpenAndType 本地环境超时问题未包含在本次验证中。

@wuchulonly
wuchulonly force-pushed the feat/aop-single-transport branch from bb07182 to 7c369ae Compare July 24, 2026 12:41
@M09Ic
M09Ic merged commit 4e2abcf into master Jul 25, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants