My Agent Core Design - Context & Session
My Agent Core Design - Context & Session
Context & Session
- Context 采用 Node 模型, 每个 conversation item 是一个树节点.
- 使用 SQLite 持久化 conversation/session 数据, session 数据集中存放在用户级
${SOONG_AGENT_HOME}/sessions.sqlite. - Session 是完整 agent tree 的持久化容器; run 是某个 agent 在该 session 内的一次 loop 执行.
- 同一个 session 内, main/Orchestrator run 串行; child/sub/fork agent run 可以并发.
- 同一个 session_id 覆盖主 agent 和 sub agent 的过程; 通过 agent_id / run_id 区分不同 agent 和 run.
SQLite Schema
- SQLite 只保存 conversation/session/runtime 元数据:
- 全局元数据表:
sessions,agents,runs,artifacts. - 每个 session 独立表:
nodes_<session_id>,events_<session_id>.
- 全局元数据表:
- 第一版不建
plans当前状态表. - 第一版不建
tasks/task_attempts/task_dependencies当前状态表. - Plan 是普通项目 Markdown 文件, 由普通 file tool 读写.
- Task DAG 当前状态来自运行时内存, 通过项目级 Task WAL JSONL 恢复.
- SQLite events 可记录 Task tool lifecycle / runtime event, 但不作为 Task DAG source of truth.
- 动态表名使用原始 session_id, 但 session_id 必须由 core 生成并严格 sanitize, 只允许
[a-zA-Z0-9_]+. - session_id 示例:
sess_20260612_153022_a1b2.
SQLite Writes
- 所有 SQLite 写操作进入全局 async writer queue, 顺序执行.
- SQLite 开启 WAL, 允许读并发.
- 第一版优先稳定, 不追求多 writer 并发.
- 写 node 和对应 event 必须在同一事务中完成.
- 如果事务失败, node 和 event 都不落库.
- 纯 lifecycle event 没有关联 node 时可单独写 event.
Task WAL
- Task DAG 变更不写 SQLite 当前状态表.
- Task DAG 变更写入
<project>/.soong-agent/tasks/<session_id>/<model-chosen-task-name>.wal.jsonl. - Task WAL 由 Task manager 单 writer 队列追加.
- Task WAL append 成功后才更新内存 DAG.
- runtime 恢复 session 时 replay 对应 WAL 文件重建 Task DAG.
- Task WAL replay 失败会使该 session 的 Task DAG 不可用, 但不破坏 SQLite conversation replay.
Node And Event
- Node 是主数据, Event 是 timeline/debug 日志:
- 构造模型上下文只看 nodes 和显式注入的 synthetic context.
- events 用于 timeline, debug, inspect, replay 辅助.
- Node 不和 Event 共用同一个全局 seq.
nodes_<session_id>.node_seq在 session 内单调递增, 只表示 node 创建顺序.node_seq由 storage manager 在写入 node 时分配.- child/sub/fork 并发写 node 时也必须经过 storage manager, 避免 seq 冲突.
- 上下文顺序主要由 parent/child tree 和 active path 决定.
events_<session_id>.seq由 storage writer 分配, 表示 timeline 顺序.events_<session_id>.run_seq在 run 内单调递增, 用于 run replay.- timeline 按 event seq 排序, 不依赖 created_at 排序.
Node Types
- Node 使用
role + node_type:- role 表示 provider/message 层角色, 例如 user / assistant / tool.
- node_type 表示 core 内部语义, 例如 message / skill_context / memory_context / compaction / child_result / plan_instruction / task_instruction / task_board / system_note.
- Plan tool 返回的模板内容写为
node_type=plan_instruction. - Task template tool 返回的模板内容写为
node_type=task_instruction. - Task DAG summary 可写为
node_type=task_board.
nodes_<session_id> Fields
- node_id TEXT PRIMARY KEY
- node_seq INTEGER NOT NULL
- parent_id TEXT NULL
- agent_id TEXT NOT NULL
- run_id TEXT NULL
- role TEXT NOT NULL
- node_type TEXT NOT NULL
- content_json TEXT NOT NULL
- metadata_json TEXT
- token_count INTEGER
- created_at TEXT NOT NULL
events_<session_id> Fields
- event_id TEXT PRIMARY KEY
- seq INTEGER NOT NULL
- run_seq INTEGER
- agent_id TEXT
- run_id TEXT
- level TEXT NOT NULL
- event_type TEXT NOT NULL
- node_id TEXT
- tool_call_id TEXT
- payload_json TEXT
- created_at TEXT NOT NULL
Global Tables
sessions字段:- session_id TEXT PRIMARY KEY
- cwd TEXT NOT NULL
- root_agent_id TEXT NOT NULL
- active_node_id TEXT
- parent_session_id TEXT
- status TEXT NOT NULL
- metadata_json TEXT
- created_at TEXT NOT NULL
- updated_at TEXT NOT NULL
agents字段:- agent_id TEXT PRIMARY KEY
- session_id TEXT NOT NULL
- parent_agent_id TEXT
- agent_type TEXT NOT NULL
- created_by_run_id TEXT
- fork_from_node_id TEXT
- status TEXT NOT NULL
- result_json TEXT
- metadata_json TEXT
- created_at TEXT NOT NULL
- updated_at TEXT NOT NULL
runs字段:- run_id TEXT PRIMARY KEY
- session_id TEXT NOT NULL
- agent_id TEXT NOT NULL
- status TEXT NOT NULL
- start_node_id TEXT
- end_node_id TEXT
- end_reason TEXT
- turn_count INTEGER
- usage_json TEXT
- error_json TEXT
- metadata_json TEXT
- created_at TEXT NOT NULL
- updated_at TEXT NOT NULL
artifacts字段:- artifact_id TEXT PRIMARY KEY
- session_id TEXT NOT NULL
- agent_id TEXT
- run_id TEXT
- node_id TEXT
- tool_call_id TEXT
- path TEXT NOT NULL
- filename TEXT
- mime_type TEXT
- size_bytes INTEGER
- summary TEXT
- metadata_json TEXT
- created_at TEXT NOT NULL
Status Enums
- session.status: active / archived.
- agent.status: idle / running / completed / failed / cancelled.
- run.status: queued / pending / running / completed / failed / aborted / cancelled.
- run.end_reason: completed / max_turns / aborted_streaming / aborted_tools / prompt_too_long / max_output_tokens_recovery / failed.
- run.end_reason 只保留高层稳定枚举; provider/tool/storage 细节进入
runs.error_json和 events. - stop_hook_prevented 是 hook/event/recovery 语义, 不作为普通 run.end_reason; Stop hook deny 后 loop 继续, 最终仍无法继续时用 max_turns / aborted_* / failed 等高层 end_reason.
- agent.agent_type: main / orchestrator / sub / fork.
- orchestrator 表示 orchestrator mode 下的 Orchestrator agent, 不是两层 agent 结构.
- 具体用途放
agents.metadata_json.purpose, 例如 compact / worker / review / debug. - Memory Extraction Job 不是 agent, 不写入
agents表, 不使用agent_type, 不创建 agent_id / run_id.
Content Blocks
content_json存 provider-neutral content blocks, 不是 provider 原始格式, 也不是单独 JSON 文件.- Content block 第一版支持:
- text
- json
- tool_call
- tool_result
- artifact_ref
- Content block 在 core 内部使用严格 Pydantic discriminated union, 按
type分派. jsoncontent block 写入时按阈值处理:- 小 JSON 直接存在 block 中.
- 大 JSON 按 byte/token 阈值 artifact 化.
- artifact 化后 block 只保留 summary + artifact_ref.
- prompt composer 不再重新承载完整大 JSON.
artifact_refcontent block:- 只引用 artifact_id.
- 可带 summary, mime_type 等轻量展示信息.
- 真实 path/size/run/node/tool_call 关系只放
artifacts表.
- Tool call 和 tool result 都是 content blocks:
- assistant node 可包含 text + tool_call blocks.
- tool node 包含 tool_result blocks.
- user node 可包含 text / attachment / artifact_ref blocks.
- Tool 失败时仍写入 tool_result block, 带
is_error: true, 同时写tool_failedevent.
Active Path
- 构造模型上下文时只取 active node 沿 parent_id 回 root 的 active path.
- sibling branch 默认不进入上下文.
/switch_node改变 active node 后, 下一轮上下文使用新的 active path.- 只支持从 user message 开新 branch.
- worker sub agent 每次 dispatch_worker 可以在该 worker 的 context tree 上开启新 branch.
- worker run 默认只读取本次 dispatch branch 的 active path.
/tree和/branch合并成/switch_node能力.- 第一版不做 branch merge, 也不需要 branch summary.
- Context 原始历史不物理删除, compact 后仍可回溯.
This post is licensed under CC BY 4.0 by the author.