@deepseek-ai/dsh-tool-workflow 0.0.1-rc.1
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/LICENSE +28 -0
- package/README.i18n.yaml +6 -0
- package/README.md +80 -0
- package/README.zh.md +80 -0
- package/lib/index.js +199 -0
- package/lib/invariant.js +23 -0
- package/lib/types/index.d.ts +25 -0
- package/lib/types/invariant.d.ts +16 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, DeepSeek
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/workflow/tool-workflow/README.md
|
|
5
|
+
README.md: 29896bee0f78a1d1764c3908965325fcecbf7b53
|
|
6
|
+
README.zh.md: 12e1ecd8932120c74384a289530954422ba145f2
|
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# @deepseek-ai/dsh-tool-workflow
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
The model-facing **`workflow` tool**: run a JavaScript orchestration script that fans out subagents, and return the script's final value. This package owns the model-facing schema and run lifecycle over [`ctx.workflows`](../workflow/README.md); script parsing, execution, caps, and cancellation live behind the seam, while the consumer retains ownership of the parent-facing schema and result envelope.
|
|
6
|
+
|
|
7
|
+
## What the model sees
|
|
8
|
+
|
|
9
|
+
Three parameters: `meta` (required identity data: `name`, `description`, and optional progress annotations), `script` (required plain JavaScript body — no `export const meta` statement; the tool description carries the complete authoring contract), and `args` (optional JSON object exposed to the script as the `args` global; wrap a bare list in a field so the wire schema stays honest). The plugin also contributes a `tool:<toolName>` system-prompt section carrying the usage policy — use the tool only on an explicit user ask for a workflow / large orchestration; prefer plain subagent calls for one or two delegations — per the convention that tool guidance ships with the tool plugin, never in the deployment persona.
|
|
10
|
+
|
|
11
|
+
## Lifecycle
|
|
12
|
+
|
|
13
|
+
Collection is synchronous (like [`dsh-tool-subagent`](../../subagent/tool-subagent/README.md)): `execute` starts a run and awaits `run.result` inside a `try/finally` that always disposes the run, so the script and its children reach quiescence on every path. `exec.signal` is bridged to `run.cancel()` (including the already-aborted-before-start case). A non-`completed` stop reason maps to an `isError` result reporting the reason—never partial output as success; a parse/meta failure thrown synchronously by `start()` becomes an `isError` the model can correct from. Completion returns canonical `{ runId, agentsStarted, result }`; the Native renderer preserves the meta name, agent count, and JSON value, truncating only that projection at `maxResultChars`.
|
|
14
|
+
|
|
15
|
+
## Render intent
|
|
16
|
+
|
|
17
|
+
Decided up front (per the [render-intent Agent Note](../../../.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md)): a `generic` card titled `workflow: <meta.name>`, read directly from `args.meta.name` (presentation is a pure function of args and does not ask the engine to parse); the script text rides as `rawInput`. The result keeps the generic card.
|
|
18
|
+
|
|
19
|
+
## Config
|
|
20
|
+
|
|
21
|
+
| Key | Default | Meaning |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `toolName` | `workflow` | The model-facing tool name to register. |
|
|
24
|
+
| `maxResultChars` | `50000` | Rendered-result ceiling; longer JSON is truncated with a notice. |
|
|
25
|
+
|
|
26
|
+
## Model Experience
|
|
27
|
+
|
|
28
|
+
### System prompt
|
|
29
|
+
|
|
30
|
+
#### What the model sees
|
|
31
|
+
|
|
32
|
+
Every parent request in this plugin's registration scope receives the workflow guidance below. A scoped tool restriction can hide the schema without removing this independently registered guidance.
|
|
33
|
+
|
|
34
|
+
##### Workflow guidance
|
|
35
|
+
|
|
36
|
+
```markdown
|
|
37
|
+
Use the <toolName> tool ONLY when the user explicitly asks for a workflow or for large multi-agent orchestration: you write a JavaScript script (the tool description documents the exact format) that fans work out across many subagents with phases and structured results. For one or two delegations, prefer plain subagent calls.
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### Token effect
|
|
41
|
+
|
|
42
|
+
Small fixed guidance cost per request while the plugin is active.
|
|
43
|
+
|
|
44
|
+
#### KV Cache effect
|
|
45
|
+
|
|
46
|
+
Prefix-stable while the plugin scope and guidance text are unchanged. Activation or disposal may invalidate reuse from this prompt section.
|
|
47
|
+
|
|
48
|
+
### Tool schema
|
|
49
|
+
|
|
50
|
+
#### What the model sees
|
|
51
|
+
|
|
52
|
+
When visible, the generated default [`workflow` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tool-workflow) carries the complete JavaScript hook and metadata contract; `toolName` can rename the definition, and the model submits script, metadata, and optional args.
|
|
53
|
+
|
|
54
|
+
#### Token effect
|
|
55
|
+
|
|
56
|
+
Substantial fixed schema cost on each request where the tool is visible.
|
|
57
|
+
|
|
58
|
+
#### KV Cache effect
|
|
59
|
+
|
|
60
|
+
Prefix-stable while `toolName`, definition, and visibility are unchanged. Renaming, plugin lifecycle, or scoped restrictions may invalidate reuse from this schema.
|
|
61
|
+
|
|
62
|
+
### Tool-call history and result
|
|
63
|
+
|
|
64
|
+
#### What the model sees
|
|
65
|
+
|
|
66
|
+
The full model-written script, metadata, and args remain in the assistant tool call. Success is exactly `workflow "<name>" completed (<count> agent<optional-s>).`, newline, `Return value:`, newline, and pretty-printed data-dependent JSON; a cap adds `… [truncated: <omitted> more characters]` on a new line. Failures are exactly `Error: workflow run was cancelled`, optionally suffixed ` (<error>)`, `Error: workflow run failed: <error-or-unknown error>`, or defensively `Error: workflow run ended abnormally (<reason>)`; a call without an owning agent becomes `Error: workflow tool requires a calling agent (exec.agent was undefined)`. Intermediate child messages are omitted.
|
|
67
|
+
|
|
68
|
+
#### Token effect
|
|
69
|
+
|
|
70
|
+
Call tokens can be large and remain until compaction. Result rendering is capped by `maxResultChars`; child-model tokens are separate from the parent's retained context.
|
|
71
|
+
|
|
72
|
+
#### KV Cache effect
|
|
73
|
+
|
|
74
|
+
Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.
|
|
75
|
+
|
|
76
|
+
## Known Limitations and Deferred Work
|
|
77
|
+
|
|
78
|
+
- **The parent turn blocks until the whole workflow settles** — there is no background start/poll surface, and cancellation discards partial output as an error.
|
|
79
|
+
- **`args` must be an object and Native result text is bounded** — callers wrap top-level arrays/scalars in a field; the canonical workflow result remains complete, while JSON beyond `maxResultChars` is truncated in the model-facing projection rather than stored behind a retrieval handle.
|
|
80
|
+
- **Workflow policy is fixed per tool registration** — provider selection, caps, and tool name are deployment config, not model-call arguments.
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# @deepseek-ai/dsh-tool-workflow
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
面向模型的 **`workflow` 工具**:运行一段扇出 subagent 的 JavaScript 编排脚本,并返回脚本的最终值。本包负责基于 [`ctx.workflows`](../workflow/README.md) 定义面向模型的 schema 和运行生命周期;脚本解析、执行、上限与取消位于 seam 之后,消费方仍负责面向父级的 schema 和结果包络。
|
|
6
|
+
|
|
7
|
+
## 模型看到的内容
|
|
8
|
+
|
|
9
|
+
工具有三个参数:`meta`(必需的身份数据:`name`、`description` 和可选的进度注解)、`script`(必需的纯 JavaScript 脚本体,不含 `export const meta` 语句;工具描述包含完整的编写约定)以及 `args`(可选 JSON 对象,作为全局变量 `args` 向脚本公开;裸列表应包装到字段中,使协议 schema 如实表达形态)。插件还会贡献一个 `tool:<toolName>` 系统提示词段,其中包含使用策略:只有用户明确要求工作流/大型编排时才使用该工具;一两项委派优先使用普通 subagent 调用。这遵循工具指导随工具插件交付、绝不放入部署 persona 的约定。
|
|
10
|
+
|
|
11
|
+
## 生命周期
|
|
12
|
+
|
|
13
|
+
收集是同步的(类似 [`dsh-tool-subagent`](../../subagent/tool-subagent/README.md)):`execute` 启动运行并等待 `run.result`;这些操作位于 `try/finally` 中,该结构总会 dispose(资源释放)运行,使脚本及其子 agent(智能体)在每条路径上完全停稳。`exec.signal` 会桥接到 `run.cancel()`,包括启动前已经中止的情况。非 `completed` 结束原因会映射为报告原因的 `isError` 结果,绝不会把局部输出当作成功;`start()` 同步抛出的解析/meta 失败会变成模型可据以修正的 `isError`。完成时返回规范值 `{ runId, agentsStarted, result }`;Native 渲染器保留 meta 名称、agent 数量和 JSON 值,只会在 `maxResultChars` 处截断该投影。
|
|
14
|
+
|
|
15
|
+
## 渲染意图
|
|
16
|
+
|
|
17
|
+
渲染意图预先确定(见[渲染意图 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md)):使用一个 `generic` 卡片,标题为 `workflow: <meta.name>`,直接从 `args.meta.name` 读取(呈现是参数的纯函数,不要求引擎解析);脚本文本作为 `rawInput` 携带。结果继续使用 generic 卡片。
|
|
18
|
+
|
|
19
|
+
## 配置
|
|
20
|
+
|
|
21
|
+
| 键 | 默认值 | 含义 |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `toolName` | `workflow` | 要注册的面向模型工具名称。 |
|
|
24
|
+
| `maxResultChars` | `50000` | 渲染结果上限;更长的 JSON 会被截断并附上提示。 |
|
|
25
|
+
|
|
26
|
+
## 模型体验
|
|
27
|
+
|
|
28
|
+
### 系统提示词
|
|
29
|
+
|
|
30
|
+
#### 模型看到的内容
|
|
31
|
+
|
|
32
|
+
在该插件的注册作用域内,每个父级请求都会收到下方的工作流指导。作用域工具限制可以隐藏 schema,而不移除这段独立注册的指导。
|
|
33
|
+
|
|
34
|
+
##### 工作流指导
|
|
35
|
+
|
|
36
|
+
```markdown
|
|
37
|
+
Use the <toolName> tool ONLY when the user explicitly asks for a workflow or for large multi-agent orchestration: you write a JavaScript script (the tool description documents the exact format) that fans work out across many subagents with phases and structured results. For one or two delegations, prefer plain subagent calls.
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### Token 影响
|
|
41
|
+
|
|
42
|
+
插件启用期间,每个请求都会产生少量固定的指导 token 开销。
|
|
43
|
+
|
|
44
|
+
#### KV Cache 影响
|
|
45
|
+
|
|
46
|
+
只要插件作用域和指导文本不变,前缀就保持稳定。启用或 dispose 可能会使从该提示词段起的缓存复用失效。
|
|
47
|
+
|
|
48
|
+
### 工具 schema
|
|
49
|
+
|
|
50
|
+
#### 模型看到的内容
|
|
51
|
+
|
|
52
|
+
工具可见时,已生成的默认 [`workflow` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tool-workflow) 包含完整的 JavaScript 钩子与元数据约定;`toolName` 可以重命名该定义,模型会提交脚本、元数据和可选 args。
|
|
53
|
+
|
|
54
|
+
#### Token 影响
|
|
55
|
+
|
|
56
|
+
工具可见时,每个请求都会产生较大的固定 schema token 开销。
|
|
57
|
+
|
|
58
|
+
#### KV Cache 影响
|
|
59
|
+
|
|
60
|
+
只要 `toolName`、定义和可见性不变,前缀就保持稳定。重命名、插件生命周期或作用域限制可能会使从该 schema 起的缓存复用失效。
|
|
61
|
+
|
|
62
|
+
### 工具调用历史与结果
|
|
63
|
+
|
|
64
|
+
#### 模型看到的内容
|
|
65
|
+
|
|
66
|
+
由模型编写的完整脚本、元数据和 args 会保留在 assistant 工具调用中。成功结果精确为 `workflow "<name>" completed (<count> agent<optional-s>).`、换行、`Return value:`、换行,以及经过美化打印且依赖数据的 JSON;达到上限时,会在新行添加 `… [truncated: <omitted> more characters]`。失败结果精确为 `Error: workflow run was cancelled`(可以追加后缀 ` (<error>)`)、`Error: workflow run failed: <error-or-unknown error>` 或防御性的 `Error: workflow run ended abnormally (<reason>)`;没有所属 agent 的调用变为 `Error: workflow tool requires a calling agent (exec.agent was undefined)`。中间子 agent 消息会被省略。
|
|
67
|
+
|
|
68
|
+
#### Token 影响
|
|
69
|
+
|
|
70
|
+
调用 token 可能很多,并会保留到压缩(compaction)为止。结果渲染受 `maxResultChars` 限制;子模型 token 与父级保留的上下文相互独立。
|
|
71
|
+
|
|
72
|
+
#### KV Cache 影响
|
|
73
|
+
|
|
74
|
+
仅追加;新增可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
|
|
75
|
+
|
|
76
|
+
## 已知限制与暂缓事项
|
|
77
|
+
|
|
78
|
+
- **父级轮次会阻塞到整个工作流结算**:没有后台启动/轮询接口,取消会把局部输出作为错误丢弃。
|
|
79
|
+
- **`args` 必须是对象,Native 结果文本有界**:调用方把顶层数组/标量包装到字段中;规范工作流结果保持完整,超过 `maxResultChars` 的 JSON 会在面向模型的投影中截断,而不是存储在检索句柄背后。
|
|
80
|
+
- **每次工具注册的工作流策略固定**:提供方选择、上限和工具名称属于部署配置,不是模型调用参数。
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import z from "@deepseek-ai/schemastery";
|
|
2
|
+
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
3
|
+
//#region lib/types/index.js
|
|
4
|
+
/**
|
|
5
|
+
* The model-facing `workflow` tool: run a JavaScript orchestration script that fans out
|
|
6
|
+
* subagents, and return the script's final value. It owns the model-facing schema and run lifecycle; script
|
|
7
|
+
* parsing, execution, caps, and cancellation live behind `ctx.workflows`
|
|
8
|
+
* (`@deepseek-ai/dsh-workflow`), so a hardened engine swaps in without touching what the model
|
|
9
|
+
* sees. Execution awaits `run.result` and always disposes the run; non-completed reasons become tool
|
|
10
|
+
* errors, and background collection remains deferred. Presentation is an args-only generic card
|
|
11
|
+
* titled from `meta.name`. Explicit-ask usage guidance is registered as the tool's own prompt
|
|
12
|
+
* section rather than deployment persona prose.
|
|
13
|
+
* @module @deepseek-ai/dsh-tool-workflow
|
|
14
|
+
*/
|
|
15
|
+
const name = "tool-workflow";
|
|
16
|
+
const inject = [
|
|
17
|
+
"tools",
|
|
18
|
+
"workflows",
|
|
19
|
+
"systemPrompt"
|
|
20
|
+
];
|
|
21
|
+
const Config = z.object({
|
|
22
|
+
toolName: z.string().default("workflow"),
|
|
23
|
+
maxResultChars: z.natural().min(1).default(5e4)
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* The script-authoring contract, embedded in the tool description. This IS the
|
|
27
|
+
* model-facing spec: the meta block, the hooks and their exact semantics, and
|
|
28
|
+
* the supported schema subset.
|
|
29
|
+
*/
|
|
30
|
+
const DESCRIPTION = `Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.
|
|
31
|
+
|
|
32
|
+
The workflow's identity rides the \`meta\` parameter as JSON: required \`name\` (short kebab-case) and \`description\` strings, optional \`whenToUse\` string and \`phases\` array (\`{title, detail?, provider?, model?}\`). The \`script\` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO \`export const meta\` statement — meta is a parameter, not code), running with top-level await; end with \`return <value>\` — the value must be JSON-serializable and is this tool's result.
|
|
33
|
+
|
|
34
|
+
Script-body hooks:
|
|
35
|
+
- \`agent(prompt, opts?): Promise<any>\` — run one subagent to completion. Without \`opts.schema\` it resolves to the child's final text; with \`opts.schema\` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves \`null\` when the child fails (filter with \`.filter(Boolean)\`). Other opts: \`label\` (display), \`phase\` (progress group), and independent \`provider\`/\`model\` LLM target overrides (either may be provided alone). Anything else (\`effort\`/\`isolation\`/\`agentType\`) is rejected loudly.
|
|
36
|
+
- \`pipeline(items, ...stages): Promise<any[]>\` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives \`(prev, item, index)\`. An ordinary stage throw drops that ITEM to \`null\` and skips its remaining stages.
|
|
37
|
+
- \`parallel(thunks): Promise<any[]>\` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to \`null\`.
|
|
38
|
+
- \`phase(title)\` — start a progress phase; \`log(message)\` — narrate progress; \`args\` — the tool call's \`args\` input, verbatim.
|
|
39
|
+
|
|
40
|
+
Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item \`null\`.
|
|
41
|
+
|
|
42
|
+
Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.`;
|
|
43
|
+
/** The pending-state card: a generic card titled by the workflow's meta name. */
|
|
44
|
+
function presentWorkflowCall(args) {
|
|
45
|
+
return {
|
|
46
|
+
card: "generic",
|
|
47
|
+
title: `workflow: ${args.meta.name}`,
|
|
48
|
+
rawInput: args.script
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/** The completed-state card: keep the pending title; render the result content as-is. */
|
|
52
|
+
function presentWorkflowResult(args, result) {
|
|
53
|
+
return { card: "generic" };
|
|
54
|
+
}
|
|
55
|
+
/** A non-`completed` stop reason means the script did not finish cleanly. */
|
|
56
|
+
function stopReasonError(result) {
|
|
57
|
+
switch (result.stopReason) {
|
|
58
|
+
case "completed": return;
|
|
59
|
+
case "cancelled": return `workflow run was cancelled${result.error !== void 0 ? ` (${result.error})` : ""}`;
|
|
60
|
+
case "error": return `workflow run failed: ${result.error ?? "unknown error"}`;
|
|
61
|
+
/* v8 ignore start -- defensive: WorkflowStopReason is a closed union, exhaustive by construction; a future variant fails here loudly */
|
|
62
|
+
default: return `workflow run ended abnormally (${String(result.stopReason)})`;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Render the run's outcome text: the meta name, agent count, and the JSON value (capped). */
|
|
66
|
+
function renderResult(name, agentsStarted, value, maxChars) {
|
|
67
|
+
const rendered = JSON.stringify(value, null, 2);
|
|
68
|
+
const clipped = rendered.length > maxChars ? `${rendered.slice(0, maxChars)}\n… [truncated: ${rendered.length - maxChars} more characters]` : rendered;
|
|
69
|
+
return `workflow "${name}" completed (${agentsStarted} agent${agentsStarted === 1 ? "" : "s"}).\nReturn value:\n${clipped}`;
|
|
70
|
+
}
|
|
71
|
+
function apply(ctx, config) {
|
|
72
|
+
const { toolName, maxResultChars } = config;
|
|
73
|
+
ctx.systemPrompt.section({
|
|
74
|
+
name: `tool:${toolName}`,
|
|
75
|
+
order: 115,
|
|
76
|
+
text: `Use the ${toolName} tool ONLY when the user explicitly asks for a workflow or for large multi-agent orchestration: you write a JavaScript script (the tool description documents the exact format) that fans work out across many subagents with phases and structured results. For one or two delegations, prefer plain subagent calls.`
|
|
77
|
+
});
|
|
78
|
+
ctx.tools.register(defineTool({
|
|
79
|
+
name: toolName,
|
|
80
|
+
description: DESCRIPTION,
|
|
81
|
+
parameters: {
|
|
82
|
+
script: {
|
|
83
|
+
type: "string",
|
|
84
|
+
required: true,
|
|
85
|
+
description: "The plain-JS workflow script body (top-level await allowed; NO `export const meta` statement; end with `return <json-value>`)."
|
|
86
|
+
},
|
|
87
|
+
meta: {
|
|
88
|
+
type: "object",
|
|
89
|
+
additionalProperties: true,
|
|
90
|
+
required: true,
|
|
91
|
+
description: "The workflow identity block (plain JSON — never code).",
|
|
92
|
+
properties: {
|
|
93
|
+
name: {
|
|
94
|
+
type: "string",
|
|
95
|
+
required: true,
|
|
96
|
+
description: "Short kebab-case workflow name."
|
|
97
|
+
},
|
|
98
|
+
description: {
|
|
99
|
+
type: "string",
|
|
100
|
+
required: true,
|
|
101
|
+
description: "One-line description of what the workflow does."
|
|
102
|
+
},
|
|
103
|
+
whenToUse: {
|
|
104
|
+
type: "string",
|
|
105
|
+
description: "Optional guidance on when this workflow applies."
|
|
106
|
+
},
|
|
107
|
+
phases: {
|
|
108
|
+
type: "array",
|
|
109
|
+
description: "Optional phase declarations matched by phase() calls.",
|
|
110
|
+
items: {
|
|
111
|
+
type: "object",
|
|
112
|
+
additionalProperties: true,
|
|
113
|
+
properties: {
|
|
114
|
+
title: {
|
|
115
|
+
type: "string",
|
|
116
|
+
required: true,
|
|
117
|
+
description: "The phase title phase() calls match by exact string."
|
|
118
|
+
},
|
|
119
|
+
detail: {
|
|
120
|
+
type: "string",
|
|
121
|
+
description: "Optional one-line description of the phase."
|
|
122
|
+
},
|
|
123
|
+
provider: {
|
|
124
|
+
type: "string",
|
|
125
|
+
description: "Optional provider override this phase is expected to use."
|
|
126
|
+
},
|
|
127
|
+
model: {
|
|
128
|
+
type: "string",
|
|
129
|
+
description: "Optional model override this phase is expected to use."
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
args: {
|
|
137
|
+
type: "object",
|
|
138
|
+
additionalProperties: true,
|
|
139
|
+
description: "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]})."
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
output: {
|
|
143
|
+
schema: {
|
|
144
|
+
type: "object",
|
|
145
|
+
additionalProperties: false,
|
|
146
|
+
properties: {
|
|
147
|
+
runId: {
|
|
148
|
+
type: "string",
|
|
149
|
+
required: true
|
|
150
|
+
},
|
|
151
|
+
agentsStarted: {
|
|
152
|
+
type: "integer",
|
|
153
|
+
required: true
|
|
154
|
+
},
|
|
155
|
+
result: {
|
|
156
|
+
type: "json",
|
|
157
|
+
required: true
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
render: (args, value) => [{
|
|
162
|
+
type: "text",
|
|
163
|
+
text: renderResult(args.meta.name, value.agentsStarted, value.result, maxResultChars)
|
|
164
|
+
}]
|
|
165
|
+
},
|
|
166
|
+
async execute(args, exec) {
|
|
167
|
+
const parent = exec.agent;
|
|
168
|
+
if (!parent) throw new Error("workflow tool requires a calling agent (exec.agent was undefined)");
|
|
169
|
+
const run = ctx.workflows.start({
|
|
170
|
+
script: args.script,
|
|
171
|
+
meta: args.meta,
|
|
172
|
+
...args.args !== void 0 ? { args: args.args } : {},
|
|
173
|
+
parent,
|
|
174
|
+
signal: exec.signal
|
|
175
|
+
});
|
|
176
|
+
const onAbort = () => {
|
|
177
|
+
run.cancel("parent step aborted");
|
|
178
|
+
};
|
|
179
|
+
exec.signal.addEventListener("abort", onAbort, { once: true });
|
|
180
|
+
try {
|
|
181
|
+
const result = await run.result;
|
|
182
|
+
const error = stopReasonError(result);
|
|
183
|
+
if (error !== void 0) throw new Error(error);
|
|
184
|
+
return {
|
|
185
|
+
runId: run.id,
|
|
186
|
+
agentsStarted: result.agentsStarted,
|
|
187
|
+
result: result.value
|
|
188
|
+
};
|
|
189
|
+
} finally {
|
|
190
|
+
exec.signal.removeEventListener("abort", onAbort);
|
|
191
|
+
await run.dispose();
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
presentCall: (args) => presentWorkflowCall(args),
|
|
195
|
+
presentResult: (args, result) => presentWorkflowResult(args, result)
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
//#endregion
|
|
199
|
+
export { Config, apply, inject, name };
|
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region lib/types/invariant.js
|
|
2
|
+
/**
|
|
3
|
+
* Package-owned invariant companion for `@deepseek-ai/dsh-tool-workflow`.
|
|
4
|
+
* @module @deepseek-ai/dsh-tool-workflow/invariant
|
|
5
|
+
*/
|
|
6
|
+
const PACKAGE_NAME = "@deepseek-ai/dsh-tool-workflow";
|
|
7
|
+
/** Cordis companion plugin name. */
|
|
8
|
+
const name = "tool-workflow-invariant";
|
|
9
|
+
/** Service required before the companion can reserve package ownership. */
|
|
10
|
+
const inject = ["invariants"];
|
|
11
|
+
/**
|
|
12
|
+
* No runtime invariant: this model-facing adapter has no independent lifecycle stream; execution
|
|
13
|
+
* relations are owned by the capability seam it calls.
|
|
14
|
+
*/
|
|
15
|
+
const install = () => {};
|
|
16
|
+
/**
|
|
17
|
+
* Register this package's invariant companion.
|
|
18
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
19
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
20
|
+
*/
|
|
21
|
+
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
22
|
+
//#endregion
|
|
23
|
+
export { apply, inject, name };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The model-facing `workflow` tool: run a JavaScript orchestration script that fans out
|
|
3
|
+
* subagents, and return the script's final value. It owns the model-facing schema and run lifecycle; script
|
|
4
|
+
* parsing, execution, caps, and cancellation live behind `ctx.workflows`
|
|
5
|
+
* (`@deepseek-ai/dsh-workflow`), so a hardened engine swaps in without touching what the model
|
|
6
|
+
* sees. Execution awaits `run.result` and always disposes the run; non-completed reasons become tool
|
|
7
|
+
* errors, and background collection remains deferred. Presentation is an args-only generic card
|
|
8
|
+
* titled from `meta.name`. Explicit-ask usage guidance is registered as the tool's own prompt
|
|
9
|
+
* section rather than deployment persona prose.
|
|
10
|
+
* @module @deepseek-ai/dsh-tool-workflow
|
|
11
|
+
*/
|
|
12
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
13
|
+
import z from '@deepseek-ai/schemastery';
|
|
14
|
+
export declare const name = "tool-workflow";
|
|
15
|
+
export declare const inject: string[];
|
|
16
|
+
/** Config: the model-facing tool name plus result rendering caps. */
|
|
17
|
+
export interface Config {
|
|
18
|
+
/** The model-facing tool name to register (default `workflow`). */
|
|
19
|
+
toolName?: string;
|
|
20
|
+
/** Rendered-result ceiling, in characters: a longer JSON value is truncated with a notice (default 50000). */
|
|
21
|
+
maxResultChars?: number;
|
|
22
|
+
}
|
|
23
|
+
export declare const Config: z<Config>;
|
|
24
|
+
export declare function apply(ctx: Context, config: Config): void;
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for `@deepseek-ai/dsh-tool-workflow`.
|
|
3
|
+
* @module @deepseek-ai/dsh-tool-workflow/invariant
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
6
|
+
/** Cordis companion plugin name. */
|
|
7
|
+
export declare const name = "tool-workflow-invariant";
|
|
8
|
+
/** Service required before the companion can reserve package ownership. */
|
|
9
|
+
export declare const inject: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Register this package's invariant companion.
|
|
12
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
13
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
14
|
+
*/
|
|
15
|
+
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
16
|
+
//# sourceMappingURL=invariant.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@deepseek-ai/dsh-tool-workflow",
|
|
3
|
+
"description": "Model-facing workflow tool: run a JavaScript orchestration script over ctx.workflows",
|
|
4
|
+
"version": "0.0.1-rc.1",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "restricted"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
|
|
11
|
+
"directory": "packages/workflow/tool-workflow"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "lib/index.js",
|
|
15
|
+
"types": "lib/types/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./lib/types/index.d.ts",
|
|
19
|
+
"default": "./lib/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./invariant": {
|
|
22
|
+
"types": "./lib/types/invariant.d.ts",
|
|
23
|
+
"default": "./lib/invariant.js"
|
|
24
|
+
},
|
|
25
|
+
"./src/*": "./src/*",
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"lib/index.js",
|
|
30
|
+
"lib/invariant.js",
|
|
31
|
+
"lib/types/**/*.d.ts"
|
|
32
|
+
],
|
|
33
|
+
"license": "BSD-3-Clause",
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@deepseek-ai/dsh-agent": "^0.0.1-rc.1",
|
|
36
|
+
"@deepseek-ai/dsh-llm": "^0.0.1-rc.1",
|
|
37
|
+
"@deepseek-ai/dsh-tools": "^0.0.1-rc.1",
|
|
38
|
+
"@deepseek-ai/dsh-workflow": "^0.0.1-rc.1",
|
|
39
|
+
"@deepseek-ai/cordis": "^4.0.1-rc.1",
|
|
40
|
+
"@deepseek-ai/dsh-system-prompt": "^0.0.1-rc.1",
|
|
41
|
+
"@deepseek-ai/dsh-invariants": "^0.0.1-rc.1"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@deepseek-ai/schemastery": "^3.18.1-rc.1"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@deepseek-ai/dsh-invariants": "^0.0.1-rc.1",
|
|
48
|
+
"@deepseek-ai/dsh-llm": "^0.0.1-rc.1",
|
|
49
|
+
"@deepseek-ai/dsh-agent": "^0.0.1-rc.1",
|
|
50
|
+
"@deepseek-ai/dsh-subagent": "^0.0.1-rc.1",
|
|
51
|
+
"@deepseek-ai/dsh-session": "^0.0.1-rc.1",
|
|
52
|
+
"@deepseek-ai/dsh-system-prompt": "^0.0.1-rc.1",
|
|
53
|
+
"@deepseek-ai/dsh-tools": "^0.0.1-rc.1",
|
|
54
|
+
"@deepseek-ai/dsh-workflow": "^0.0.1-rc.1",
|
|
55
|
+
"@deepseek-ai/dsh-workflow-workerthread": "^0.0.1-rc.1",
|
|
56
|
+
"@deepseek-ai/cordis": "^4.0.1-rc.1"
|
|
57
|
+
}
|
|
58
|
+
}
|