core · 数据模型
所有公共导出来自 @migor/agentia 包根(src/index.ts)。core 层是零依赖的数据模型与结构面:四类单元最终都编译成 AgentTool,一次 run 沉淀为一条 Trace。
| 导出 | 签名摘要 | 说明 |
|---|---|---|
| AgentTool<I, O> | { name; description; inputSchema; strict?; run(input: I, ctx?: ToolRunContext) } | 模型可见工具的最小结构面。run 抛错被包成 is_error 的 tool_result 回给模型,run 不中断。 |
| JsonSchema | { type; description?; properties?; required?; additionalProperties?; … } | 工具 input_schema 的 JSON Schema 子集(v1 裸 schema,不依赖 zod)。 |
| ModelClient | { messages.stream(params) → { on('text', cb); finalMessage() } } | engine 对模型端的最小结构面;Anthropic SDK 天然满足,其他 provider 适配成同一形态。 |
| ToolRunContext | { client; recorder; parentSpanId } | engine 调用每个工具时注入的执行上下文,供子单元把嵌套 span 挂进当前 trace。 |
| RecorderBackend | begin / end / event / setAttribute / snapshot | TraceRecorder 面向子单元的最小记账面(core 不依赖 engine)。 |
| Trace | { traceId; rootSpanId; spans: Span[]; status; totalUsage } | 一次 run == 一条 trace(traceId == runId);totalUsage 为各 span 求和。 |
| Span | { spanId; parentSpanId; kind; name; startedAt; endedAt?; status; error?; usage?; attributes; events } | 调用树节点;unit 名为 ${unitType}:${unitName},llm.turn 名为模型 id。 |
| Usage | { inputTokens; outputTokens; cacheReadTokens; cacheCreationTokens; costEstimate? } | span 聚合用量;成本由 token × 单价表估算。 |
| SpanKind | 'run' | 'unit' | 'llm.turn' | 'internal' | span 层级:整次运行 / 单元调用 / 单元内每次模型往返。 |
| UnitType | 'tool' | 'skill' | 'prompt' | 'subagent' | 四类单元,共用命名空间。 |
| SpanEvent | { time; name; body } | span 上的结构化事件(如 tool.input / tool.output / compaction)。 |
| SpanError | { type; message; retryable } | 错误分类;retryable 标记 429 / 5xx / 网络类可安全重试。 |
| SpanStatus / SpanId / TraceId | 'ok' | 'error' / string / string | 基础类型别名。 |
| validateJsonSchema | (schema: JsonSchema, input: unknown) → string | null | JSON Schema 子集校验(fromZod 接入时先走 zod),返回首条错误消息或 null。 |
engine · 运行时内核
流式 manual loop:模型往返 + 递归工具调用,直到 end_turn / 循环上限 / submit_result 提交结构化结果。
| 导出 | 签名摘要 | 说明 |
|---|---|---|
| runAgent | (options: RunAgentOptions) → Promise<AgentRunResult> | 主循环入口;不注入 recorder 时内部新建,traceId 即 runId。 |
| resolveDefaultModel | (over?: string) → string | 模型缺省解析:显式参数 > AGENTIA_MODEL 环境变量 > claude-opus-5。 |
| TraceRecorder | class:begin(kind, name, parent) / end(id, patch?) / event / setAttribute / snapshot(status) | span 记账器,traceId 随实例生成。 |
| classifyError | (e: unknown) → SpanError | SDK 异常归类:rate_limit / connection 标 retryable。 |
| AgentRunResult | { trace; stopReason; finalText; iterations; error?; typed? } | typed 为 resultSchema 校验通过的结构化结果(模型未提交则为 undefined)。 |
| AgentStopReason | 'end_turn' | 'max_tokens' | 'refusal' | 'pause_turn' | 'max_iterations' | 'tool_use_no_blocks' | 'error' | 循环终止原因。 |
| ContextPolicy | { budgetTokens?; beforeTurn(messages, { iteration, model }) → Promise<messages> } | 上下文预算策略面:每回合发送前可编辑 / 压缩消息。 |
| SystemParam / SystemTextBlock | string | SystemTextBlock[] | system 参数:纯文本,或带 cache_control breakpoint 的可缓存块数组。 |
RunAgentOptions 选项
| 选项 | 类型 | 说明 |
|---|---|---|
| messages(必填) | MessageParam[] | 初始消息;由调用方给 user 起始消息。 |
| system | SystemParam | 顶层 system(SystemPrompt 产物);稳定内容放在第一个 breakpoint 前。 |
| tools | AgentTool[] | 主 agent 可调工具菜单(裸 JSON schema)。 |
| model | string | 缺省走 resolveDefaultModel。 |
| maxTokens | number | 流式请求的 max_tokens,给足避免中途截断。 |
| maxIterations | number | 循环安全上限,防止无限 tool 往返。 |
| client | ModelClient | 缺省 new Anthropic()(读环境变量);多模型场景注入适配 client。 |
| recorder | TraceRecorder | run 层复用注入;不注入则内部新建。 |
| onText | (delta: string) => void | 文本增量回调(终端 / SSE 用)。 |
| runName | string | 写入 trace 根 span 名。 |
| contextPolicy | ContextPolicy | 每回合发送前的上下文预算策略(compaction / context editing)。 |
| resultSchema | JsonSchema | 给出后追加隐藏工具 submit_result,模型提交校验通过的结果写入 result.typed 并结束循环。 |
engine · 长上下文策略
预算驱动的上下文护栏:估算 ≤ 预算走快路径原样放行;超预算先 context editing(不调模型);仍超且有 summarize 才 compaction,并带滞回避免每回合反复压缩。
| 导出 | 签名摘要 | 说明 |
|---|---|---|
| createBudgetPolicy | (opts?: BudgetPolicyOptions) → ContextPolicy | 上述三段降级的开箱实现;框架不替你造 token,可注入按 /count_tokens 的 estimate。 |
| BudgetPolicyOptions | { budgetTokens?=60000; keepRecent?=20; estimateTokens?; editBeforeCompact?=true; summarize?; compactEvery?=1 } | summarize 提供才允许 compaction;compactEvery 为压缩滞回(回合数)。 |
| trimToolPairs | (messages, opts?: TrimOptions) → messages | context editing:丢弃超出 keepRecent(缺省 1)的旧 tool_use→tool_result 对。 |
| traceToMessages | (trace, opts?: ReplayOptions) → MessageParam[] | trace 重放基底:把完成的 run 还原成可喂回模型的对话(角色交替合法、tool 对配对、可截断)。 |
| compactMessages | (messages, opts: CompactOptions) → Promise<messages> | compaction:旧前缀经 summarize 摘要,只留最近 keepRecent(缺省 20)条。 |
| defaultEstimateTokens | (text: string) → number | CJK 感知的 token 启发式估算(预算决策用,非精确记账)。 |
| estimateMessages | (messages, estimate?) → number | 整组消息 token 估算。 |
| renderMessages | (messages) → string | 消息渲染成纯文本,作摘要器输入。 |
| TrimOptions / CompactOptions | { keepRecent? } / { keepRecent?; summarize } | 上述两函数的选项类型。 |
run · 生命周期与触发
一次 run 的完整生命周期(RunContext + recorder + 记忆水合/回写),以及同步 RPC、异步任务、定时调度三类触发 —— 共用同一份输入契约,换宿主不换语义。
| 导出 | 签名摘要 | 说明 |
|---|---|---|
| executeRun | (options: ExecuteRunOptions) → Promise<{ run; result }> | run 生命周期入口:RunContext 作用域内跑 runAgent,finish / fail 收口。 |
| ExecuteRunOptions | RunAgentOptions & { idempotencyKey?; contextInit?; memory? } | memory:run 开始把 store.load(keys) 水合进 blackboard(用户种子优先),结束回写。 |
| Run | class:start() / finish(result) / fail(error) / toMeta() | run 状态机(queued → running → succeeded/failed);runId == recorder.traceId。 |
| RunContext | class:static current() / get<T>(key) / set / has / delete / keys | run 内 blackboard,AsyncLocalStorage 传播,不用全局单例。 |
| withRunContext | (ctx: RunContext, fn) → Promise<T> | 在指定 ctx 作用域内执行 fn。 |
| RunMeta / RunStatus | { runId; status; idempotencyKey?; createdAt; startedAt?; finishedAt?; error? } / 'queued' | 'running' | 'succeeded' | 'failed' | 运行记录与状态。 |
| SystemPrompt | class:add(name, text, stable?) / add(section) / build({ cache? }) | 分段组装 system:stable 段进可缓存前缀打 ephemeral breakpoint,volatile 段放其后。 |
| SystemSection | { name; text; stable? } | system 段落;stable=false 不进可缓存前缀。 |
| normalizeMessages | (input: RunInput | unknown) → MessageParam[] | 任意任务入参(string / messages / { prompt | text | messages })规范成 messages;空数组抛错。 |
| RunInput | string | MessageParam[] | { prompt?; text?; messages? } | transport 层接受的原始入参形态。 |
| RunSpec | { messages; options?; source? } | 一次任务的规范化入参;source 标记触发来源(sync / async / schedule:<id>)。 |
| RunInvocationOptions | { model?; maxTokens?; maxIterations?; client?; onText?; blackboard?; contextPolicy?; idempotencyKey?; rethrow?; tools? } | 单次 run 的调用参数,三类触发共用。 |
| runSync / createSyncHandler | (app, input, opts?) / (app) → (input, opts?) => … | 同步 RPC:规范化入参后直接 app.run。 |
| AsyncRunner | new AsyncRunner(app, { client?, store?, concurrency? }):submit(input, { idempotencyKey?, source?, options? }) / resumePending() | 提交即返回任务记录、后台执行;同幂等键未失败任务 last-wins 去重;concurrency 限并发,超出排队。 |
| AppCallable | { name; run(messages, opts?) } | 应用最小调用面(run 层不向上依赖 toolkit)。 |
| Scheduler | new Scheduler(runner):every(intervalMs, input, opts?) / at(when, input, opts?) | 周期 / 定点触发,到点转为异步任务提交;返回 ScheduleHandle { id, cancel() }。 |
| TaskStore | interface:save / get / byIdempotency / list / clear | 任务记录存储面;byIdempotency 为 last-wins 去重依据。 |
| TaskRecord | { taskId; status; idempotencyKey?; spec: RunSpec; runId?; createdAt; startedAt?; … } | 任务记录;完成后回填 runId(== traceId)。 |
| InMemoryTaskStore | class(TaskStore) | Map 实现:测试与缺省场景用。 |
| FileTaskStore | new FileTaskStore(file) | JSONL 一行一快照落盘;宿主重启后 resumePending() 续跑 queued/running。 |
| SqliteTaskStore | new SqliteTaskStore(path) | node:sqlite 落库(WAL 读写不互斥),支持 ':memory:'。 |
| RedisTaskStore | new RedisTaskStore(client, { prefix? }) | duck-typed Redis 客户端(ioredis/node-redis 均可,可选 peer),TaskStore 方法支持异步。 |
run · 宿主与导出
同一份应用一行接入 HTTP;trace 可导出到任何 OTLP 收集器;OpenAI 兼容端点一行接入多模型。
| 导出 | 签名摘要 | 说明 |
|---|---|---|
| createHttpHandler | (app: AppCallable, opts?: { runner? }) → (req, res) => Promise<void> | node:http 接入:POST /run(同步)、POST /tasks(异步)、GET /tasks/:id(轮询)。 |
| createOtlpExporter | ({ endpoint, headers?, serviceName? }) → { export(trace) → Promise<void> } | trace 导出到任意 OTLP/HTTP 收集器(缺省 service.name 为 'agentia')。 |
| createOpenAIClient | (opts?: { apiKey?; baseURL?; fetchImpl? }) → ModelClient | OpenAI 兼容端点(含 DeepSeek 等)适配成 ModelClient;apiKey 缺省读 OPENAI_API_KEY。 |
| MemoryStore | interface:load(keys) / save(entries) | 跨 run 记忆存储面(可同步或异步实现)。 |
| InMemoryMemoryStore | class(MemoryStore) | Map 实现:进程内,无持久化。 |
container · 显式 DI
显式 provider 注册,覆盖式语义(后注册覆盖先注册);resolve 单例缓存并做循环依赖检测。
| 导出 | 签名摘要 | 说明 |
|---|---|---|
| Container | class:register(...providers) / has(token) / resolve<T>(token) | DI 容器;register 返回 this 可链式。 |
| Token | string | provider 注册键。 |
| Provider | ValueProvider | ClassProvider | FactoryProvider | 三种 provider 形态的联合。 |
| ValueProvider | { provide; useValue } | 直接给值。 |
| ClassProvider | { provide; useClass; deps? } | 类实例化;deps 按序注入构造器参数。 |
| FactoryProvider | { provide; useFactory; deps? } | 工厂函数;deps 与 useFactory 形参一一对应。 |
toolkit · 声明式单元与装配
装饰器声明四类单元,createApp 装配:DI 注册 → 扫描收集菜单 → 装配期静态校验(菜单查重、tools 引用存在性、toolSources 指向、DI 循环依赖)。
| 导出 | 签名摘要 | 说明 |
|---|---|---|
| createApp | (opts: AppOptions) → AgentApp;带 discover 时 → Promise<AgentApp> | 装配应用;目录发现走动态 import,故返回 Promise。 |
| AppOptions | { name?; providers?; modules?; discover?; system; model?; maxTokens?; maxIterations?; contextPolicy?; toolSources?; middleware? } | system 必填:SystemPrompt 实例(自动打缓存)或拼好的 SystemParam。 |
| AgentApp | class:run(messages, opts?: RunAppOptions) → Promise<AgentRunOutput>;tools;container | 装配产物;run 每执行一次从 SystemPrompt 重建 system,保证 volatile 新鲜。 |
| RunAppOptions | RunInvocationOptions & { system? } | 单次调用参数,可覆盖 system。 |
| AgentRunOutput | { run: Run; result: AgentRunResult } | app.run 的返回。 |
| defineModule / AgentModule | (m: AgentModule) → AgentModule / { providers; middleware? } | 第三方能力包约定:providers 先于应用级注册(同 token 应用级覆盖),middleware 拼在更外层;defineModule 为 identity 函数。 |
| Tool | @Tool(spec: ToolSpec) 方法装饰器 | 类方法即工具:入参按 schema 先校验再执行。 |
| ToolSpec | { name?; description; schema: JsonSchema; strict? } | name 缺省取方法名;strict 需 additionalProperties:false + required 齐全。 |
| collectTools | (instance: object) → AgentTool[] | 沿原型链扫描 @Tool 方法并绑定实例。 |
| Skill | @Skill(spec: SkillSpec) 方法装饰器 | 方法体是确定性脚本;模型调用只在显式 ctx.llm() 时发生,记在 skill 自己的 unit span 下。 |
| SkillSpec | { name?; description; schema?; model?; maxTokens?; maxIterations?; tools? } | tools 为容器 provider token 列表(ctx.llm() 可调)。 |
| SkillContext | { model?; llm(opts: SkillLlmOptions) → Promise<SkillLlmResult> } | 受限子运行句柄:每次 llm() 在 unit span 下开一轮独立 agent 循环。 |
| SkillLlmOptions / SkillLlmResult | { prompt?; messages?; system?; model?; maxTokens?; maxIterations? } / { text; stopReason } | prompt 与 messages 二选一;system 接受 string 或 SystemPrompt。 |
| collectSkills / skillToTool | (instance) → SkillUnit[] / (unit, resolveTools) → AgentTool | 扫描 @Skill 方法 / 编译成主 agent 菜单项。 |
| SkillUnit | { name; description; inputSchema; spec; invoke(input, ctx) } | 含绑定实例的方法执行器。 |
| SubAgent | @SubAgent(spec: SubAgentSpec) 方法装饰器 | 方法体不执行:框架按 system 另起隔离循环,中间过程不外泄,只有最终报告回流。 |
| SubAgentSpec | { name?; description; schema; system; tools?; model?; maxTokens?; maxIterations? } | system 支持 string / SystemPrompt / (task) => SystemParam(动态拼,框架不附加);tools 为 provider token 列表。 |
| collectSubAgents / subagentToTool | (instance) → SubAgentUnit[] / (unit, resolveTools) → AgentTool | 扫描 @SubAgent 方法 / 编译成 AgentTool(子循环复用 ctx.client 与 recorder)。 |
| SubAgentUnit | { name; description; inputSchema; spec } | 子代理单元元数据。 |
| Prompt | @Prompt(spec: PromptSpec) 方法装饰器 | 纯文本资产编译成无副作用的拉取型工具;每次调用重算(volatile 语义)。 |
| PromptSpec | { name?; description; schema? } | description 写清何时该拉取,模型据此决定调用;schema 缺省空对象(无参资产)。 |
| collectPrompts | (instance: object) → AgentTool[] | 扫描 @Prompt 方法(static 方法亦可)。 |
| asset | (base: string | URL, rel: string) → string | asset(import.meta.url, './system.md') 相对单元目录读文本资产;每次调用现读不缓存。 |
| discoverProviders | (dir: string) → Promise<Provider[]> | 目录约定扫描 units/<name>/index.ts:default export 为类 / Provider / Provider[],类以文件夹名为 token 注册。 |
| applyMiddleware | (tools: AgentTool[], middleware: UnitMiddleware[]) → AgentTool[] | 洋葱模型包裹整个菜单(链序 = 注册顺序,先注册最外层);链为空原样返回,零开销。 |
| UnitMiddleware | (call: UnitCall, next: UnitNext) => unknown | 单元调用前后横切(鉴权 / 缓存 / 审计);不调 next 即短路,抛错按单元失败处理。 |
| UnitCall / UnitNext | { unit; input; ctx? } / (input?) => unknown | 入参 schema 校验已过;next(newInput) 可改写入参。 |
| fromZod | (jsonSchema: JsonSchema, zod: unknown) → JsonSchema | zod 可选接入(peer):校验走 zod safeParse(结构面识别,框架不 import zod),错误路径原样回给模型自我修正。 |