@deepseek-ai/dsh-headless 0.1.1-rc.1 → 0.1.2-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +123 -7
- package/README.zh.md +124 -8
- package/cordis.patch.yml +2 -7
- package/lib/index.js +76 -11
- package/lib/invariant.js +4 -4
- package/lib/startup.js +1 -1
- package/lib/types/index.d.ts +2 -1
- package/package.json +20 -18
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/bundle/headless/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 282fa76dd720751d61ba7f44e5e35884d5f21e8f
|
|
6
|
+
README.zh.md: 5a2727a25e6e4840900ebc9dc70d10ff13db12dd
|
package/README.md
CHANGED
|
@@ -1,20 +1,136 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
description: "One-shot task mode for dsh: run a single task from the command line and get the final answer printed, for users scripting or automating dsh."
|
|
3
|
+
kind: "package-bundle"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @deepseek-ai/dsh-headless
|
|
2
7
|
|
|
3
8
|
English | [中文](README.zh.md)
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
`dsh-headless` runs one dsh task from the command line and prints the final answer, then exits — no GUI, no server, no browser. Type `dsh --profile headless "run the tests"` and the agent works through the task with the same model, tools, and safety defaults as every other surface. It is ideal for scripts, CI, and one-off jobs: the process opens no ports and leaves nothing running behind. The exit code tells you the outcome — 0 when the task completed, 1 when it aborted or errored. The main boundary: one task per invocation, with no interactive follow-up.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Use this package](#use-this-package)
|
|
17
|
+
- [Understand the implementation](#understand-the-implementation)
|
|
18
|
+
- [Further Exploration](#further-exploration)
|
|
19
|
+
- [Model Experience](#model-experience)
|
|
20
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
21
|
+
- [Dev Note](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## Use this package
|
|
27
|
+
|
|
28
|
+
Run one task, get the final answer, and exit. The task is the command line itself, so the whole invocation is the smallest working example.
|
|
29
|
+
|
|
30
|
+
### Running a one-shot task
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
dsh --profile headless "run the tests"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The agent works through the task, streams each non-empty provider reasoning delta to stderr under a `dsh: reasoning:` heading, then prints the final answer on stdout and exits. Consecutive reasoning deltas stay in one section, and the runner closes that section before later output when the provider supplied no trailing newline. A successful run without reasoning keeps stderr empty; a failure exits 1 and prints `dsh: <code>: <message>` to stderr. A missing or blank task is rejected before anything runs. The task text is supplied through the single `task` setting:
|
|
37
|
+
|
|
38
|
+
| Field | Default | Meaning |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| `task` | required | The task text for the single run |
|
|
41
|
+
|
|
42
|
+
The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-headless) is the exhaustive source for every accepted field and its JSDoc.
|
|
43
|
+
|
|
44
|
+
### When to use it
|
|
45
|
+
|
|
46
|
+
Use headless for scripted or automated dsh runs — CI steps, batch jobs, quick answers from a terminal. Avoid it when you need a multi-turn interactive session or a GUI; the browser surface ([dsh-web-app](../web-app/README.md)) serves that. The process stays alive only for the run, opens no listening port, and exits on its own, so it fits pipelines that wait on the process.
|
|
47
|
+
|
|
48
|
+
### Help and task errors
|
|
49
|
+
|
|
50
|
+
`dsh --profile headless --help` prints the command's help text and exits without running anything. A missing or whitespace-only task is a usage error: nothing runs and the process exits 1.
|
|
51
|
+
|
|
52
|
+
-----
|
|
53
|
+
|
|
54
|
+
<a id="understand-the-implementation"></a>
|
|
55
|
+
## Understand the implementation
|
|
56
|
+
|
|
57
|
+
<details>
|
|
58
|
+
<summary>Implementation internals — click to expand</summary>
|
|
59
|
+
|
|
60
|
+
The runner is a direct driver over the core API carrier: it creates one fresh Agent through the registry and folds the owned durable event interval into one process-level outcome.
|
|
61
|
+
|
|
62
|
+
### Run flow
|
|
6
63
|
|
|
7
|
-
|
|
64
|
+
The runner awaits the complete application (`ctx.get('loader')?.await()`) so the composed tools and adapters are not half-mounted, reads the shared [`agentDefaultModel`](../../core/agent-default-model/README.md) selection, creates one fresh persisted Agent with that provider and model, and submits the task as an ordinary user message. It streams that Agent's non-empty reasoning deltas to stderr, waits for quiescence, then flushes the Session and folds the owned interval (`firstSeq` onward) into the last non-empty `assistant/message` text and final `turn/end` reason. It writes the final text to stdout and requests exit.
|
|
8
65
|
|
|
66
|
+
### Patch surface over base
|
|
67
|
+
|
|
68
|
+
The patch rides over `dsh-base`: it inherits the projection cache, sets the coding persona on the base `system-prompt` row, keeps the same temporary process-wide PTC mode opt-in (`DSH_TOOLS_MODE`) as the Web surface, disables the shared HMR row, inserts PTC mode's worker as a core execution capability, and mounts the startup provider and the runner. The cache checkpoints each persisted one-shot session for later consumers; its durability barrier flushes each covered log prefix before publishing the cache row and may split otherwise coalesced JSONL runs. The startup provider ([`src/startup.ts`](src/startup.ts)) injects `ctx.cmdlineArgs` ([`dsh-cmdline`](../../boot/cmdline/README.md)), reads the positional argument, prints the app's `--help`, and provides `headlessStartup`; the runner injects that service and reads its task from lazy config.
|
|
69
|
+
|
|
70
|
+
### Exit mapping
|
|
71
|
+
|
|
72
|
+
A completed final `turn/end` exits 0; any other outcome — aborted, error, or no turn in the owned interval — exits 1. An `error` reason also writes `dsh: <code>: <message>` to stderr. A direct driver failure (for example, Agent creation) writes `dsh: <message>` to stderr and exits 1.
|
|
73
|
+
|
|
74
|
+
### Source map
|
|
75
|
+
|
|
76
|
+
| File | Role |
|
|
77
|
+
|---|---|
|
|
78
|
+
| [`src/index.ts`](src/index.ts) | The `headless-runner` plugin: run flow, output contract, exit mapping |
|
|
79
|
+
| [`src/startup.ts`](src/startup.ts) | The `headless-startup` provider: task positional and `--help` |
|
|
80
|
+
| [`cordis.patch.yml`](cordis.patch.yml) | The one-shot patch over `dsh-base` |
|
|
81
|
+
| [`src/invariant.ts`](src/invariant.ts) | Invariant companion: no runtime invariant; the observable contract is process-level |
|
|
82
|
+
| [`tests/headless.spec.ts`](tests/headless.spec.ts) | Run flow, aggregation, flush, and exit mapping |
|
|
83
|
+
| [`tests/startup.spec.ts`](tests/startup.spec.ts) | Command-line parsing over a real Loader tree |
|
|
84
|
+
|
|
85
|
+
### Invariant ownership
|
|
86
|
+
|
|
87
|
+
The invariant companion registers an empty installer because the runner's observable contract (final text on stdout, exit code by turn-end reason) is process-level and owned by the launcher e2e; the plugin registers nothing and holds no mutable relation to audit inside the tree.
|
|
88
|
+
|
|
89
|
+
</details>
|
|
90
|
+
|
|
91
|
+
-----
|
|
92
|
+
|
|
93
|
+
<a id="further-exploration"></a>
|
|
94
|
+
## Further Exploration
|
|
95
|
+
|
|
96
|
+
Read these pages when you want to go deeper into the shared core, the sibling GUI, or the command-line handoff.
|
|
97
|
+
|
|
98
|
+
- [Bundle package map](../README.md) — the surfaces built on the same core.
|
|
99
|
+
- [dsh-base](../base/README.md) — the shared core headless runs on.
|
|
100
|
+
- [dsh-web-app](../web-app/README.md) — the interactive browser sibling for multi-turn work.
|
|
101
|
+
- [dsh-cmdline](../../boot/cmdline/README.md) — how the launcher hands the command line to the app.
|
|
102
|
+
- [Generated configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-headless) — every accepted config field and its source declaration.
|
|
103
|
+
|
|
104
|
+
-----
|
|
105
|
+
|
|
106
|
+
<a id="model-experience"></a>
|
|
9
107
|
## Model Experience
|
|
10
108
|
|
|
11
|
-
None, as the runner submits the task as an ordinary user message
|
|
109
|
+
None, as the runner submits the task as an ordinary user message and the composed base and headless rows own the prompts and tools.
|
|
12
110
|
|
|
13
111
|
#### KV Cache effect
|
|
14
112
|
|
|
15
|
-
|
|
113
|
+
The runner adds nothing to the request prefix; it only drives one user message through the composed tree.
|
|
16
114
|
|
|
17
115
|
## Known Limitations and Deferred Work
|
|
18
116
|
|
|
19
|
-
|
|
20
|
-
|
|
117
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
These limits tell you when headless does not fit and what it needs from the `dsh` launcher. They are current package constraints, not a general CLI comparison or a task backlog.
|
|
121
|
+
|
|
122
|
+
- **One task per run** — after the task is answered the process exits; there is no interactive follow-up, so split multi-step work into separate runs.
|
|
123
|
+
- **Runs through the `dsh` launcher** — starting the headless profile another way fails at startup, because only the launcher can request the process exit.
|
|
124
|
+
- **No pre-token heartbeat** — stderr stays silent until the provider emits a non-empty reasoning delta; a delayed first token exposes no earlier progress signal.
|
|
125
|
+
- **Reasoning enters stderr logs** — redirection and supervisors may retain substantially more and potentially sensitive model output; route stderr to a controlled sink when needed.
|
|
126
|
+
- **Only reasoning and the final answer are printed** — a run without an assistant message prints an empty stdout line and exits 1; intermediate tool output is not printed.
|
|
127
|
+
|
|
128
|
+
<a id="dev-note"></a>
|
|
129
|
+
### Dev Note
|
|
130
|
+
|
|
131
|
+
<details>
|
|
132
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
133
|
+
|
|
134
|
+
None.
|
|
135
|
+
|
|
136
|
+
</details>
|
package/README.zh.md
CHANGED
|
@@ -1,20 +1,136 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
description: "dsh 的一次性任务模式:从命令行运行单个任务并打印最终答案,供用户脚本化或自动化 dsh。"
|
|
3
|
+
kind: "package-bundle"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @deepseek-ai/dsh-headless
|
|
2
7
|
|
|
3
8
|
[English](README.md) | 中文
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
`dsh-headless` 从命令行运行一个 dsh 任务并打印最终答案,然后退出——没有 GUI、没有服务器、没有浏览器。输入 `dsh --profile headless "run the tests"`,agent(智能体)会以与其他表层相同的模型、工具与安全默认值完成该任务。它非常适合脚本、CI 与一次性任务:进程不打开任何端口,也不会留下任何后台运行的东西。退出码告诉你结果——任务完成时为 0,中止或出错时为 1。主要边界:每次调用只运行一个任务,没有交互式后续。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [使用本包](#use-this-package)
|
|
17
|
+
- [理解实现](#understand-the-implementation)
|
|
18
|
+
- [进一步探索](#further-exploration)
|
|
19
|
+
- [模型体验](#model-experience)
|
|
20
|
+
- [已知限制与延期工作](#known-limitations-and-deferred-work)
|
|
21
|
+
- [开发备注](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## 使用本包
|
|
27
|
+
|
|
28
|
+
运行一个任务,获得最终答案,然后退出。任务就是命令行本身,因此整条命令就是最小的可运行示例。
|
|
29
|
+
|
|
30
|
+
### 运行一次性任务
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
dsh --profile headless "run the tests"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
agent(智能体)会完成该任务,把提供方的每个非空推理增量流式写入 stderr 的 `dsh: reasoning:` 段,然后把最终答案写入 stdout 并退出。连续推理增量保持在同一段中;提供方未给尾换行时,runner 会在后续输出前结束该段。没有推理内容的成功运行保持 stderr 为空;失败时退出码为 1,并以 `dsh: <code>: <message>` 向 stderr 写入错误。缺失或空白任务会在任何内容运行前被拒绝。任务文本通过唯一的 `task` 设置提供:
|
|
37
|
+
|
|
38
|
+
| 字段 | 默认值 | 含义 |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| `task` | 必填 | 单次运行的任务文本 |
|
|
41
|
+
|
|
42
|
+
生成的[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-headless)是每个受支持字段及其 JSDoc 的穷尽式真源。
|
|
43
|
+
|
|
44
|
+
### 何时使用
|
|
45
|
+
|
|
46
|
+
在脚本化或自动化的 dsh 运行中使用 headless——CI 步骤、批处理任务、从终端快速获取答案。当需要多轮交互会话或 GUI 时请避免它;浏览器表层([dsh-web-app](../web-app/README.zh.md))负责这类场景。进程只为本次运行而存活,不打开监听端口,并且自行退出,因此适合等待进程结束的流水线。
|
|
47
|
+
|
|
48
|
+
### 帮助与任务错误
|
|
49
|
+
|
|
50
|
+
`dsh --profile headless --help` 打印该命令的帮助文本并直接退出,不运行任何内容。缺失或只有空白的任务属于用法错误:什么都不运行,进程退出 1。
|
|
51
|
+
|
|
52
|
+
-----
|
|
53
|
+
|
|
54
|
+
<a id="understand-the-implementation"></a>
|
|
55
|
+
## 理解实现
|
|
56
|
+
|
|
57
|
+
<details>
|
|
58
|
+
<summary>实现细节——点击展开</summary>
|
|
59
|
+
|
|
60
|
+
runner 是核心 API 载体之上的直接驱动器:它通过注册表创建一个全新的 Agent(智能体),并把所属的持久化事件区间折叠成一个进程级结果。
|
|
61
|
+
|
|
62
|
+
### 运行流程
|
|
6
63
|
|
|
7
|
-
|
|
64
|
+
runner 等待整个应用结算(`ctx.get('loader')?.await()`),确保已组合的工具与适配器不会半挂载,读取共享的 [`agentDefaultModel`](../../core/agent-default-model/README.zh.md) 选择,用该 provider 与模型创建一个全新的持久化 Agent(智能体),并把任务作为普通用户消息提交。它把该 Agent 的非空推理增量流式写入 stderr、等待完全停稳,然后 flush Session,并把所属区间(从 `firstSeq` 起)折叠为最后一条非空 `assistant/message` 文本与最终 `turn/end` 原因。最后,它把最终文本写入 stdout 并请求退出。
|
|
8
65
|
|
|
66
|
+
### 叠加在 base 之上的 patch 表层
|
|
67
|
+
|
|
68
|
+
patch 叠加在 `dsh-base` 之上:继承投影缓存,在基础 `system-prompt` 行上设置编码 persona,保留与 Web 表层相同的临时进程级 PTC mode 开关(`DSH_TOOLS_MODE`),禁用共享的 HMR 行,把 PTC mode 的 worker 作为核心执行能力插入,并挂载启动提供方与 runner。缓存为每个已持久化的一次性会话写入检查点,供后续消费方使用;其持久性屏障会在发布缓存行前 flush 所覆盖的日志前缀,因此可能拆分原本会合并的 JSONL 行。启动提供方([`src/startup.ts`](src/startup.ts))注入 `ctx.cmdlineArgs`([`dsh-cmdline`](../../boot/cmdline/README.zh.md)),读取位置参数、打印应用自己的 `--help`,并提供 `headlessStartup`;runner 注入该服务,再从惰性配置中读取任务。
|
|
69
|
+
|
|
70
|
+
### 退出映射
|
|
71
|
+
|
|
72
|
+
最终 `turn/end` 完成时退出码为 0;任何其他结果——aborted、error,或所属区间内没有轮次——退出码为 1。结束原因为 `error` 时还会向 stderr 写入 `dsh: <code>: <message>`。直接驱动器失败(例如 Agent 创建失败)向 stderr 写入 `dsh: <message>` 并退出 1。
|
|
73
|
+
|
|
74
|
+
### 源码地图
|
|
75
|
+
|
|
76
|
+
| 文件 | 职责 |
|
|
77
|
+
|---|---|
|
|
78
|
+
| [`src/index.ts`](src/index.ts) | `headless-runner` 插件:运行流程、输出约定、退出映射 |
|
|
79
|
+
| [`src/startup.ts`](src/startup.ts) | `headless-startup` 提供方:任务位置参数与 `--help` |
|
|
80
|
+
| [`cordis.patch.yml`](cordis.patch.yml) | 叠加在 `dsh-base` 之上的一次性 patch |
|
|
81
|
+
| [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件:无运行时不变式;可观察约定是进程级的 |
|
|
82
|
+
| [`tests/headless.spec.ts`](tests/headless.spec.ts) | 运行流程、汇总、flush 与退出映射 |
|
|
83
|
+
| [`tests/startup.spec.ts`](tests/startup.spec.ts) | 在真实 Loader 树上的命令行解析 |
|
|
84
|
+
|
|
85
|
+
### 不变式归属
|
|
86
|
+
|
|
87
|
+
不变式伴生插件注册一个空安装器,因为 runner 的可观察约定(stdout 的最终文本、按轮次结束原因决定的退出码)是进程级的、由启动器 e2e 负责;插件不注册任何内容,树内也没有任何可变关系可审计。
|
|
88
|
+
|
|
89
|
+
</details>
|
|
90
|
+
|
|
91
|
+
-----
|
|
92
|
+
|
|
93
|
+
<a id="further-exploration"></a>
|
|
94
|
+
## 进一步探索
|
|
95
|
+
|
|
96
|
+
当你想深入了解共享核心、兄弟 GUI 或命令行交接时,阅读以下页面。
|
|
97
|
+
|
|
98
|
+
- [组合包包映射](../README.zh.md)——基于同一核心构建的表层。
|
|
99
|
+
- [dsh-base](../base/README.zh.md)——headless 运行其上的共享核心。
|
|
100
|
+
- [dsh-web-app](../web-app/README.zh.md)——用于多轮工作的交互式浏览器兄弟表层。
|
|
101
|
+
- [dsh-cmdline](../../boot/cmdline/README.zh.md)——启动器如何把命令行交给应用。
|
|
102
|
+
- [生成配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-headless)——每个受支持配置字段及其源声明。
|
|
103
|
+
|
|
104
|
+
-----
|
|
105
|
+
|
|
106
|
+
<a id="model-experience"></a>
|
|
9
107
|
## 模型体验
|
|
10
108
|
|
|
11
|
-
|
|
109
|
+
无,因为 runner 把任务作为普通用户消息提交,提示词与工具由组合出的 base 与 headless 行提供。
|
|
12
110
|
|
|
13
111
|
#### KV Cache 影响
|
|
14
112
|
|
|
15
|
-
|
|
113
|
+
runner 不向请求前缀添加任何内容;它只是把一条用户消息驱动经过组合出的配置树。
|
|
114
|
+
|
|
115
|
+
## 已知限制与延期工作
|
|
116
|
+
|
|
117
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
这些限制告诉你 headless 何时不适用、它需要 `dsh` 启动器提供什么。它们是当前包约束,不是通用的 CLI 对比或任务积压。
|
|
121
|
+
|
|
122
|
+
- **每次运行一个任务**——任务得到回答后进程即退出;没有交互式后续,因此多步工作请拆成多次运行。
|
|
123
|
+
- **通过 `dsh` 启动器运行**——以其他方式启动 headless profile 会在启动时失败,因为只有启动器能请求进程退出。
|
|
124
|
+
- **首个 token 前没有心跳**——提供方发出第一个非空推理增量前,stderr 保持静默;延迟首个 token 的提供方不会更早给出进度信号。
|
|
125
|
+
- **推理进入 stderr 日志**——重定向与监督进程可能保留更多且可能敏感的模型输出;需要时应把 stderr 路由到受控位置。
|
|
126
|
+
- **只打印推理和最终答案**——没有 assistant 消息的运行向 stdout 打印空行并以 1 退出;中间工具输出不会打印。
|
|
127
|
+
|
|
128
|
+
<a id="dev-note"></a>
|
|
129
|
+
### 开发备注
|
|
130
|
+
|
|
131
|
+
<details>
|
|
132
|
+
<summary>维护者的工作上下文——点击展开</summary>
|
|
16
133
|
|
|
17
|
-
|
|
134
|
+
无。
|
|
18
135
|
|
|
19
|
-
|
|
20
|
-
- **`ctx.appExit` 由启动器持有**:在 `dsh` 启动器之外启动 headless profile 会在激活时明确报错,直到宿主提供该退出请求。
|
|
136
|
+
</details>
|
package/cordis.patch.yml
CHANGED
|
@@ -9,18 +9,13 @@
|
|
|
9
9
|
persona: >-
|
|
10
10
|
You are a coding agent powered by the {{model}} model. Your working directory is {{cwd}}.
|
|
11
11
|
|
|
12
|
-
# The shared module-reload HMR row stays off; the launcher's watch-only
|
|
13
|
-
# fallback still keeps the user patch layers live until the run exits.
|
|
14
|
-
- id: hmr
|
|
15
|
-
disabled: true
|
|
16
|
-
|
|
17
12
|
- id: tools
|
|
18
13
|
config:
|
|
19
|
-
# Keep the same temporary process-wide
|
|
14
|
+
# Keep the same temporary process-wide PTC mode opt-in as the Web surface.
|
|
20
15
|
mode: !!js process.env.DSH_TOOLS_MODE
|
|
21
16
|
|
|
22
17
|
- insert:
|
|
23
|
-
#
|
|
18
|
+
# PTC mode is a core execution capability, not a Web component.
|
|
24
19
|
- id: code-runtime
|
|
25
20
|
name: '@deepseek-ai/dsh-code-runtime-worker-thread'
|
|
26
21
|
|
package/lib/index.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
|
+
import { brandString } from "@deepseek-ai/dsh-brand";
|
|
3
4
|
import { installModelSelection } from "@deepseek-ai/dsh-agent";
|
|
4
5
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
5
|
-
import {
|
|
6
|
+
import { assertNever } from "@deepseek-ai/dsh-util-values";
|
|
6
7
|
//#region lib/types/index.js
|
|
7
8
|
/**
|
|
8
9
|
* @deepseek-ai/dsh-headless — one-shot direct Agent driver. The bundle patch
|
|
9
10
|
* rides over dsh-base without Host, HTTP, or browser plugins; this runner
|
|
10
11
|
* creates one Agent through the core registry, drives the task to quiescence,
|
|
11
|
-
* flushes its Session, prints the final
|
|
12
|
+
* streams provider reasoning to stderr, flushes its Session, prints the final
|
|
13
|
+
* assistant text to stdout, and exits.
|
|
12
14
|
*
|
|
13
15
|
* @module @deepseek-ai/dsh-headless
|
|
14
16
|
*/
|
|
@@ -49,6 +51,64 @@ function summarize(events, firstSeq) {
|
|
|
49
51
|
reason
|
|
50
52
|
};
|
|
51
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Project provider-reported reasoning from one owned run to stderr as it is
|
|
56
|
+
* appended, while keeping final outcome derivation on the durable log.
|
|
57
|
+
* @param ctx - plugin context carrying the Session event feed.
|
|
58
|
+
* @param agent - the exact Agent whose reasoning belongs to this invocation.
|
|
59
|
+
* @param stderr - progress output sink.
|
|
60
|
+
* @returns a disposer that also terminates an unterminated reasoning line.
|
|
61
|
+
*/
|
|
62
|
+
function streamReasoning(ctx, agent, stderr) {
|
|
63
|
+
let started = false;
|
|
64
|
+
let open = false;
|
|
65
|
+
let endsWithNewline = true;
|
|
66
|
+
const close = () => {
|
|
67
|
+
if (!open) return;
|
|
68
|
+
if (!endsWithNewline) stderr.write("\n");
|
|
69
|
+
open = false;
|
|
70
|
+
endsWithNewline = true;
|
|
71
|
+
};
|
|
72
|
+
const dispose = ctx.on("session/event", (session, event) => {
|
|
73
|
+
if (session !== agent.session) return;
|
|
74
|
+
if (event.type === "turn/start") {
|
|
75
|
+
close();
|
|
76
|
+
started = true;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (!started || event.type !== "assistant/chunk") return;
|
|
80
|
+
const chunk = event.data.chunk;
|
|
81
|
+
switch (chunk.type) {
|
|
82
|
+
case "reasoning-delta":
|
|
83
|
+
if (chunk.text === "") return;
|
|
84
|
+
if (!open) {
|
|
85
|
+
stderr.write("dsh: reasoning:\n");
|
|
86
|
+
open = true;
|
|
87
|
+
}
|
|
88
|
+
stderr.write(chunk.text);
|
|
89
|
+
endsWithNewline = chunk.text.endsWith("\n");
|
|
90
|
+
return;
|
|
91
|
+
case "block-start":
|
|
92
|
+
if (chunk.blockType !== "reasoning") close();
|
|
93
|
+
return;
|
|
94
|
+
case "block-end":
|
|
95
|
+
if (chunk.block.type !== "reasoning") close();
|
|
96
|
+
return;
|
|
97
|
+
case "usage": return;
|
|
98
|
+
case "text-delta":
|
|
99
|
+
case "tool-call-delta":
|
|
100
|
+
case "finish":
|
|
101
|
+
close();
|
|
102
|
+
return;
|
|
103
|
+
/* v8 ignore next -- closed-union exhaustiveness guard */
|
|
104
|
+
default: return assertNever(chunk, "headless reasoning stream");
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
return () => {
|
|
108
|
+
dispose();
|
|
109
|
+
close();
|
|
110
|
+
};
|
|
111
|
+
}
|
|
52
112
|
/** Report an unexpected direct-driver failure and request a failing exit. */
|
|
53
113
|
function fail(io, error) {
|
|
54
114
|
io.stderr.write(`dsh: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
@@ -68,7 +128,7 @@ async function run(ctx, task, io) {
|
|
|
68
128
|
if (agents === void 0 || defaultModel === void 0 || sessions === void 0) return;
|
|
69
129
|
const selection = defaultModel.currentSelection();
|
|
70
130
|
const { agent } = await agents.create({
|
|
71
|
-
sessionId:
|
|
131
|
+
sessionId: brandString(`session-${randomUUID()}`),
|
|
72
132
|
meta: { cwd: process.cwd() },
|
|
73
133
|
agentOptions: {
|
|
74
134
|
provider: selection.provider,
|
|
@@ -83,14 +143,19 @@ async function run(ctx, task, io) {
|
|
|
83
143
|
});
|
|
84
144
|
await agent.whenIdle();
|
|
85
145
|
const firstSeq = agent.session.seq;
|
|
86
|
-
agent.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
146
|
+
const stopReasoning = streamReasoning(ctx, agent, io.stderr);
|
|
147
|
+
try {
|
|
148
|
+
agent.followup(createUserMessage({
|
|
149
|
+
content: [{
|
|
150
|
+
type: "text",
|
|
151
|
+
text: task
|
|
152
|
+
}],
|
|
153
|
+
source: { kind: "user" }
|
|
154
|
+
}));
|
|
155
|
+
await agent.whenIdle();
|
|
156
|
+
} finally {
|
|
157
|
+
stopReasoning();
|
|
158
|
+
}
|
|
94
159
|
await sessions.flush(agent.session);
|
|
95
160
|
const outcome = summarize(agent.session.events, firstSeq);
|
|
96
161
|
io.stdout.write(outcome.text + "\n");
|
package/lib/invariant.js
CHANGED
|
@@ -9,10 +9,10 @@ const name = "headless-invariant";
|
|
|
9
9
|
/** Service required before the companion can register. */
|
|
10
10
|
const inject = ["invariants"];
|
|
11
11
|
/**
|
|
12
|
-
* No runtime invariant: the runner
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* No runtime invariant: the runner's observable contract (provider reasoning
|
|
13
|
+
* on stderr, final text on stdout, exit code by turn-end reason) is
|
|
14
|
+
* process-level and owned by the launcher e2e; it registers nothing and holds
|
|
15
|
+
* no mutable relation to audit inside the tree.
|
|
16
16
|
*/
|
|
17
17
|
const install = () => {};
|
|
18
18
|
/**
|
package/lib/startup.js
CHANGED
|
@@ -18,7 +18,7 @@ const HEADLESS_STARTUP_SERVICE = "headlessStartup";
|
|
|
18
18
|
* @returns a fresh program, so one process can parse more than once (tests).
|
|
19
19
|
*/
|
|
20
20
|
function headlessCommand() {
|
|
21
|
-
return new Command().name("dsh --profile headless").description("Answer one task, print the final assistant message, and exit.").helpOption("-h, --help", "show this help").argument("[task...]", "the task text; multiple words are joined by spaces").addHelpText("after", `
|
|
21
|
+
return new Command().name("dsh --profile headless").description("Answer one task, stream reasoning to stderr, print the final assistant message, and exit.").helpOption("-h, --help", "show this help").argument("[task...]", "the task text; multiple words are joined by spaces").addHelpText("after", `
|
|
22
22
|
Examples:
|
|
23
23
|
dsh --profile headless "run the tests" answer one task and exit
|
|
24
24
|
`);
|
package/lib/types/index.d.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* @deepseek-ai/dsh-headless — one-shot direct Agent driver. The bundle patch
|
|
3
3
|
* rides over dsh-base without Host, HTTP, or browser plugins; this runner
|
|
4
4
|
* creates one Agent through the core registry, drives the task to quiescence,
|
|
5
|
-
* flushes its Session, prints the final
|
|
5
|
+
* streams provider reasoning to stderr, flushes its Session, prints the final
|
|
6
|
+
* assistant text to stdout, and exits.
|
|
6
7
|
*
|
|
7
8
|
* @module @deepseek-ai/dsh-headless
|
|
8
9
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-headless",
|
|
3
3
|
"description": "The dsh one-shot bundle: a direct core Agent/Session runner over dsh-base with no Host, HTTP, or browser layer",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.2-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -45,26 +45,28 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"commander": "^15.0.0",
|
|
48
|
-
"@deepseek-ai/dsh-
|
|
49
|
-
"@deepseek-ai/dsh-cmdline": "^0.1.
|
|
50
|
-
"@deepseek-ai/
|
|
48
|
+
"@deepseek-ai/dsh-brand": "^0.1.2-alpha.2",
|
|
49
|
+
"@deepseek-ai/dsh-cmdline": "^0.1.2-alpha.2",
|
|
50
|
+
"@deepseek-ai/dsh-code-runtime-worker-thread": "^0.1.2-alpha.2",
|
|
51
|
+
"@deepseek-ai/dsh-util-values": "^0.1.2-alpha.2",
|
|
52
|
+
"@deepseek-ai/schemastery": "^3.18.2"
|
|
51
53
|
},
|
|
52
54
|
"peerDependencies": {
|
|
53
|
-
"@deepseek-ai/cordis-plugin-loader": "^1.0.
|
|
54
|
-
"@deepseek-ai/dsh-agent": "^0.1.
|
|
55
|
-
"@deepseek-ai/dsh-
|
|
56
|
-
"@deepseek-ai/dsh-
|
|
57
|
-
"@deepseek-ai/dsh-
|
|
58
|
-
"@deepseek-ai/
|
|
59
|
-
"@deepseek-ai/
|
|
55
|
+
"@deepseek-ai/cordis-plugin-loader": "^1.0.3",
|
|
56
|
+
"@deepseek-ai/dsh-agent-default-model": "^0.1.2-alpha.2",
|
|
57
|
+
"@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2",
|
|
58
|
+
"@deepseek-ai/dsh-llm": "^0.1.2-alpha.2",
|
|
59
|
+
"@deepseek-ai/dsh-session": "^0.1.2-alpha.2",
|
|
60
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
61
|
+
"@deepseek-ai/dsh-agent": "^0.1.2-alpha.2"
|
|
60
62
|
},
|
|
61
63
|
"devDependencies": {
|
|
62
|
-
"@deepseek-ai/cordis
|
|
63
|
-
"@deepseek-ai/
|
|
64
|
-
"@deepseek-ai/dsh-
|
|
65
|
-
"@deepseek-ai/dsh-
|
|
66
|
-
"@deepseek-ai/dsh-
|
|
67
|
-
"@deepseek-ai/
|
|
68
|
-
"@deepseek-ai/dsh-agent": "^0.1.
|
|
64
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
65
|
+
"@deepseek-ai/cordis-plugin-loader": "^1.0.3",
|
|
66
|
+
"@deepseek-ai/dsh-agent-default-model": "^0.1.2-alpha.2",
|
|
67
|
+
"@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2",
|
|
68
|
+
"@deepseek-ai/dsh-llm": "^0.1.2-alpha.2",
|
|
69
|
+
"@deepseek-ai/dsh-session": "^0.1.2-alpha.2",
|
|
70
|
+
"@deepseek-ai/dsh-agent": "^0.1.2-alpha.2"
|
|
69
71
|
}
|
|
70
72
|
}
|