DSH / Atlas
2026-08-09implementedarchitecture

headless is a direct core entry point

headless 是直接使用核心服务的入口

The `headless` product contract is one local task with final assistant text on stdout, a success-sensitive exit code, empty stderr on success, and no listening port. A composition containing Workspace Host services, ApiProxy, HTTP, the Web runtime, or browser plugins contradicts that contract and makes local completion depend on an unrelated transport tree. The direct entry point still needs the same deployment model

English

Problem

The headless product contract is one local task with final assistant text on stdout, a success-sensitive exit code, empty stderr on success, and no listening port. A composition containing Workspace Host services, ApiProxy, HTTP, the Web runtime, or browser plugins contradicts that contract and makes local completion depend on an unrelated transport tree.

The direct entry point still needs the same deployment model state as Web-created Agents. A separate provider/model default would give one deployment two answers, while deriving completion before the Agent and Session persistence are quiescent permits stdout and the exit code to observe incomplete state.

Decision

The shipped headless profile contains dsh-base and dsh-headless. The headless bundle supplies its persona and tool mode, disables HMR, mounts the Code Mode worker explicitly, and inserts headless-runner. Its tree contains no @deepseek-ai/dsh-host-* package, ApiProxy, HTTP server, Web runtime, or browser client. Code Mode and Session persistence are one-shot Agent capabilities independent of Web presentation.

headless-runner is a direct core entry point. After Loader settlement, it reads ctx.agentDefaultModel.currentSelection(), creates a fresh persisted Agent through ctx.agents.create, installs that ModelSelection in the Agent scope, waits for startup quiescence, anchors the Session sequence, submits one ordinary user message, and waits for quiescence again. It awaits ctx.sessions.flush, folds its durable event interval for the last non-empty assistant text and final turn/end reason, writes the text plus one newline to stdout, and requests bounded launcher shutdown with exit 0 exactly when the reason is completed. A terminal error reason writes its durable code and message to stderr; unexpected driver failures also use stderr and exit 1.

@deepseek-ai/dsh-agent-default-model owns the transport-independent default used for an Agent without a session-local selection. AgentDefaultModelConfig provides ctx.agentDefaultModel and registers the agent-default-model Settings section. Composition config supplies {provider, model}; user settings may also supply reasoningEffort. currentSelection() returns the live complete selection and saveSelection() writes it as a complete section, so a selection without an effort clears any stored effort. dsh-base supplies the composition entry. Direct and ApiProxy entry points consume this service; ApiProxy alone owns session-local precedence, model validation, and persistence of accepted Web selections.

loadProfile recognizes the exact installation-owned headless tuple (dsh-base, dsh-web-app, dsh-headless) and normalizes it to the shipped headless template while preserving every other manifest field. Extra, missing, or reordered bundle lists are user-owned and remain untouched.

This note owns the headless transport and completion contracts. Apps own their command lines owns the current dsh --profile headless grammar; the former dsh run decision records the superseded launcher-owned grammar, GUI layering and RPC protocol owns browser gateway boundaries, web config-tree boot and transport layering owns the Web tree, and the default model follows the picker owns persistence of the shared Agent default.

Verification

Package tests use the real Session store and Agent registry around a scripted Agent factory to pin idle-to-idle aggregation, late asynchronous completion, terminal model diagnostics, other non-completed exits, direct failures, Loader-time disposal, and flush-before-exit ordering. The keyless assembled snapshots drive dsh --profile headless through a replayed tool round trip, record a user/message with source.kind: 'user', and expose a terminal model failure on stderr. Built-bin acceptance reaches a mock provider through the published entry and requires final text on stdout, exit 0, and empty stderr. Config-dump acceptance excludes every Host, Web, and Client package from the shipped headless tree; PTY shutdown coverage requires no observation line and bounded disposal.

Alternatives considered

AlternativeContract mismatch
Keep dsh-web-app but suppress its observation lineThe process still opens a port and carries the Host, Web, and browser trees.
Build a Host-only one-shot bundle around ApiProxyApiProxy is a client protocol gateway; a local one-shot entry point has no client boundary.
Use InProcessApiClient for product-level protocol coverageProduct execution would depend on an unrelated protocol solely to exercise that protocol.
Give headless a separate provider/model configDirect and Web creation would have independent defaults and persistence.
Omit Code Mode and Session persistenceBoth capabilities belong to one-shot Agent execution rather than Web presentation.
Normalize every tuple containing Web and headless bundlesBundle lists are an extension surface; only the exact installation-owned tuple is safe to classify.

Consequences

dsh --profile headless provides a local Agent task rather than browser observation, Host APIs, or HTTP. Users who need those capabilities choose dsh web. Successful stderr is empty, completion follows durable flush, and the persisted Session remains available to later tooling. Its initial user message records source.kind: 'user' and therefore carries no ApiProxy rpcId.

ApiProxy carrier coverage stays in the ApiProxy package. Custom one-shot profiles may include Host or Web bundles explicitly, while the shipped profile and the recognized installation-owned tuple are Web-free.

中文

问题

headless 的产品约定是一个本地任务:最终 assistant 文本写入 stdout,退出状态反映成功与否,成功时 stderr 为空,并且不打开监听端口。包含 Workspace Host 服务、ApiProxy、HTTP、Web 运行时或浏览器插件的组合违背这一约定,也使本地完成状态依赖无关的传输树。

直接入口仍需要与 Web 所创建 Agent 相同的部署模型状态。独立的提供方/模型默认值会让同一部署产生两种答案,而在 Agent 与会话持久化完全停稳之前推导完成状态,会让 stdout 与退出状态观察到不完整状态。

决策

随附的 headless profile 包含 dsh-basedsh-headless。headless 组合包提供自身的 persona 与工具模式、禁用 HMR(热模块替换)、显式挂载 Code Mode worker,并插入 headless-runner。其插件树不包含任何 @deepseek-ai/dsh-host-* 包、ApiProxy、HTTP server、Web 运行时或浏览器客户端。Code Mode 与会话持久化均为独立于 Web 呈现的一次性 Agent 能力。

headless-runner 是直接使用核心服务的入口。Loader 完全加载后,它读取 ctx.agentDefaultModel.currentSelection(),通过 ctx.agents.create 创建一个新的持久化 Agent,在 Agent 作用域中安装该 ModelSelection,等待启动工作完全停稳,锚定会话事件序号,提交一条普通用户消息,再次等待完全停稳。随后,它等待 ctx.sessions.flush,折叠自身持有的持久事件区间,以取得最后一条非空 assistant 文本和最终 turn/end 结束原因,将文本连同一个换行写入 stdout,并且仅在结束原因为 completed 时请求启动器以退出状态 0 有界关闭。结束原因为 error 时,其持久化错误码与消息写入 stderr;驱动器的意外失败也写入 stderr 并以 1 退出。

@deepseek-ai/dsh-agent-default-model 拥有与传输无关的默认值,供没有会话级选择的 Agent 使用。AgentDefaultModelConfig 提供 ctx.agentDefaultModel 并注册 agent-default-model Settings 分节。组合配置提供 {provider, model},用户设置还可以提供 reasoningEffortcurrentSelection() 返回当前的完整选择,saveSelection() 则写入完整分节,因此不含强度的选择会清除已存强度。dsh-base 提供组合条目。直接入口与 ApiProxy 入口均消费该服务;只有 ApiProxy 负责会话级优先级、模型校验与已接受 Web 选择的持久化。

loadProfile 识别安装过程拥有的精确 headless 元组(dsh-basedsh-web-appdsh-headless),将其规范化为随附的 headless 模板,并保留 manifest(元数据清单)的其他所有字段。带额外项、缺少项或顺序不同的组合包列表归用户所有,保持不变。

本 Agent Note 负责 headless 的传输与完成约定。应用持有自己的命令行负责当前的 dsh --profile headless 语法;原 dsh run 决策记录已被取代的启动器持有语法,GUI 分层与 RPC 协议负责浏览器网关边界,Web 配置树启动与传输分层负责 Web 插件树,默认模型跟随选择器负责共享 Agent 默认值的持久化。

验证

包测试围绕脚本化 Agent 工厂使用真实的会话存储与 Agent 注册表,固定空闲态到空闲态的聚合、延迟异步完成、终止态模型诊断、其他未完成退出、直接失败、Loader 加载期间的 dispose(资源释放),以及退出前 flush 的顺序。组装后的无密钥快照通过回放的工具往返驱动 dsh --profile headless,记录一条带 source.kind: 'user'user/message,并在 stderr 暴露终止态模型失败。构建后二进制验收通过已发布入口访问 mock 提供方,并要求最终文本出现在 stdout、退出状态为 0 且 stderr 为空。配置转储验收排除随附 headless 树中的所有 Host、Web 与 Client 包;PTY 关闭覆盖要求不出现观察行,并在有界时间内完成 dispose。

考虑过的替代方案

替代方案约定不匹配之处
保留 dsh-web-app,但隐藏观察行进程仍会打开端口并携带 Host、Web 与浏览器插件树。
围绕 ApiProxy 构建纯 Host 一次性组合包ApiProxy 是客户端协议网关,而本地一次性入口没有客户端边界。
使用 InProcessApiClient 实现产品级协议覆盖产品执行会仅为测试无关协议而依赖该协议。
为 headless 单独提供提供方/模型配置直接创建与 Web 创建会拥有彼此独立的默认值和持久化。
省略 Code Mode 与会话持久化两项能力都属于一次性 Agent 执行,而不是 Web 呈现。
规范化所有包含 Web 与 headless 组合包的元组组合包列表是扩展面;只有精确的安装过程所属元组可以安全分类。

后果

dsh --profile headless 提供本地 Agent 任务,而不是浏览器观察、Host API 或 HTTP。需要这些能力的用户选择 dsh web。成功时 stderr 为空,完成结果在持久化 flush 后推导,持久化会话仍可供后续工具使用。初始用户消息记录 source.kind: 'user',因此不携带 ApiProxy rpcId

ApiProxy 载体覆盖保留在 ApiProxy 包中。自定义一次性 profile 可以显式包含 Host 或 Web 组合包;随附 profile 与可识别的安装过程所属元组均不含 Web。