AgentRuntime:端口、依赖与方法装配

一个会话对应一个 AgentRuntime:它身上的八十多个状态字段、构造时注入的四十九项依赖,近百个方法文件怎样用声明合并加原型安装装到同一个类上,AgentRuntimeInternal 的作用,trace 上下文如何从根一路传到模型请求,以及 core 包对外导出了什么。

作者 David更新于 5 篇(共 47 篇)

ZCode 的 Agent 运行时住在 apps/zcode-cli/packages/core/src/runtime:163 个文件、约 3.7 万行,全部围绕一个类 AgentRuntime。终端 TUI、-p 无头模式、桌面端与 Web 背后的协议服务,最终都是拿到一个 AgentRuntime 实例,调它的方法、订阅它的事件。它自己不碰具体实现:文件、子进程、网络、存储与模型大多经“端口”注入,端口的接口声明在 apps/zcode-cli/packages/contractssrc/interfaces 下有 25 个 *.port.ts),实现在 adapters,由 bootstrap 组装。

这一篇只讲这个类本身:一个实例对应什么、身上挂着哪些状态、要哪些依赖、近百个方法文件怎样装到同一个类上,以及 trace 上下文怎么一路传下去。回合怎么跑、输入怎么受理、事件怎么落库,分别见回合循环输入受理会话事件流

目录分工

位置(相对 core/src/runtime内容
agent-runtime.ts类本体:82 个私有字段、构造器、两个关闭方法,以及同名 interface 声明的公开方法
methods/97 个文件、约 2.56 万行;每个文件导出若干以 this 为首参的函数,由 methods/index.ts 安装到原型上
helpers/53 个文件、约 7900 行;显式接收 runtime 参数或完全无状态的辅助函数
internal.tsinternal-methods.tsinternal-turn-methods.tsinternal-hook-methods.tsAgentRuntimeInternal:给方法文件用的内部视图
types.tsAgentRuntimeConfigAgentRuntimeDeps 与各方法的入参、出参类型
deps.ts统一依赖出口:从 @zcode/contracts 与 core 其他目录再导出,外加两个 trace 包装函数
execution-state.tssession-mode-port.tsmodel-selection.ts权限模式与 Plan 开关、给工具用的模式端口、模型选择的防御性拷贝
command-queue.ts运行时命令队列,见输入受理
permission-full-access.tspermission-grant-recovery.ts审批时一键切换完全访问,见权限模式与规则

一个会话,一个实例

构造器签名是 constructor(sessionId, config, deps)apps/zcode-cli/packages/core/src/runtime/agent-runtime.ts:228)。sessionId 只在构造时赋值一次(agent-runtime.ts:230),类上没有任何改写它的方法,getSessionId() 原样返回它(apps/zcode-cli/packages/core/src/runtime/methods/config.ts:255),所以一个实例从生到死只服务一个会话。bootstrap 里有一段注释把这层关系写得很直白:ZCodeAppAgentRuntimesessionId 两两 1:1(apps/zcode-cli/packages/bootstrap/src/app/dynamic-workflow-run-progress-sink.ts:27)。

整个仓库里 new AgentRuntime( 只出现在四处:

位置创建的是事件存储
apps/zcode-cli/packages/bootstrap/src/app/create-app.ts:726每个 ZCodeApp 的主会话宿主传入,缺省新建内存存储(create-app.ts:730
apps/zcode-cli/packages/core/src/runtime/methods/subagent.ts:239子 Agent 的子会话与父共用(subagent.ts:296
apps/zcode-cli/packages/bootstrap/src/app/script-workflow-child-runtime.ts:111动态工作流 actor 与旧脚本工作流的子会话与父共用(script-workflow-child-runtime.ts:191
apps/zcode-cli/packages/bootstrap/src/app/workflow-facade.ts:283专家工作流每个活动的子会话另建一个内存存储(workflow-facade.ts:299

一个进程里可以同时存在多个实例。TUI 同一时刻只持有一个 ZCodeApp,换会话时新建、再关掉旧的(apps/zcode-cli/packages/cli/src/tui-prompt-handler.ts:63tui-prompt-handler.ts:123);桌面端与 Web 拉起的协议服务则用一张 Map 管着多条会话记录(apps/zcode-cli/packages/bootstrap/src/zcode-protocol/server.ts:260),每条记录各有自己的事件存储、ZCodeApp 与 runtime(apps/zcode-cli/packages/bootstrap/src/zcode-protocol/server-operations.ts:3300server-operations.ts:3323),空闲的由常驻池回收,见会话事件流的“会话驻留”一节。

它持有什么

82 个字段全部声明为 privateagent-runtime.ts:133agent-runtime.ts:226),都只在内存里;需要跨进程存活的部分写进 SessionStorePort,冷启动时由 resumeFromStore 读回,见 SQLite 会话库。按用途归纳:

类别代表字段
身份与配置sessionIdturnNumberconfigappVersionworkingDirectory(Bash cd 会改)、workspaceRoot(不随 cd 漂移)、sessionModelSelection
端口与协作对象permissionServicepermissionBrokertoolSchedulerregistryexecutorhookRunnermodelFactoryexecutionPortfileSystemPortmcpPortsubagentPort 等二十余个
对话与上下文messageHistoryreadFileStatecachedToolscontextBuildercontextInitializedcontextSourceSnapshotmemoryRoot
事件与观测eventReducereventStoreeventSinks(一个 Set)、rootTraceContextloggeragentTelemetry
调度与回合runtimeCommandQueueruntimeCommandDrainActiveactiveForegroundExecutionforegroundPromotionLeaseactiveTurnactiveTurnStartReservationpendingInputReservationsqueueAutoDrain
持久化与投影标记sessionPersistedlatestConversationMessageIdlatestAssistantTurnIdpendingModelChangeTimelinesessionTitleGenerationAttempted
计数与保护mainTurnCacheHitAggregatecurrentTurnFileChangesautoCompactConsecutiveFailuresbranchGeneration(回退后丢弃旧分支的后台结果)
生命周期mcpStartupPromiseresidencyBlockingWorkCountshuttingDownbackgroundTaskNotificationsSealed

依赖哪些 Port

AgentRuntimeDeps 共 49 项(apps/zcode-cli/packages/core/src/runtime/types.ts:309),只有事件存储 eventStore 与模型工厂 modelFactory 必填(types.ts:314types.ts:317),其余缺席就意味着对应能力不存在。下表中端口接口所在文件都在 apps/zcode-cli/packages/contracts/src/interfaces/ 下,另注明的除外:

类别依赖接口定义
会话与事件eventStoreeventSinksessionStoresessionMailboxPortsession.port.ts:57session.port.ts:76session-store.port.ts:1089session-mailbox.port.ts:12
模型modelFactoryproviderRuntimeHeadersPortmodelRequestAdmissionmodelCatalogPortresolveEffectiveModelSelectionmodelIoDirtypes.ts:386types.ts:395(core);apps/zcode-cli/packages/contracts/src/model/index.ts:74model-catalog.port.ts:29
本地 I/OexecutionPortfileSystemPorthttpClientPortimageProcessorPortpdfDocumentPortartifactStorebrowserControlPortexecution.port.ts:278file-system.port.ts:280http-client.port.ts:89image-processor.port.ts:78pdf-document.port.ts:41tool-artifact-store.port.ts:106browser-control.port.ts:537
上下文与扩展contextSourcePortskillPortmcpPortcontextBuildermemoryRootcontext-source.port.ts:92apps/zcode-cli/packages/contracts/src/skills/index.ts:108mcp.port.ts:290
权限与钩子permissionServicepermissionBrokerhookRunnerworkspaceHookAdmissionworkspaceHookSnapshotpermission.port.ts:95;其余是 core 自己的类型
工具装配toolRegistrytoolExecutortoolSchedulerruntimeTaskRegistrycore 内部类型,缺省在构造器里新建
多 Agent 与工作流subagentPortcoordinatorResponsePortworkflowPortworkflowSubmitPortworkflowSubmitSchemaworkflowEscalatePortdynamicWorkflowRunPortdynamicWorkflowSnippetPortsubagent.port.ts:113coordinator-response.port.ts:18workflow.port.ts:36workflow-submit.port.ts:45workflow-escalate.port.ts:47dynamic-workflow-run.port.ts:600dynamic-workflow-snippet.port.ts:49
自动化automationPortoffPeakPortautomation.port.ts:43off-peak.port.ts:47
观测与环境agentTelemetry 及其两项因果配置、loggertraceContextappVersionnowisRemoteWorkspaceapps/zcode-cli/packages/contracts/src/telemetry/agent-execution.ts:277

有一部分端口 runtime 自己并不保存,只在构造时转交给工具执行器,例如 httpClientPortautomationPortoffPeakPort、三个工作流端口(apps/zcode-cli/packages/core/src/runtime/helpers/runtime-tools.ts:154)。端口在不在场,也直接决定注册哪些内置工具(runtime-tools.ts:49):

  registerBuiltInTools(runtime.registry, {
    bashTimeoutPolicy: runtime.config.bashTimeoutPolicy,
    includeSkill: Boolean(runtime.skillPort),
    includeAgent: Boolean(runtime.subagentPort),
    includeSendMessage: runtime.subagentPort?.sendMessage !== undefined,
    includeRespondToCoordinator:
      runtime.config.taskType === "subagent_child" && Boolean(deps.coordinatorResponsePort),
    // submit_result 只在注入了 workflowSubmitPort 的 workflow actor 会话注册。以端口存在为门,
    // 与 taskType 无关:workflow actor 是 workflow_child,其 runtimeScope 目前是 "main"。
    includeSubmitResult: Boolean(deps.workflowSubmitPort),
    // ...
    includeWorkflow: Boolean(deps.workflowPort),
    includeAutomation: Boolean(deps.automationPort) && runtime.config.taskType !== "subagent_child",

例外写在注释里:十个动态工作流工具的端口在任何 CLI 里都装配齐全,灰度由宿主决定,所以不看端口,看 config.dynamicWorkflowEnabledruntime-tools.ts:70);node_repl 与浏览器控制也不因宿主给了 browserControlPort 就暴露,而是看官方插件推导出的 runtimeFeaturesruntime-tools.ts:74)。

端口的边界并不绝对。apps/zcode-cli/AGENTS.md 要求业务模块不直接调用 fschild_processprocess.env 等底层 API(apps/zcode-cli/AGENTS.md:53),但 core/src 里仍有 13 个文件直接 import 了 node:fs(直接起子进程的一个也没有),例如 apps/zcode-cli/packages/core/src/runtime/methods/bash-shell-snapshot.ts:1,多数是 Bash、任务输出与工作流相关的工具,另有浏览器客户端、钩子与子 Agent 的几处。端口的实现从哪来、怎样按配置组装,见下一篇 bootstrap

近百个方法文件怎样装到一个类上

类文件只有 664 行,因为方法体都不在里面。agent-runtime.ts 先声明一个只有字段和构造器的 class,再声明一个同名的 interface 列出公开方法,两者被 TypeScript 合并成同一个类型;文件末尾一行把实现装上原型(agent-runtime.ts:131):

// oxlint-disable typescript-eslint/no-unsafe-declaration-merging
export class AgentRuntime {
  private sessionId: SessionId;
  // ...
}

export interface AgentRuntime {
  lastPermissionGrantId?: string;
  beginShutdown(): void;
  // ...
  getMode(): CollaborationMode;
  // ...
}

installAgentRuntimeMethods(AgentRuntime);

安装函数就是一长串赋值(apps/zcode-cli/packages/core/src/runtime/methods/index.ts:197):

type AgentRuntimeConstructor = { prototype: object };

export function installAgentRuntimeMethods(ctor: AgentRuntimeConstructor): void {
  const proto = ctor.prototype as Record<string, unknown>;
  proto.updateConfig = updateConfig;
  proto.setExecutionState = setExecutionState;
  proto.grantPermissionFullAccess = grantPermissionFullAccess;
  proto.initializeSessionShellEnvironmentIfNeeded = initializeSessionShellEnvironmentIfNeeded;
  proto.getSessionShellSelection = getSessionShellSelection;
  proto.getMode = getMode;
  // ...
  proto.isProjectMemoryEnabled = isProjectMemoryEnabled;
}

被安装的都是普通函数,用 TypeScript 的 this 参数声明调用者类型,例如 export function getMode(this: AgentRuntimeInternal)config.ts:86)。一共装了 187 个方法,来自 46 个方法模块和另外两个文件(permission-full-access.tshelpers/project-memory-extraction.ts)。其中 87 个出现在公开 interface 里,再加上类体里的 beginShutdowncloseBrowserSession,公开方法共 89 个;另外 100 个只给内部互相调用。方法文件里还有两种不安装的写法:只在模块内用的 this 函数经 .call(this, …) 调用,如 runRuntimeCommand.call(this, firstCommand)apps/zcode-cli/packages/core/src/runtime/methods/runtime-command-queue.ts:61);显式收 runtime 参数的函数,如 applyRuntimeExecutionState(runtime, input, cause)apps/zcode-cli/packages/core/src/runtime/execution-state.ts:43)。

为什么这么拆?CLI 的 AGENTS.md 规定单个源文件默认不超过 400 行(apps/zcode-cli/AGENTS.md:12);internal-hook-methods.ts 开头的注释说,它是为了让 internal-methods.ts 不越过 400 行、通过一个名为 runtime-module-boundary 的测试而单独拆出来的(apps/zcode-cli/packages/core/src/runtime/internal-hook-methods.ts:5)。这个测试不在开源仓库里,全仓只有 4 个测试文件,都不在 apps/zcode-cli。规则也没有被严格执行:97 个方法文件里有 22 个超过 400 行,最大的 session-fork.ts 有 1487 行、steering.ts 有 1403 行,types.ts 则干脆关掉了 max-lines 检查(types.ts:2)。

代价是编译器不再替你核对“原型上真的有这个方法”,这正是被关掉的那条 lint 规则要防的事。从代码看,新增一个方法要改三处:方法文件、methods/index.ts 的安装行、内部或公开的方法声明,漏掉安装行只会在运行时以“不是函数”的形式暴露。

AgentRuntimeInternal:内部视图

字段是 private 的,类体之外的函数按理读不到。AgentRuntimeInternalapps/zcode-cli/packages/core/src/runtime/internal.ts:60)把同样的字段以公开属性重新声明一遍,并继承三组方法声明:AgentRuntimeCoreMethodsAgentRuntimeTurnMethodsAgentRuntimeHookMethods,分别在 internal-methods.tsinternal-turn-methods.tsinternal-hook-methods.ts。方法文件一律把 this 声明成它,于是可以随意读写状态、互相调用内部方法;bootstrap 与协议层拿到的仍是合并后的 AgentRuntime 类型,看不到私有字段,也看不到那 100 个内部方法。

由于同名字段一边是 private、一边是公开属性,两个类型互不兼容,构造器只能先做一次 this as unknown as AgentRuntimeInternal 的双重断言(agent-runtime.ts:229),再调用 createDefaultSubagentPortstartMcpStartup 等内部方法。内部视图比类多出 4 个字段:sessionMailboxPortpermissionFullAccessPendingpendingInputDrainslastPermissionGrantIdinternal.ts:117internal.ts:136)。后三个是运行中动态挂上的,例如 permissionFullAccessPendingapps/zcode-cli/packages/core/src/runtime/permission-full-access.ts:34 置位;sessionMailboxPort 则只有声明、从未被赋值,邮箱端口实际直接从 deps 读(runtime-tools.ts:109)。还有些状态干脆不挂在实例上,而是放进以实例为键的 WeakMap,例如“事务已提交、事件尚未发布”的权限授予(apps/zcode-cli/packages/core/src/runtime/permission-grant-recovery.ts:4)。

构造时做了什么

构造器依次做配置投影、建缺省对象、派生根 trace 与子 logger、保存端口、新建消息历史与命令队列、装配工具,最后提前启动 MCP,主干如下(agent-runtime.ts:228):

  constructor(sessionId: SessionId, config: AgentRuntimeConfig, deps: AgentRuntimeDeps) {
    const runtime = this as unknown as AgentRuntimeInternal;
    this.sessionId = sessionId;
    this.turnNumber = 0;
    // ...
    this.permissionBroker = deps.permissionBroker ?? createDenyPermissionBroker();
    // ...
    this.eventReducer = new EventReducer();
    this.eventStore = deps.eventStore;
    this.sessionStore = deps.sessionStore;
    this.rootTraceContext = deps.traceContext ?? createRootTraceContext({ sessionId });
    // ...
    this.subagentPort = deps.subagentPort ?? runtime.createDefaultSubagentPort(deps);
    // ...
    const tooling = initializeRuntimeTooling(runtime, deps, sessionId);
    this.hookRunner = tooling.hookRunner;
    this.workspaceHookAdmission = deps.workspaceHookAdmission;
    this.executor = tooling.executor;

    this.contextBuilder = deps.contextBuilder ?? null;
    if (this.contextBuilder) {
      runtime.initializeMessageHistoryFromContext(this.contextBuilder, this.rootTraceContext);
      this.contextInitialized = true;
    }
    runtime.startMcpStartup(this.rootTraceContext);
  }

几个值得注意的缺省:

  • 审批缺省拒绝。宿主不注入 permissionBroker 时用 DenyPermissionBroker,任何需要问人的工具调用都会以“No permission client configured”被拒(apps/zcode-cli/packages/core/src/permission/broker.ts:24)。
  • 上下文预算策略被强制改写AgentRuntimeConfig 允许传 "legacy""preflight-v1"types.ts:130),但构造器无论传什么都覆盖成共享默认值(agent-runtime.ts:232),即 "preflight-v1"packages/shared/src/zcode-protocol/index.ts:1696);注释说 3.12.2 仍接受旧宿主传入 legacy,但运行时、日志与子 Agent 只用 preflight。
  • 模型选择可以缺席。旧会话恢复时可能没有完整选择,构造器不替它挑默认模型(agent-runtime.ts:274),真正开跑时才由 createRuntimeModel 拒绝(apps/zcode-cli/packages/core/src/runtime/methods/runtime-model.ts:21)。
  • MCP 在构造时就开始连startMcpStartup 立即发起配置里各服务器的连接,并登记为阻止会话回收的在飞工作(apps/zcode-cli/packages/core/src/runtime/methods/mcp.ts:111),首轮回合开始时多半已经连好,细节见 MCP

trace 上下文怎么传下去

CLI 的 AGENTS.md 对可观测性的要求很硬:所有任务执行都携带可传播的 traceId,它默认对应一次顶层会话的完整任务链,子会话、子 Agent、重试与后台任务都归属同一个 traceIdsessionIdturnIdspanId 等是它之下的结构化子标识(apps/zcode-cli/AGENTS.md:74apps/zcode-cli/AGENTS.md:75)。上下文对象定义在 apps/zcode-cli/packages/contracts/src/tracing/tracer.ts:14,字段是 traceIdqueryIdspanIdparentSpanIdparentIdsessionIdturnId 与自由属性 attributes。派生子上下文沿用 traceId、生成新的 spanId、把父 spanId 记成 parentSpanId,并合并属性(tracer.ts:212):

export function createChildTraceContext(
  parent: TraceContext,
  options: {
    queryId?: QueryId;
    sessionId?: SessionId;
    turnId?: TurnId;
    attributes?: Record<string, string | number | boolean>;
  } = {},
): TraceContext {
  return {
    traceId: parent.traceId,
    queryId: options.queryId ?? parent.queryId,
    spanId: generateSpanId(),
    parentSpanId: parent.spanId,
    parentId: parent.spanId,
    sessionId: options.sessionId ?? parent.sessionId,
    turnId: options.turnId ?? parent.turnId,
    attributes: {
      ...parent.attributes,
      ...options.attributes,
    },
  };
}

deps.ts 在这个函数和 traceContextToLogContext 外面又各包了一层,显式把 queryId 带上(apps/zcode-cli/packages/core/src/runtime/deps.ts:18deps.ts:34),runtime 内部一律用包装后的版本。一条消息的 trace 链路是这样串起来的:

图表加载中…
  • 。协议层建会话记录时,如果宿主请求带了 traceIdspanId 就沿用,否则新生成一个 UUID(apps/zcode-cli/packages/bootstrap/src/zcode-protocol/server-types.ts:274);进程内的 TUI 由 createZCodeApp 自己新建(create-app.ts:153)。runtime 拿到后存进 rootTraceContext,并用它派生带 module: "core.runtime" 的子 logger(agent-runtime.ts:258agent-runtime.ts:260)。
  • 回合。受理输入时派生回合上下文,写入新的 turnIdqueryId 与属性 turnNumberapps/zcode-cli/packages/core/src/runtime/methods/prompt-admission.ts:88),整个回合在 runWithContextAsync 里执行(apps/zcode-cli/packages/core/src/runtime/methods/turn.ts:184),底层是 AsyncLocalStoragetracer.ts:166)。
  • 模型步。每次模型请求再派生一层,带上 providerIdmodelIditerationquerySourceapps/zcode-cli/packages/core/src/runtime/methods/turn-model-step.ts:158);标题生成这类旁路请求同样从回合上下文派生。回合中途注入一条 guide 后,后续请求改挂在那条输入的 queryId 上(apps/zcode-cli/packages/core/src/runtime/methods/turn-guide-drain.ts:52)。
  • 隐式取用。工具执行器、钩子运行器发事件时没有显式上下文,一律取 getCurrentTraceContext() ?? runtime.rootTraceContextruntime-tools.ts:99runtime-tools.ts:161)。
  • 落到事件与子会话。事件本身只记 traceIdturnIdapps/zcode-cli/packages/core/src/runtime/methods/events.ts:69),spanId 这一层只进日志;子 Agent 的 runtime 直接拿请求里的 trace 作为自己的根(subagent.ts:366),与父会话共享 traceId

执行状态、模式端口与模型选择

执行状态只有两个字段:权限模式 modebuildedityolo 与内部用的 autoplan 只在读旧格式时接受)和 Plan 开关 planEnabledpackages/shared/src/execution-state.ts:3)。修改统一走 core 的 applyRuntimeExecutionStateapps/zcode-cli/packages/core/src/runtime/execution-state.ts:43):完全访问的切换进行中则拒绝;Plan 与进行中的 Goal 不能同时生效;先把状态写成会话条目 runtime/execution_state,成功后才改内存,最后发 SessionModeChanged 事件,注释写明“保存失败不发布成功快照,也不提前改内存”(runtime/execution-state.ts:42)。

模式端口 createRuntimeSessionModePortapps/zcode-cli/packages/core/src/runtime/session-mode-port.ts:5)把进出 Plan 模式包装成端口交给工具执行器(runtime-tools.ts:193),Plan 相关工具经它切换状态,不直接碰 runtime 字段;工具一侧的行为见 Todo、提问与 Plan 模式

模型选择 cloneModelSelection 只做一件事:逐字段拷贝 providerIdmodelIdoptionsapps/zcode-cli/packages/core/src/runtime/model-selection.ts:3)。读写 sessionModelSelection 时两头都拷贝(config.ts:94),外部拿到的对象改了也不会串回 runtime。模型怎样按选择创建,见模型适配层

对外公开的方法

89 个公开方法按用途归纳:

类别个数主要方法
输入与回合10admitPromptexecuteTurnsteerTurnenqueueDeferredInputstopActiveForegroundExecutionrecordExternalUserPrompt
队列管理10removePendingInputByIdreservePendingInputByIdeditPendingInputByIdreorderPendingInputsetQueueAutoDrainsetFollowupMode
配置与模式12updateConfigsetExecutionStategetModegrantPermissionFullAccesssetSessionModelSelectionemitModelSelected
事件与投影7subscribeEventsappendEventgetSessionEventStoregetProjectionisSessionPersisted
会话标题3setCustomSessionTitlemaybeStartSessionTitleGenerationFromExternalInput
工具与权限9getToolRegistryinvalidateToolCachescheduleToolsexecuteToolsresolvePermissioncreateChildClientPorts
目标5recordTargetChangedcontinueActiveTargetIfIdlecontinueActiveTargetLoop
后台任务与工作流10readBackgroundBashOutputstopBackgroundTasksealBackgroundTaskNotificationsstartSavedWorkflowRunamendWorkflowRunSettings
恢复、回退与分叉9resumeFromStorerewindConversationToMessageforkStableConversationAtMessagepreviewWorkspaceFileRewind
驻留与生命周期5hasActiveOrQueuedTurnWorkhasResidencyBlockingWorktrackResidencyBlockingWorkbeginShutdowncloseBrowserSession
其他9getSessionIdgetProjectIdgetSkillCataloggenerateWorkspaceTexttestModelConnectivitydrainMemoryExtractions

createChildClientPortsgetSessionEventStorenotifyExternalChildSessionEvent 三个方法是给“在类外构造子 runtime”的 bootstrap 留的接缝:子会话必须共用父的事件存储,否则 transcript 会是一片空白;审批与请求头端口必须路由回父会话,注释记录了曾经因为身份错位让子代理在首个模型请求前挂起 80 分钟的事故(config.ts:177config.ts:191config.ts:216)。

RuntimeFactory 与 core 的导出面

@zcode/corepackage.json 声明了四个入口:主入口、./repl./browser-client./create-workflow-graph-boundsapps/zcode-cli/packages/core/package.json:8)。主入口把 agent、context、compact、tool、hooks、mcp、subagent、runtime-task、workflow、permission 等子目录整体再导出,运行时部分在 apps/zcode-cli/packages/core/src/index.ts:132 导出 AgentRuntime,另外点名导出几个 bootstrap 也要用的函数,例如 fork 与 dwf 截断共用的消息克隆器,注释解释了为什么不让 bootstrap 再抄一份(core/src/index.ts:135)。

core/src/runtime.ts 是运行时的二级出口,除了 AgentRuntime 与一批类型,还声明了一个工厂接口 RuntimeFactory,只有一个方法 create(config),返回 Promise<AgentRuntime>apps/zcode-cli/packages/core/src/runtime.ts:38)。它经 index.ts 以类型导出,但在整个仓库里找不到任何实现或使用方,四处创建实例都直接 new AgentRuntime(...)。从签名看它也装不下今天的构造器:只收 config,既没有 sessionId 也没有 deps,更像早期设计留下的契约。

下一篇:bootstrap:把运行时拼起来——这四十九项依赖从哪里来:配置分层、数据目录、模型工厂,以及会话怎样创建与恢复。

本页目录