My Agent Core Design - Implementation
Python Implementation
- Python 版本基线: Python 3.11+.
- 包管理使用
uv+pyproject.toml. - Python distribution name 使用
soong-agent. - import package name 继续使用
agent_core. - CLI entry point 使用
soong-agent. - Core 直接使用实用依赖:
pydantichttpxaiosqlitePyYAML- 常用 provider 官方 SDK.
PyYAML用于解析/写入 Memory, Skill 等 md frontmatter.- 第一版默认安装常用官方 SDK, 优先保证开箱即用.
- Core 采用 async-first 设计:
- model streaming, tool execution, hook execution, child agent 都通过 asyncio 调度.
- 对外 event stream 使用 async iterator / async generator.
- 类型和 schema:
- 用 Pydantic 定义 core protocol, tool input/output, hook input/output, provider normalized event.
- JSON Schema 从 Pydantic model 导出, 供 provider tool schema 和声明式 tool 校验使用.
- 核心类型分三层:
- protocol: 面向 provider / tool / hook 的稳定协议类型.
- runtime: 面向 SDK 调用方、loop、event stream 的运行态类型.
- storage: 面向 SQLite 落库和迁移的 row / record 类型.
- protocol 类型不直接包含 SQLite 字段.
- storage 类型不直接暴露给 provider adapter.
- runtime 类型负责连接 protocol 和 storage, 但不替代二者.
- protocol 第一批类型:
- ModelRequest
- ModelMessage
- ContentBlock
- SystemBlock
- ModelEvent
- ToolCall
- ToolResult
- ToolDefinition
- HookInput
- HookOutput
- PermissionRequest
- PermissionDecision
- Plan / Task 不放入 protocol 层, 放入 runtime/domain 层.
- runtime 第一批类型:
- AgentConfig
- RunHandle
- RunState
- RuntimeEvent
- SessionState
- AgentState
- Node
- ArtifactRef
- Plan
- Task
- TaskDAG
- TaskStep
- TaskWalEvent
- ChildAgentResult
- ContextBuildReport
- runtime 类型是 core loop 和 SDK 调用方主要接触的对象.
- storage 第一批类型:
- SessionRecord
- AgentRecord
- RunRecord
- NodeRecord
- EventRecord
- ArtifactRecord
- storage 类型字段贴近 SQLite 表结构.
- storage 类型中的 JSON 字段保留
*_json命名. - storage 到 runtime 的转换由 mapper 负责.
- runtime 类型不直接依赖 SQLite row shape.
- 类型文件按三层组织:
src/agent_core/types/protocol.pysrc/agent_core/types/runtime.pysrc/agent_core/types/storage.pysrc/agent_core/types/mappers.pysrc/agent_core/types/enums.py
protocol.py只放 provider / tool / hook 稳定协议类型.runtime.py放 SDK 调用方、loop、domain 使用的运行态类型.storage.py放 SQLite row / record 类型.mappers.py负责 storage <-> runtime 转换.enums.py放跨层共享的 StrEnum, 避免各层重复定义状态字符串.- Pydantic 模型默认禁止未知字段:
- 默认使用
extra="forbid". - 只有明确设计为扩展点的字段允许承载额外信息, 例如
metadata,provider_options,raw. - provider / tool / hook 协议边界不接受任意未声明字段.
- 未知字段应尽早报 schema/config 错误, 避免被静默忽略.
- 默认使用
- ID 类型第一版使用字符串:
- runtime/storage/protocol 中的 id 字段都用
str. - 通过固定前缀区分语义, 例如
run_,task_,plan_,node_,agent_,artifact_. - Pydantic validator / helper 函数负责校验前缀和基本格式.
- 不为每类 ID 定义独立 runtime class.
- 这样保持 JSON, SQLite, Markdown frontmatter 和 Task WAL event payload 之间的表示一致.
- runtime/storage/protocol 中的 id 字段都用
- 状态、事件类型、权限类型使用
StrEnum:- SQLite、JSON 和 Task WAL 中保存枚举值字符串.
- Python 代码中使用枚举成员, 避免散落硬编码字符串.
- 适用范围包括 run status, task status, task step status, event type, permission kind, hook phase, tool kind.
- 跨层共享枚举放在
src/agent_core/types/enums.py.
- 跨层共享枚举放在
- storage/runtime mapper 保持轻量:
- 只负责字段命名转换、JSON parse/dump、枚举转换、默认值补齐.
- 不负责业务规则判断.
- task DAG 状态流转、权限校验、claim 校验留给 service/manager 层.
- mapper 抛出的错误仅表示数据格式无法转换, 不表示业务操作不允许.
- 错误类型体系:
- 定义
AgentCoreError作为 SDK 内部可预期错误基类. - 第一批分类 exception 包括
ConfigError,ProviderError,ToolError,StorageError,SchemaError,PermissionDeniedError. - 协议 / event 中的错误结构命名为
ErrorPayload/ProviderErrorPayload, 不与 Python exception 同名. - 避免直接使用 Python 内置
PermissionError表达 agent permission 拒绝. AgentCoreError携带 code, message, retryable, details, cause.ErrorPayload默认字段包括 type, code, message, retryable, details, redacted.ErrorPayload默认不包含 traceback.- debug 模式下 traceback 保存为 redacted artifact, event payload 只引用 artifact_id.
- run 边界负责把 exception 转成结构化 error payload 和对应 event.
- 对外 event / inspect 中默认只暴露 redacted error payload, 不直接暴露完整 traceback.
- debug 模式可以把 traceback 保存为 redacted artifact.
- 定义
- SQLite:
- 第一版直接使用
aiosqlite. - runtime 持有一个 storage manager.
- 写操作通过单 writer 队列串行化.
- 读操作第一版可以复用 storage manager 连接, 或使用受控独立只读连接.
- 不允许每个 run 随意创建连接直接写同一个 DB.
- storage manager 负责事务边界、锁等待、关闭连接.
- SQLite 默认启用 WAL:
- 初始化时设置
PRAGMA journal_mode=WAL. - 设置合理
busy_timeout. - WAL / busy_timeout 由 storage manager 管理, 第一版不暴露为常规配置.
- 初始化时设置
- 内置轻量 migration 系统:
- 使用
schema_migrations(version, applied_at)表记录已应用版本. - core 启动 / 打开 session DB 时自动按顺序执行缺失 migration.
- migration 由 SDK 代码内置, 不依赖 Alembic 等外部迁移工具.
- migration 必须幂等或在事务中保证失败回滚.
- schema 变更必须同步更新 storage record 类型和 mapper 测试.
- 使用
- 第一版直接使用
- Task WAL:
- Task DAG 不存 SQLite 当前状态表.
- Task DAG 当前状态保存在运行时内存.
- Task DAG 变更追加写入项目级 JSONL WAL.
- runtime 启动 / 恢复 session 时 replay Task WAL 重建内存 DAG.
- Task WAL manager 使用单 writer 队列, 避免并发追加交错.
- Task WAL record 使用 Pydantic model 校验.
- Task WAL 文件路径默认
<project>/.soong-agent/tasks/<session_id>/<model-chosen-task-name>.wal.jsonl.
- HTTP/provider:
- provider adapter 内部可以用
httpxasync client. - 第一版内置多个常用 provider adapter:
- OpenAI adapter.
- Anthropic adapter.
- OllamaProviderAdapter.
- 内置 adapter 默认都不强制启用, 由配置选择 provider.
- provider adapter 通过 registry 创建:
- 内置 key 包括
openai,anthropic,ollama. - registry value 是 adapter class 或 factory.
- 调用方可以注册自定义 adapter class / factory.
- 配置中的
model.provider用 registry key 选择 adapter. - 未知 provider key 触发
ConfigError. - registry 归属于
AgentCore/AgentRuntime实例, 不使用全局单例. - 初始化时可传入
provider_registry或providers. - builder API 提供
register_provider(key, factory). - 多个 runtime 实例可以拥有不同 provider registry, 方便测试和隔离.
- 内置 key 包括
- 常用官方 SDK 默认作为 core 依赖安装, 不要求用户额外安装 extras 才能使用内置 provider.
- 内置 provider adapter 可以直接依赖对应官方 SDK.
- 官方 SDK 依赖只允许出现在 provider adapter 层.
- 官方 SDK 类型不能泄漏到 core protocol, runtime API, storage schema, event payload.
- adapter 边界负责把官方 SDK request/response/error 转成 core 标准类型.
- OpenAI / Ollama 这类 HTTP 接口简单的 provider 仍可直接用
httpx. OllamaProviderAdapter用于本地开发和集成测试.- 所有 adapter 必须遵守统一 ProviderAdapter streaming 协议.
- OpenAI adapter 第一版只支持 Chat Completions 兼容流式接口:
- 面向
/v1/chat/completions风格协议. - 输入映射到 messages/tools/tool_choice.
- 输出消费 streaming chat delta.
- OpenAI Responses API 后续再作为独立能力补充.
- 第一版不要求 OpenAI provider 支持 Responses API.
- 面向
- Anthropic adapter 第一版使用 Anthropic Messages streaming API:
- 使用 Anthropic 原生 messages / system / tools 协议.
- 支持 tool use / tool result 的标准映射.
- Anthropic 原始 streaming event 只在 adapter 内部处理.
- core 只接收统一
ModelEvent.
- Ollama adapter 第一版:
- 支持无工具 streaming 作为基础能力.
- 如果当前 Ollama API / 模型明确支持 tools, adapter 启用 tool call 映射.
- 如果 run 需要 tools 但当前 Ollama provider 不支持 tools, run 直接 failed, 不发送模型请求.
- 不用 prompt 约定模拟 tool call.
- 不设计统一
ProviderCapabilities对象:- provider 能力判断写在各 adapter 内部.
- 官方 provider adapter 按官方 API 能力实现.
- OpenAI / Ollama 这类能力不稳定的 provider, 由 adapter 根据配置、模型信息或请求特征自行判断.
- 如果 adapter 判断当前请求不支持, 返回/抛出结构化 provider capability error.
- core 不在发送模型请求前做统一能力矩阵校验.
- provider adapter 内部可以用
- Hook / command tool:
- 使用
asyncio.create_subprocess_shell或asyncio.create_subprocess_exec. - stdin/stdout 都走 JSON 协议.
- timeout 和 exit code 由 adapter 统一处理.
- 使用
- 项目代码结构按标准 Python 工程组织:
- 使用
src/layout. - 包目录固定为
src/agent_core/. - 测试目录使用
tests/. - CLI entry point 在
pyproject.toml中声明为soong-agent = "agent_core.cli:main".
- 使用
- SDK 包结构建议:
src/agent_core/runtime: loop, run state, event stream.src/agent_core/provider: provider adapter 和统一协议.src/agent_core/context: SQLite session, node tree, replay.src/agent_core/tools: tool adapter, registry, permission, execution.src/agent_core/hooks: hooks config, command hook runner.src/agent_core/memory: Memory Extraction Job, restricted memory writer, memory file store, recall.src/agent_core/agents: child agent, fork agent, orchestrator mode.src/agent_core/tasks: in-memory Task DAG, Task tools, WAL JSONL replay.src/agent_core/config: 用户级${SOONG_AGENT_HOME}/config.tomlloader 和 schema 校验.src/agent_core/skills: skill metadata scan and progressive disclosure.
This post is licensed under CC BY 4.0 by the author.