引擎契约
CrystalCode.Engine 运行对话并报告发生了什么。前端交给它一个 SessionFrontEnd,调用它,并观察事件。前端从不直接读取引擎状态,引擎也从不绘制、读取按键或写到控制台。
前端提供(SessionFrontEnd):
Observer(ISessionObserver)接收每个SessionEvent。Approvals(IApprovalPrompt)请操作者批准工具调用,并在调用自动放行或正在审查时被告知。Questions(IUserPrompt)回答内置question工具。Sessions(ISessionChooser)为/resume挑选已保存的会话,包括一个工作区或每个工作区。Trust(IWorkspaceTrustPrompt)询问是否信任一个目录。无法询问的前端返回 false。
前端调用 CodingSession:Create、StartAsync、SubmitAsync(斜杠命令、回合运行时的后续请求、中断和回合开始;操作者要求退出时返回 true)、TurnTask 结束后的 CompleteTurnAsync、退出前收集回合的 FinishTurnAsync、TryInterrupt、TogglePlan、SetVerbose、NotifyDraftChanged、Enqueue、PasteClipboardImageAsync 和 Close。TurnActive、TurnTask、PlanMode 和 SessionId 报告状态。通常的回合是:SubmitAsync,等待 TurnTask,然后 CompleteTurnAsync。
事件是不可变的密封记录,Events 下一个文件一个类型:
- 生命周期和界面:
SessionStarted、ChromeChanged、PreferencesChanged、SlashCommandsChanged、PromptHistoryLoaded、ImageHistoryInvalidated、ActivityChanged。 - 回合:
UserMessageSent、TurnStarted、StreamReceived(携带 Crystal 的ChatStreamEvent)、ToolCallsIssued、ToolResultsReceived、ModelRoundClosed、RetryScheduled、UsageChanged、TurnFinished、QueueChanged。 - 对话:
HistoryReplayed、ConversationCleared、TodosChanged。 - 文本和报告:
NoteWritten、ErrorWritten、HelpRequested、StatusReported、ToolsListed。
引擎从产生更改的线程发布,包括模型轮次流式输出时的回合线程。观察者必须线程安全并快速返回;有 UI 线程的前端封送到该线程。事件携带引擎值,不是标题:引擎报告 SessionActivity,前端选择措辞和布局。
引擎拥有用量数字。它保持上下文用量和会话累计合计,包括回合内累计计数所加到的基线,并通过 UsageChanged 和 TurnFinished 报告它们。前端渲染它们,不计算合计。
有些引擎调用需要时间(收集回合、/compact、切换模型)。前端等待它们而不冻结界面。终端宿主在调用运行时通过泵送画面来做到这一点。
图像标记以文本跨越边界。UserMessageSent 和重放的记录携带 [Image #N] 标记,标记只有以 ImageMarkerText.Prefix(U+2063)开头时才受信任。附加图像的输入框只为已附加的跨度加前缀。Display 不能引用引擎,因此它持有自己的前缀副本;ImageMarkerContractTests 保持两者相等。
添加前端意味着引用 CrystalCode.Engine,实现上面五个契约,并把事件投影到自己的界面。CrystalCode 中的终端宿主是参考实现。CrystalCode.Engine.Tests 中的无头测试是最小的正确驱动。以后的 Avalonia 桌面前端使用 C# markup,不添加 XAML 或 AXAML 文件。
crystal run 是此可执行文件中的无头前端,不是第二个程序集。它从参数或 stdin 读取一项任务,应用仅限进程的覆盖,启动一个用户回合,然后退出。交互式 crystal 和 crystal space 命令应用相同的会话覆盖:审批、审批模型及其思考档位、Plan 或 Work、思考、所选模型的上下文预算、服务层级、速度、提示集、提示附件、技能、外部工具、插件和回合配额。覆盖不写入 config.json。这包括审批模型开关(--approval-model、--approval-provider、--approval-model-id)和档位(--approval-thinking)。之后的交互偏好命令写入操作者更改的字段,也可以写入启动时传入的 --provider 或 --model。它不写入其他启动覆盖。任务文本、--format、--show-thinking、--space 和 --workspace-trust 留在 crystal run 上。crystal run 拒绝斜杠命令,使它们不能更改已保存的设置。秘密不是命令标志。
该运行提供 RunLog 或 RunJsonLog、UnattendedApprovalPrompt、UnattendedUserPrompt、UnattendedSessionChooser 和 UnattendedTrustPrompt。信任提示是失败关闭的回退。目录检查本身在创建会话前运行,并遵循 --workspace-trust,而不是 workspaceTrust。审批提示拒绝每个本会询问操作者的调用。问题提示被驳回。会话选择被拒绝。Review 和 Audit 仍然调用审查模型:允许则执行工具,拒绝则返回审查者的理由。Plan 不提供 write、edit 或 bash。目录仍包含这些副作用时,审批策略也会拒绝它们。
--format default 写可读的跟踪。每轮模型只在设置了 --show-thinking 时打印思考文本,然后是助手回复,然后每个工具紧挨自己的结果。设置了 --show-thinking 时,回复标为 [Assistant]。read、list、glob、grep 和其他成功工具保留短的开头摘录和省略行计数。edit 和 write 保留其结果。bash 保留命令、退出状态和短的结尾,命令失败时结尾更长。其他失败保留结果文本。标签使用方括号,退出状态使用圆括号,省略行标记使用尖括号。--format json 每行写一个 JSON 对象,带 type、UTC timestamp 和 sessionID,并保留完整工具输出。事件类型是 step_start、text、reasoning、tool_use、error、note、retry、step_finish、stopped 和 session。除非设置了 --show-thinking,否则省略思考文本。进程随后打印已保存的会话 id。退出 0 表示回合完成,且没有操作者提示被拒绝或驳回。退出 1 是无效的命令、配置、凭据、工作区或提示集。退出 2 是失败的模型请求。退出 3 是模型调用、工具调用或时长预算,或上下文溢出。退出 4 是操作者拒绝或问题被驳回之后、不是失败、预算停止或中断的结束。退出 5 是中断。失败、预算停止或中断优先于拒绝。