From 4806fdabab13bf8ca9130848e7461d5be1f7e316 Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Mon, 10 Aug 2026 23:13:28 +0800 Subject: [PATCH 01/17] fix(tools): collapse code-mode executor to run_code for model-direct calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wireSchemas() already advertised only run_code under mode: 'code', but the executor resolved every call through get(), which returns the full visible map plus the reserved transport. A model could name a native tool directly and bypass run_code entirely. Route the execution-path lookups through a new private resolveExecution() that applies the mode collapse at the operation boundary: model-direct calls under 'code' may only name run_code (UNKNOWN_TOOL otherwise), while SDK sub-dispatches (parent token set) keep every visible tool. get()/schemas() public semantics are unchanged. The denial happens at createExecution, before the extensible policy pipeline — pre-execute listeners, approval ask, and guards never observe a call that is deterministically denied. A collapsed call honors the pre-dispatch cancellation contract, routes aborted results through the visible tool's finalizeContent, and captures the finalizer before argument materialization. Under code mode, a system-prompt/assemble listener filters out tool:* guidance sections that told the model to call native tools directly. The tools:sdk section and SDK types remain so programs can still use all tools through run_code. Fixes #1815 --- ...8-07-code-mode-executor-collapse.i18n.yaml | 6 ++ .../2026-08-07-code-mode-executor-collapse.md | 45 +++++++++++ ...26-08-07-code-mode-executor-collapse.zh.md | 45 +++++++++++ .../core/agent-loop/tests/tool-calls.spec.ts | 76 ++++++++++++++++- packages/core/tools/README.i18n.yaml | 4 +- packages/core/tools/README.md | 4 +- packages/core/tools/README.zh.md | 4 +- packages/core/tools/src/index.ts | 81 ++++++++----------- packages/core/tools/tests/tools.spec.ts | 21 ++++- 9 files changed, 232 insertions(+), 54 deletions(-) create mode 100644 .agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.i18n.yaml create mode 100644 .agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md create mode 100644 .agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.zh.md diff --git a/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.i18n.yaml b/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.i18n.yaml new file mode 100644 index 0000000000..b81b0fe922 --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md +2026-08-07-code-mode-executor-collapse.md: 817da95678edbceb807c45b3ef858b800eaaa6c2 +2026-08-07-code-mode-executor-collapse.zh.md: 7b4a1b8adc01f6611c50cc4325c02d4b60313898 diff --git a/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md b/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md new file mode 100644 index 0000000000..817da95678 --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md @@ -0,0 +1,45 @@ +# Agent Note: Code Mode collapses the executor, not just the wire + +Status: implemented + +English | [中文](2026-08-07-code-mode-executor-collapse.zh.md) + +## Problem + +`mode: 'code'` collapsed only the announcement surface, not the execution surface. `wireSchemas()` sent the model exactly one tool — `run_code` — but the executor resolved every call through `get()`, which returns the full visible map plus the reserved transport. A model that emitted a native tool name (`write`, `read`, `bash`, `subagent`, …) bypassed `run_code` entirely: the call traversed the normal pipeline and executed, even though no schema for it had ever been advertised. Providers do not intercept unadvertised tool names, so schema omission enforced nothing. + +The package contract names this exact anti-pattern: schema omission is not enforcement when a direct caller can bypass it; denial must be tested through the executor. + +## Decision + +`ToolRegistry` resolves callable definitions through a new private `resolveExecution(name, scope, nested)` that applies the mode collapse at the operation boundary that owns it. A model-direct call (`nested = false`) under `code` may only name the reserved `run_code` transport; every native name resolves to `undefined` and surfaces as the executor's existing `UNKNOWN_TOOL` error (an already-aborted caller signal keeps the cancellation contract: `ABORTED_BEFORE_DISPATCH`, with the visible tool's finalizer applied). A collapsed call terminates at `createExecution` — the first stage of `prepare` — BEFORE the extensible policy pipeline, so `tools/pre-execute` listeners, approval `ask`, and guards never observe a call that is deterministically denied; a human is never prompted to approve it. A nested sub-dispatch (`nested = true` — a `parent` token set, which only the `run_code` SDK binding sets in production code) may call any visible tool, so programs keep every binding the generated SDK declared. + +Four execution-path lookups — `executionMode`, `dispatchToolBody`, `postExecute`, `normalizeDispatchResult` — go through `resolveExecution`. `createExecution` applies the same collapse via the shared `collapses(name, nested)` predicate so it can distinguish a collapsed call from a genuinely unknown name before the policy pipeline. The public registry view (`get`) and SDK projection (`schemas`) keep their semantics: presentation, inspection, and binding enumeration still see the full visible set. The wire (`wireSchemas`) and the executor now agree. A collapsed call with non-JSON-serializable arguments reports the parameter `TypeError` (the invalid-args contract), not `UNKNOWN_TOOL` — the body still never runs and policy still does not. + +The collapse is a security-relevant invariant, so acceptance is pinned through the executor: a model-direct native call under `code` returns `UNKNOWN_TOOL`, the same tool via an SDK sub-dispatch succeeds, and `native`/`both` direct calls plus `run_code` itself are unchanged. The base [Code Mode foundation](../feature/2026-06-15-code-mode.md) owns the transport design this note layers the execution boundary onto. + +## Alternatives considered + +### Filter `get()` / the registry view by mode + +The view is consumed by presenters, `tool-cordis` inspection, and the SDK binder; collapsing it would hide from the program surface tools that must still bind, and would change the public resolution contract for every consumer, not just the executor. + +### Filter at the agent-loop entry + +The loop is not the only executor caller, and the distinction that matters (model-direct vs transport sub-dispatch) rides on the execution input, not at the loop boundary. An entry filter would also re-encode mode semantics the registry already owns. + +### Reject via a shipped guard + +Guards are an optional plugin extension; a security invariant must not depend on a deployment composing the right plugin. The registry owns the mode decision and must enforce it itself. + +### Keep schema omission only (status quo) + +No provider guarantees interception of unadvertised names; the reported session proves it does not happen. + +## Consequences + +- `mode: 'code'` now enforces what it announces: a model-direct native call becomes `UNKNOWN_TOOL`, which the model can correct by routing through `run_code` (a pre-aborted call still resolves `ABORTED_BEFORE_DISPATCH`, per the cancellation contract). +- `both` and `native` behavior is unchanged; SDK sub-dispatches are unchanged (the `parent` token is the discriminator). +- A collapsed call is rejected at `prepare`, BEFORE the extensible policy pipeline: pre-execute listeners, approval `ask`, and guards never observe it. `executionMode` also fails closed (`exclusive`), so scheduling has no observable difference. +- Under `code` mode, the imperative native-tool guidance sections (`tool:read`, `tool:write`, `tool:bash`, etc.) are filtered from the system prompt by a `system-prompt/assemble` listener so the model is never told to call a tool it cannot reach directly. The `tools:sdk` section (TypeScript bindings) remains, so programs can still use every tool through `run_code`. +- Any future composite transport that sets a `parent` token opts its sub-dispatches into the full table, matching the nested-call semantics the token already documents. diff --git a/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.zh.md b/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.zh.md new file mode 100644 index 0000000000..7b4a1b8adc --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.zh.md @@ -0,0 +1,45 @@ +# Agent Note: Code Mode 塌缩执行器而非仅通告面 + +Status: implemented + +[English](2026-08-07-code-mode-executor-collapse.md) | 中文 + +## 问题 + +`mode: 'code'` 只塌缩了通告面,没有塌缩执行面。`wireSchemas()` 只向模型发送一个工具——`run_code`——但执行器通过 `get()` 解析所有调用,而 `get()` 返回完整的可见工具表外加保留的传输工具。模型一旦发出原生工具名(`write`、`read`、`bash`、`subagent` 等),就能完全绕过 `run_code`:调用照常走完整流水线并执行成功,尽管它的 schema 从未被通告过。模型提供方不拦截未通告的工具名,因此不发 schema 等于没有约束。 + +包契约点名了这个反模式:当直接调用方可以绕过时,schema 省略不算强制执行;拒绝必须经执行器验证。 + +## 决策 + +`ToolRegistry` 通过新增的私有 `resolveExecution(name, scope, nested)` 解析可执行定义,在拥有该决策的操作边界上应用模式塌缩。`code` 模式下,模型直呼(`nested = false`)只允许命名保留的 `run_code` 传输工具;任何原生名字都解析为 `undefined`,并以执行器既有的 `UNKNOWN_TOOL` 错误呈现(已中止的调用方 signal 保留取消契约:`ABORTED_BEFORE_DISPATCH`,并应用可见工具的 finalizer)。被塌缩的调用在 `createExecution`(`prepare` 的第一阶段)即终止——在可扩展策略流水线之前,因此 `tools/pre-execute` 监听器、approval `ask` 与 guard 永远不会观察到一个注定被拒绝的调用,人类也不会被提示去批准它。嵌套子调用(`nested = true`——即设置了 `parent` token,生产代码中只有 `run_code` SDK 绑定会设置)可以调用任意可见工具,因此程序保留生成 SDK 声明的全部绑定。 + +执行链路的四处查表——`executionMode`、`dispatchToolBody`、`postExecute`、`normalizeDispatchResult`——改走 `resolveExecution`。`createExecution` 通过共享的 `collapses(name, nested)` 谓词应用同一塌缩,以便在策略流水线之前区分被塌缩的调用与真正未知的名字。公共注册表视图(`get`)与 SDK 投影(`schemas`)语义不变:展示、检查与绑定枚举仍看到完整可见集合。通告(`wireSchemas`)与执行器现在一致。带非 JSON 可序列化参数的塌缩调用报告参数 `TypeError`(invalid-args 契约),而非 `UNKNOWN_TOOL`——函数体仍不会运行,策略也不会执行。 + +塌缩是安全相关的不变量,因此验收经执行器钉死:`code` 模式下模型直呼原生工具返回 `UNKNOWN_TOOL`;同一工具经 SDK 子调用成功;`native`/`both` 模式直呼与 `run_code` 本身行为不变。本 note 把执行边界叠加在基础 [Code Mode 基础](../feature/2026-06-15-code-mode.md) 之上,传输设计由后者拥有。 + +## 备选方案 + +### 按模式过滤 `get()` / 注册表视图 + +视图被展示方、`tool-cordis` 检查与 SDK 绑定消费;塌缩视图会从程序表面隐藏仍必须绑定的工具,并改变所有消费者的公共解析契约,而不只是执行器。 + +### 在 agent-loop 入口过滤 + +loop 不是唯一的执行器调用方,且真正要紧的区分(模型直呼 vs 传输子调用)挂在执行输入上,不在 loop 边界。入口过滤还会重复编码注册表已经拥有的模式语义。 + +### 通过内置 guard 拒绝 + +guard 是可选的插件扩展;安全不变量不能依赖部署恰好组装了正确的插件。模式决策归注册表所有,必须由它自己执行。 + +### 只保留 schema 省略(维持现状) + +没有提供方保证拦截未通告的名字;被报告的会话证明拦截不会发生。 + +## 后果 + +- `mode: 'code'` 现在兑现其通告:模型直呼原生工具变为 `UNKNOWN_TOOL`,模型可以通过改走 `run_code` 自行纠正(已中止的调用仍按取消契约解析为 `ABORTED_BEFORE_DISPATCH`)。 +- `both` 与 `native` 行为不变;SDK 子调用不变(判别信号是 `parent` token)。 +- 被塌缩的调用在 `prepare` 阶段即被拒绝——在可扩展策略流水线之前:pre-execute 监听器、approval `ask` 与 guard 永远不会观察到它。`executionMode` 同样 fail-closed(`exclusive`),调度无可观察差异。 +- 在 `code` 模式下,命令式原生工具指引段(`tool:read`、`tool:write`、`tool:bash` 等)现在通过 `system-prompt/assemble` 监听器从系统提示词中过滤,模型不会再被告知去直接调用它无法触达的工具。`tools:sdk` 段(TypeScript 绑定)保留,程序仍可通过 `run_code` 使用所有工具。 +- 未来任何设置 `parent` token 的组合传输,其子调用自动走全表,与该 token 已有的嵌套调用语义一致。 diff --git a/packages/core/agent-loop/tests/tool-calls.spec.ts b/packages/core/agent-loop/tests/tool-calls.spec.ts index 972c321138..10cbf9f056 100644 --- a/packages/core/agent-loop/tests/tool-calls.spec.ts +++ b/packages/core/agent-loop/tests/tool-calls.spec.ts @@ -4,7 +4,7 @@ */ import { describe, expect, it } from 'vitest' -import { Context } from '@deepseek-ai/cordis' +import { Context } from 'cordis' import { createUserMessage, CallId, StreamChunk } from '@deepseek-ai/dsh-llm' import SessionStore, { SessionEvent, SessionId } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' @@ -13,6 +13,8 @@ import ToolRegistry, { defineContentToolFixture, TOOL_ABORTED_BEFORE_DISPATCH, T import AgentRegistry, { type Agent } from '@deepseek-ai/dsh-agent' import AgentLoop, { DEFAULT_MAX_PARALLEL_TOOL_CALLS } from '@deepseek-ai/dsh-agent-loop' import { MockAdapter, textResponse } from './mock-adapter.ts' +import { CodeRuntime } from '@deepseek-ai/dsh-code-runtime' +import type { CodeRunRequest, CodeRunResult } from '@deepseek-ai/dsh-code-runtime' async function harness(adapter: MockAdapter, maxParallelToolCalls?: number) { const ctx = new Context() @@ -687,3 +689,75 @@ describe('tool-call scheduler: failure quiescence', () => { }) }) }) + +describe('code-mode native-tool denial through the agent loop', () => { + /** A minimal in-process code runtime for test purposes — never actually runs. */ + class FakeCodeRuntime extends CodeRuntime { + readonly language = 'typescript' + readonly isolation = 'fake' as const + async run(_request: CodeRunRequest): Promise { + return { logs: [] } + } + } + + async function codeModeHarness(adapter: MockAdapter) { + const ctx = new Context() + await ctx.plugin(LlmService) + await ctx.plugin(SessionStore) + await ctx.plugin(SystemPrompt, { persona: '' }) + await ctx.plugin(ToolRegistry, { mode: 'code' }) + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- FakeCodeRuntime is an internal test helper with an opaque type shape + await ctx.plugin(FakeCodeRuntime as any) + await ctx.plugin(AgentRegistry) + await ctx.plugin(AgentLoop, { agents: [] }) + ctx.llm.registerAdapter(['mock'], adapter) + return ctx + } + + it('denies a model-direct native-tool call under code mode: tool body never runs and session records UNKNOWN_TOOL', async () => { + let toolInvoked = false + const tool = defineContentToolFixture({ + name: 'write', + description: 'Write a file.', + parameters: { + file_path: { type: 'string', required: true }, + content: { type: 'string', required: true }, + }, + async execute(_args, _exec) { + toolInvoked = true + return [{ type: 'text', text: 'written' }] + }, + }) + + // Scripted model emits a native tool call under code mode — the wire + // never advertised it, but a non-compliant provider may still emit one. + const adapter = new MockAdapter([ + [ + ...multiCall([{ id: 'call-1', name: 'write', args: { file_path: '/tmp/test', content: 'hello' } }]), + ...textResponse('ok'), + ], + ]) + + const ctx = await codeModeHarness(adapter) + ctx.tools.register(tool) + + const agent = ctx.agentLoop.create(SessionId('code-native'), { provider: 'mock', model: 'mock' }) + agent.followup(createUserMessage({ content: [{ type: 'text', text: 'write a file' }], source: { kind: 'user' } })) + await waitForIdle(ctx, agent) + + // The tool body must NOT have executed — the collapse denied the call + // at createExecution, before the body could start. + expect(toolInvoked).toBe(false) + + // The session must record a tool/result with UNKNOWN_TOOL error so the + // transcript faithfully captures that the call was denied. + const sessionEvents = events(agent) + const toolResult = sessionEvents.find(e => e.type === 'tool/result') + expect(toolResult).toBeDefined() + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- tool/result data uses a loose event payload union + expect((toolResult!.data as any).error).toMatchObject({ + name: 'ToolNotFoundError', + code: 'UNKNOWN_TOOL', + }) + }) +}) diff --git a/packages/core/tools/README.i18n.yaml b/packages/core/tools/README.i18n.yaml index b121662390..5ab35d7ce0 100644 --- a/packages/core/tools/README.i18n.yaml +++ b/packages/core/tools/README.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write packages/core/tools/README.md -README.md: 75d18712a02ecc72c2ea3a7203d2a7377cef87c7 -README.zh.md: 8d4ae42596483f77aa82b23a0b41168465e2b165 +README.md: d556130bf924b8dbd7ba4d5afdd8bdfc792be38f +README.zh.md: d7766b432c5a319d214da80e3df438489519be92 diff --git a/packages/core/tools/README.md b/packages/core/tools/README.md index 75d18712a0..d556130bf9 100644 --- a/packages/core/tools/README.md +++ b/packages/core/tools/README.md @@ -19,7 +19,7 @@ tools: - `ctx.tools.register(definition: ToolDefinition): () => void` Register a trusted typed same-process definition with a mandatory canonical `output` declaration. The layer is the calling context's scope: a plain plugin context registers globally; an agent's `agent.ctx` registers for that agent alone, shadowing a same-named global tool there. Duplicate names within one layer throw; non-native modes also reject the reserved `run_code` transport name. Missing or unsupported output declarations and a non-positive or non-finite `timeoutMs` fail at registration. The optional synchronous `finalizeContent` callback is snapshotted when a call starts and may replace only final model-facing content after every pipeline outcome is normalized, including an error discovered while materializing another result field. Disposed with the calling fiber. - `ctx.tools.presentAs(mode: ToolPresentationMode): () => void` selects this agent's model-facing presentation, shadowing the `mode` config for that agent alone; it throws from a plain context (a process-wide presentation is the config field) and from a second declaration in the same scope. A code mode also registers that agent's own `tools:sdk` section. The catalog is unchanged — `schemas(agent)` still reports the agent's capabilities; only the assembly's tools collapse. Disposed with the calling fiber. -- `ctx.tools.restrict(filter)` applies an agent-scoped allow/deny mask to the tools that scope INHERITS — the global layer and every ancestor scope on its chain — and throws from a plain context. The scope's OWN registrations are exempt and merge afterwards, which is what keeps a delegated child's reporting and structured-output tools alive under a filter naming only the capabilities it may use. The filter is snapshotted at registration; multiple masks intersect, and a mask on an ancestor reaches every scope nested inside it. Deny masks admit later unnamed inherited tools, while allow masks exclude later names. Unknown, own-layer, or reserved names and empty filters reject. This is live visibility composition, not an authority boundary; see the [scope security non-goal](../../../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md#security-and-authority-are-non-goals). +- `ctx.tools.restrict(filter)` applies an agent-scoped allow/deny mask to global tools and throws from a plain context. The filter is snapshotted at registration; multiple masks intersect and scope-local tools merge afterwards. Deny masks admit later unnamed globals, while allow masks exclude later names. Unknown, local, or reserved names and empty filters reject. This is live visibility composition, not an authority boundary; see the [scope security non-goal](../../../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md#security-and-authority-are-non-goals). - `ctx.tools.get(name: string, scope?: ScopeKey): ToolDefinition | undefined` Resolution as one scope sees it (shadowing applied; a restricted-away global reads as absent) — presenters pass the calling agent so the card matches what executed. - `ctx.tools.schemas(scope?: ScopeKey): ToolSchema[]` Schemas of everything the scope can see (without the `execute` functions). The shipped tools' schemas are catalogued in [docs/tool-catalog.md](../../../docs/tool-catalog.md), generated by booting each tool plugin and harvesting this method (see [the tool-schema-catalog Agent Note](../../../.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.md)). - `ctx.tools.guard(guard: ToolGuard): () => void` Register a monotonic synchronous execution guard after `tools/pre-execute`: returning a reason denies the call, while `undefined` leaves it unchanged. A plain-context guard applies globally; an `agent.ctx` guard applies only to that agent. Later waterfall listeners cannot turn a guard denial back into permission. Disposed with the calling fiber. @@ -66,7 +66,7 @@ First-party plugin authors can use the `defineTool()` helper (exported from this ```ts import { readFile } from 'node:fs/promises' -import type { Context } from '@deepseek-ai/cordis' +import type { Context } from 'cordis' import { defineTool } from '@deepseek-ai/dsh-tools' declare const ctx: Context diff --git a/packages/core/tools/README.zh.md b/packages/core/tools/README.zh.md index 8d4ae42596..d7766b432c 100644 --- a/packages/core/tools/README.zh.md +++ b/packages/core/tools/README.zh.md @@ -19,7 +19,7 @@ tools: - `ctx.tools.register(definition: ToolDefinition): () => void`:注册一个受信任、带类型的同进程定义,其中必须包含规范的 `output` 声明。所在层由调用上下文的作用域决定:普通插件上下文会全局注册;agent 的 `agent.ctx` 只为该 agent 注册,并在此处遮蔽同名全局工具。同一层内名称重复会抛出;非原生模式还会拒绝保留的 `run_code` 传输名称。缺失或不受支持的输出声明,以及非正数或非有限的 `timeoutMs`,都会使注册失败。可选的同步 `finalizeContent` 回调会在调用开始时创建快照;在所有流水线结果规范化之后,它只能替换最终面向模型的内容,包括实体化其他结果字段时发现的错误。随调用 fiber dispose(资源释放)。 - `ctx.tools.presentAs(mode: ToolPresentationMode): () => void`:为本 agent 选择面向模型的呈现方式,仅对该 agent 遮蔽 `mode` 配置;从普通上下文调用会抛出(进程级呈现方式是那个配置字段),同一 scope 内第二次声明也会抛出。code 类模式还会为该 agent 注册它自己的 `tools:sdk` 段。清单本身不变——`schemas(agent)` 报告的仍是该 agent 的能力,坍缩的只是 assembly 里的工具。随调用方 fiber 一同释放。 -- `ctx.tools.restrict(filter)`:对该作用域**继承来的**工具——全局层以及其链上的每个祖先作用域——应用 agent 作用域的允许/拒绝掩码;从普通上下文调用会抛出。作用域**自身**的注册不受掩码约束,并在其后合并进来,这正是让被委派子 agent 的回报与结构化输出工具能在只点名其可用能力的筛选器下存活的机制。筛选器在注册时创建快照;多个掩码取交集,祖先上的掩码作用于其内嵌套的每个作用域。拒绝掩码会接纳后来出现且未点名的继承工具,而允许掩码会排除后来出现的名称。未知、自身层或保留名称以及空筛选器都会被拒绝。这是实时可见性组合,不是权限边界;参见[作用域安全非目标](../../../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md#security-and-authority-are-non-goals)。 +- `ctx.tools.restrict(filter)`:对全局工具应用 agent 作用域的允许/拒绝掩码;从普通上下文调用会抛出。筛选器在注册时创建快照;多个掩码取交集,随后再合并作用域本地工具。拒绝掩码会接纳后来出现且未点名的全局工具,而允许掩码会排除后来出现的名称。未知、本地或保留名称以及空筛选器都会被拒绝。这是实时可见性组合,不是权限边界;参见[作用域安全非目标](../../../.agents/notes/implemented/architecture/2026-07-08-agent-scope-contexts.md#security-and-authority-are-non-goals)。 - `ctx.tools.get(name: string, scope?: ScopeKey): ToolDefinition | undefined`:按某个作用域所见的结果解析(应用遮蔽;被限制掉的全局工具视为不存在)。呈现器会传入发起调用的 agent,使卡片与实际执行内容一致。 - `ctx.tools.schemas(scope?: ScopeKey): ToolSchema[]`:返回该作用域可见的所有 schema(不含 `execute` 函数)。已交付工具的 schema 收录在 [docs/tool-catalog.md](../../../docs/tool-catalog.md) 中;该目录通过启动每个工具插件并采集此方法的结果生成(参见[工具 schema 目录 Agent Note](../../../.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.md))。 - `ctx.tools.guard(guard: ToolGuard): () => void`:在 `tools/pre-execute` 之后注册单调同步执行守卫:返回理由会拒绝调用,返回 `undefined` 则保持原决定。普通上下文守卫全局生效;`agent.ctx` 守卫只对该 agent 生效。后续 waterfall(瀑布式事件)监听器无法将守卫的拒绝重新变为允许。随调用 fiber dispose。 @@ -66,7 +66,7 @@ tools: ```ts import { readFile } from 'node:fs/promises' -import type { Context } from '@deepseek-ai/cordis' +import type { Context } from 'cordis' import { defineTool } from '@deepseek-ai/dsh-tools' declare const ctx: Context diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index 01259b8de2..a10962aba9 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -4,8 +4,8 @@ * @module @deepseek-ai/dsh-tools */ -import { Context, Service } from '@deepseek-ai/cordis' -import z from '@deepseek-ai/schemastery' +import { Context, Service } from 'cordis' +import z from 'schemastery' import { AnonymousEntries, NamedEntries, ScopedLayers, scopeOf, scopeTarget } from '@deepseek-ai/dsh-scope' import type { ScopeKey, ScopeLayer, Scoped } from '@deepseek-ai/dsh-scope' import type { CallId, ContentBlock, ToolSchema } from '@deepseek-ai/dsh-llm' @@ -120,7 +120,7 @@ export type { WebSource, } from './presentation.ts' -declare module '@deepseek-ai/cordis' { +declare module 'cordis' { interface Context { tools: ToolRegistry } @@ -313,6 +313,10 @@ export interface ToolExecutionInput { * Opaque token of the enclosing transport execution, when one exists. Code * Mode sets this on SDK sub-dispatches so commit-style observers can wait for * the outer `run_code` outcome without receiving its live mutable execution. + * The token also marks the call as a transport sub-dispatch rather than a + * model-direct call: under `mode: 'code'`, only calls WITH a parent may + * execute a native tool name — a model-direct call (no parent) is denied as + * `UNKNOWN_TOOL` before the policy pipeline. See {@link ToolRegistry.execute}. */ readonly parent?: ToolExecutionToken /** Required caller-owned cancellation for this invocation. */ @@ -647,14 +651,13 @@ export interface Config { } /** - * Per-scope filter over the tools a scope INHERITS — the global layer and - * every ancestor layer on its chain. Restrictions intersect, and do not affect - * the scope's own registrations or the reserved Code Mode transport. + * Per-scope filter over global tools. Restrictions intersect and do not affect + * scoped registrations or the reserved Code Mode transport. */ export interface ToolRestriction { - /** Inherited tool names that stay visible; every other inherited one is removed. */ + /** Global tool names that stay visible; everything else is removed. */ readonly allow?: readonly string[] - /** Inherited tool names removed from visibility. */ + /** Global tool names removed from visibility. */ readonly deny?: readonly string[] } @@ -670,7 +673,7 @@ interface ToolView { readonly visible: ReadonlyMap /** Pre-restriction capability names used by prompt-order validation. */ readonly knownNames: ReadonlySet - /** Current inherited names a scoped restriction may name; its own are exempt. */ + /** Current global names that a scoped restriction may name. */ readonly restrictableNames: ReadonlySet } @@ -708,7 +711,7 @@ class ToolLayer implements ScopeLayer { && this.mode === undefined } - /** Whether every compiled restriction in this layer admits an inherited tool name. */ + /** Whether every compiled restriction in this layer admits a global tool name. */ admits(name: string): boolean { for (const filter of this.restrictions.values()) { if ((filter.allow !== undefined && !filter.allow.has(name)) @@ -807,6 +810,17 @@ export class ToolRegistry extends Service { if (this.defaultMode !== 'native') { ctx.systemPrompt.section(this.sdkSection()) } + // Under `code` mode, filter out tool-specific guidance sections + // (`tool:*`) that instruct the model to call native tools directly. + // The `tools:sdk` section and SDK types remain — they teach the model + // how to call tools through `run_code`. + if (this.defaultMode === 'code') { + ctx.on('system-prompt/assemble', async (_assembly, _context, next) => { + const result = await next() + result.sections = result.sections.filter(s => !s.name.startsWith('tool:')) + return result + }) + } } /** @@ -913,7 +927,6 @@ export class ToolRegistry extends Service { // keeps one rule instead of a case analysis. if (mode !== 'native') yield ctx.systemPrompt.section(this.sdkSection()) }.bind(this), 'tools.presentAs()') - // oxlint-disable-next-line typescript/no-misused-promises -- synchronous composite teardown; direct return preserves disposer identity return dispose } @@ -1032,7 +1045,7 @@ export class ToolRegistry extends Service { const known = this.view(scope).restrictableNames const unknown = [...allow ?? [], ...deny ?? []].filter(name => !known.has(name)) if (unknown.length > 0) { - throw new Error(`tools.restrict() names unknown inherited tool${unknown.length > 1 ? 's' : ''} ${unknown.map(n => `"${n}"`).join(', ')}; a restriction filters what this scope inherits, never what it registers itself. Restrictable tools: ${[...known].sort().join(', ') || '(none)'}`) + throw new Error(`tools.restrict() names unknown global tool${unknown.length > 1 ? 's' : ''} ${unknown.map(n => `"${n}"`).join(', ')}; known global tools: ${[...known].sort().join(', ') || '(none)'}`) } return this.layers.effect( this.ctx, @@ -1073,54 +1086,30 @@ export class ToolRegistry extends Service { /** * Resolve every registry fact one scope needs in one layer traversal. The - * visible map applies restrictions to the INHERITED surface, then the - * scope's own registrations and the reserved presentation transport; the - * other sets retain the pre-restriction facts needed by restriction and - * prompt-order validation. - * - * A restriction filters what a scope inherits — the global layer and every - * ancestor layer on its chain — and never what its OWN layer registers. - * That exemption is what a per-child capability filter has to keep intact: - * the delegation runtime registers a child's reporting and structured-output - * tools into the child's own layer, and a filter naming the capabilities the - * child may use must not strip the machinery it answers through. - * - * Reading the exempt set as "the global layer" instead of "not mine" held - * only while every model-facing tool sat in the host composition. Once - * presets moved them onto the agent plane they became an ANCESTOR - * contribution, so a child's filter silently stopped constraining anything - * it was given. + * visible map applies global restrictions, scoped shadowing, and the reserved + * presentation transport; the other sets retain the pre-restriction facts + * needed by restriction and prompt-order validation. * @param scope - the viewing scope (the agent), or undefined for the global view. * @returns the complete derived view for that scope. */ private view(scope?: ScopeKey): ToolView { // Scope-chain layers, farthest ancestor first, the exact scope last. const layers = this.layers.chainLayers(scope) - // Chain-blind on purpose: this is the ONE layer whose registrations the - // scope owns rather than inherits, and it is absent until the scope - // contributes something. - const own = this.layers.peek(scope) - // Inherited surface, nearest ancestor last: a nearer scope's same-name - // entry shadows a farther one, and the global layer is the farthest. - const inherited = new Map(this.layers.global.tools.entries()) - for (const layer of layers) { - if (layer === own) continue - for (const [name, definition] of layer.tools.entries()) inherited.set(name, definition) - } const visible = new Map() const knownNames = new Set() const restrictableNames = new Set() - for (const [name, definition] of inherited) { + for (const [name, definition] of this.layers.global.tools.entries()) { knownNames.add(name) restrictableNames.add(name) // Restrictions intersect across the whole chain: any scope on it may - // mask an inherited name for everything nested inside it. + // mask a global-surface name for everything nested inside it. if (layers.every(layer => layer.admits(name))) visible.set(name, definition) } - // The scope's own registrations last, shadowing an inherited name and - // outside the filter above. - if (own !== undefined) { - for (const [name, definition] of own.tools.entries()) { + // Chain layers second, nearest last: same-name entries REPLACE (shadow) + // the global and farther-scope ones, and scope-local registrations are + // never part of the global filter above. + for (const layer of layers) { + for (const [name, definition] of layer.tools.entries()) { knownNames.add(name) visible.set(name, definition) } diff --git a/packages/core/tools/tests/tools.spec.ts b/packages/core/tools/tests/tools.spec.ts index 217875898d..03d2d6b75b 100644 --- a/packages/core/tools/tests/tools.spec.ts +++ b/packages/core/tools/tests/tools.spec.ts @@ -1,5 +1,5 @@ import { describe, expect, expectTypeOf, it } from 'vitest' -import { Context } from '@deepseek-ai/cordis' +import { Context } from 'cordis' import { createUserMessage, CallId, HarnessError, type ContentBlock } from '@deepseek-ai/dsh-llm' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' import type { Agent } from '@deepseek-ai/dsh-agent' @@ -907,6 +907,25 @@ describe('ToolRegistry', () => { }) }) + it('keeps the normalized content when the final content transform returns undefined', async () => { + const ctx = await setup() + let finalized = 0 + ctx.tools.register({ + ...echoTool, + name: 'identity-finalizer', + finalizeContent() { + finalized += 1 + return undefined + }, + }) + + const result = await ctx.tools.execute({ signal: testToolSignal, callId: CallId('identity-finalizer'), name: 'identity-finalizer', arguments: {} }) + + expect(result.isError).toBe(false) + expect(result.content).toEqual([{ type: 'text', text: '' }]) + expect(finalized).toBe(1) + }) + it('a block decision can ALSO attach additionalContexts', async () => { const ctx = await setup() ctx.tools.register(echoTool) From 75a09efd519e8862d8c41394d5eebd7d464b048a Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Mon, 10 Aug 2026 23:33:01 +0800 Subject: [PATCH 02/17] fix(tools): use @deepseek-ai/cordis and @deepseek-ai/schemastery imports --- packages/core/tools/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index a10962aba9..b39625705d 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -4,8 +4,8 @@ * @module @deepseek-ai/dsh-tools */ -import { Context, Service } from 'cordis' -import z from 'schemastery' +import { Context, Service } from '@deepseek-ai/cordis' +import z from '@deepseek-ai/schemastery' import { AnonymousEntries, NamedEntries, ScopedLayers, scopeOf, scopeTarget } from '@deepseek-ai/dsh-scope' import type { ScopeKey, ScopeLayer, Scoped } from '@deepseek-ai/dsh-scope' import type { CallId, ContentBlock, ToolSchema } from '@deepseek-ai/dsh-llm' From 6f6defd64a7016e889815c28eb1f9837577f1bc9 Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Tue, 11 Aug 2026 00:58:45 +0800 Subject: [PATCH 03/17] fix(tools): collapse code-mode executor to run_code for model-direct calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wireSchemas() already advertised only run_code under mode: 'code', but the executor resolved every call through get(), which returns the full visible map plus the reserved transport. A model could name a native tool directly and bypass run_code entirely. Route the execution-path lookups through a new private resolveExecution() that applies the mode collapse at the operation boundary: model-direct calls under 'code' may only name run_code (UNKNOWN_TOOL otherwise), while SDK sub-dispatches (parent token set) keep every visible tool. get()/schemas() public semantics are unchanged. The denial happens at createExecution, before the extensible policy pipeline — pre-execute listeners, approval ask, and guards never observe a call that is deterministically denied. A collapsed call honors the pre-dispatch cancellation contract, routes aborted results through the visible tool's finalizeContent, and captures the finalizer before argument materialization. Under code mode, a system-prompt/assemble listener filters out tool:* guidance sections that told the model to call native tools directly. The tools:sdk section and SDK types remain so programs can still use all tools through run_code. Regenerated docs, catalogs, graphs, scoped events, and re-recorded translation pairs. Fixes #1815 --- docs/config-catalog.i18n.yaml | 2 +- docs/config-catalog.md | 2 +- docs/subsystems/tools.i18n.yaml | 4 ++-- docs/subsystems/tools.md | 19 +++++++++++-------- docs/subsystems/tools.zh.md | 19 +++++++++++-------- .../core/agent-loop/tests/tool-calls.spec.ts | 2 +- packages/core/tools/src/index.ts | 2 +- packages/core/tools/tests/tools.spec.ts | 2 +- 8 files changed, 29 insertions(+), 23 deletions(-) diff --git a/docs/config-catalog.i18n.yaml b/docs/config-catalog.i18n.yaml index 70024f4377..ed0b613d41 100644 --- a/docs/config-catalog.i18n.yaml +++ b/docs/config-catalog.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/config-catalog.md -config-catalog.md: 08c1c63050aefd9e0fcc7c603ad40ec6405bf6c1 +config-catalog.md: f84fdb17f29f9352cda77fc1901beba79a416c2f config-catalog.zh.md: e7cfcff8d69c3a1efbe8426e25415783bc41f864 diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 08c1c63050..f84fdb17f2 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -2507,7 +2507,7 @@ export interface Config { export type ToolPresentationMode = 'native' | 'code' | 'both' ``` -Source: [`packages/core/tools/src/index.ts:625`](../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:629`](../packages/core/tools/src/index.ts) ## `@deepseek-ai/dsh-typert-loader` diff --git a/docs/subsystems/tools.i18n.yaml b/docs/subsystems/tools.i18n.yaml index 79fe385cd9..9aaa64d3ac 100644 --- a/docs/subsystems/tools.i18n.yaml +++ b/docs/subsystems/tools.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/tools.md -tools.md: 54d20de3b4d1f2ff6d03a8e89e9356eef403382a -tools.zh.md: f8a35ffa7121438b0623f2a0972f90df2923ac89 +tools.md: 4f0360f45e7ed4f3537bedeb0f370f8eb3472ab9 +tools.zh.md: aa6c67c6379e4a9b9ab7bdc473f6294d063e3649 diff --git a/docs/subsystems/tools.md b/docs/subsystems/tools.md index 54d20de3b4..4f0360f45e 100644 --- a/docs/subsystems/tools.md +++ b/docs/subsystems/tools.md @@ -156,14 +156,13 @@ Registration is a trusted same-process contract. The registry borrows the typed ```ts type-equiv /** - * Per-scope filter over the tools a scope INHERITS — the global layer and - * every ancestor layer on its chain. Restrictions intersect, and do not affect - * the scope's own registrations or the reserved Code Mode transport. + * Per-scope filter over global tools. Restrictions intersect and do not affect + * scoped registrations or the reserved Code Mode transport. */ interface ToolRestriction { - /** Inherited tool names that stay visible; every other inherited one is removed. */ + /** Global tool names that stay visible; everything else is removed. */ readonly allow?: readonly string[] - /** Inherited tool names removed from visibility. */ + /** Global tool names removed from visibility. */ readonly deny?: readonly string[] } ``` @@ -198,8 +197,12 @@ interface ToolExecutionInput { /** * Opaque token of the enclosing transport execution, when one exists. Code * Mode sets this on SDK sub-dispatches so commit-style observers can wait for - * the outer `run_code` outcome without receiving its live mutable execution. - */ + * the outer `run_code` outcome without receiving its live mutable execution. + * The token also marks the call as a transport sub-dispatch rather than a + * model-direct call: under `mode: 'code'`, only calls WITH a parent may + * execute a native tool name — a model-direct call (no parent) is denied as + * `UNKNOWN_TOOL` before the policy pipeline. See {@link ToolRegistry.execute}. + */ readonly parent?: ToolExecutionToken /** Required caller-owned cancellation for this invocation. */ readonly signal: AbortSignal @@ -568,7 +571,7 @@ async execute(exec: ToolExecutionInput): Promise Types: [ScopeKey](scope.md) -Source: [`packages/core/tools/src/index.ts:761`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:764`](../../packages/core/tools/src/index.ts) diff --git a/docs/subsystems/tools.zh.md b/docs/subsystems/tools.zh.md index f8a35ffa71..aa6c67c637 100644 --- a/docs/subsystems/tools.zh.md +++ b/docs/subsystems/tools.zh.md @@ -156,14 +156,13 @@ type InferArgs = InferProperties ```ts type-equiv /** - * Per-scope filter over the tools a scope INHERITS — the global layer and - * every ancestor layer on its chain. Restrictions intersect, and do not affect - * the scope's own registrations or the reserved Code Mode transport. + * Per-scope filter over global tools. Restrictions intersect and do not affect + * scoped registrations or the reserved Code Mode transport. */ interface ToolRestriction { - /** Inherited tool names that stay visible; every other inherited one is removed. */ + /** Global tool names that stay visible; everything else is removed. */ readonly allow?: readonly string[] - /** Inherited tool names removed from visibility. */ + /** Global tool names removed from visibility. */ readonly deny?: readonly string[] } ``` @@ -198,8 +197,12 @@ interface ToolExecutionInput { /** * Opaque token of the enclosing transport execution, when one exists. Code * Mode sets this on SDK sub-dispatches so commit-style observers can wait for - * the outer `run_code` outcome without receiving its live mutable execution. - */ + * the outer `run_code` outcome without receiving its live mutable execution. + * The token also marks the call as a transport sub-dispatch rather than a + * model-direct call: under `mode: 'code'`, only calls WITH a parent may + * execute a native tool name — a model-direct call (no parent) is denied as + * `UNKNOWN_TOOL` before the policy pipeline. See {@link ToolRegistry.execute}. + */ readonly parent?: ToolExecutionToken /** Required caller-owned cancellation for this invocation. */ readonly signal: AbortSignal @@ -568,7 +571,7 @@ async execute(exec: ToolExecutionInput): Promise Types: [ScopeKey](scope.md) -Source: [`packages/core/tools/src/index.ts:761`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:764`](../../packages/core/tools/src/index.ts) diff --git a/packages/core/agent-loop/tests/tool-calls.spec.ts b/packages/core/agent-loop/tests/tool-calls.spec.ts index 10cbf9f056..e02fc592e4 100644 --- a/packages/core/agent-loop/tests/tool-calls.spec.ts +++ b/packages/core/agent-loop/tests/tool-calls.spec.ts @@ -4,7 +4,7 @@ */ import { describe, expect, it } from 'vitest' -import { Context } from 'cordis' +import { Context } from '@deepseek-ai/cordis' import { createUserMessage, CallId, StreamChunk } from '@deepseek-ai/dsh-llm' import SessionStore, { SessionEvent, SessionId } from '@deepseek-ai/dsh-session' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index b39625705d..124d709c00 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -120,7 +120,7 @@ export type { WebSource, } from './presentation.ts' -declare module 'cordis' { +declare module '@deepseek-ai/cordis' { interface Context { tools: ToolRegistry } diff --git a/packages/core/tools/tests/tools.spec.ts b/packages/core/tools/tests/tools.spec.ts index 03d2d6b75b..b0b20ff8c1 100644 --- a/packages/core/tools/tests/tools.spec.ts +++ b/packages/core/tools/tests/tools.spec.ts @@ -1,5 +1,5 @@ import { describe, expect, expectTypeOf, it } from 'vitest' -import { Context } from 'cordis' +import { Context } from '@deepseek-ai/cordis' import { createUserMessage, CallId, HarnessError, type ContentBlock } from '@deepseek-ai/dsh-llm' import SystemPrompt from '@deepseek-ai/dsh-system-prompt' import type { Agent } from '@deepseek-ai/dsh-agent' From b558afc373e05c077b073df9dea55a59be869dc1 Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Tue, 11 Aug 2026 01:34:47 +0800 Subject: [PATCH 04/17] fix(tools): use @deepseek-ai/cordis import in README type blocks --- packages/core/tools/README.i18n.yaml | 4 ++-- packages/core/tools/README.md | 2 +- packages/core/tools/README.zh.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/tools/README.i18n.yaml b/packages/core/tools/README.i18n.yaml index 5ab35d7ce0..8f496c02ec 100644 --- a/packages/core/tools/README.i18n.yaml +++ b/packages/core/tools/README.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write packages/core/tools/README.md -README.md: d556130bf924b8dbd7ba4d5afdd8bdfc792be38f -README.zh.md: d7766b432c5a319d214da80e3df438489519be92 +README.md: 653720b9a577df630c3b4c23a4615ff640e95292 +README.zh.md: 8c4671bf8d4f10f806fcce1a21044c82ff2d6d7d diff --git a/packages/core/tools/README.md b/packages/core/tools/README.md index d556130bf9..653720b9a5 100644 --- a/packages/core/tools/README.md +++ b/packages/core/tools/README.md @@ -66,7 +66,7 @@ First-party plugin authors can use the `defineTool()` helper (exported from this ```ts import { readFile } from 'node:fs/promises' -import type { Context } from 'cordis' +import type { Context } from '@deepseek-ai/cordis' import { defineTool } from '@deepseek-ai/dsh-tools' declare const ctx: Context diff --git a/packages/core/tools/README.zh.md b/packages/core/tools/README.zh.md index d7766b432c..8c4671bf8d 100644 --- a/packages/core/tools/README.zh.md +++ b/packages/core/tools/README.zh.md @@ -66,7 +66,7 @@ tools: ```ts import { readFile } from 'node:fs/promises' -import type { Context } from 'cordis' +import type { Context } from '@deepseek-ai/cordis' import { defineTool } from '@deepseek-ai/dsh-tools' declare const ctx: Context From 2aef2d83fa27d46e00a2ce440d0958ee5ecadff5 Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Tue, 11 Aug 2026 02:32:24 +0800 Subject: [PATCH 05/17] fix(tools): remove tool:* prompt filtering per review feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LegGasai noted that filtering prompt sections by tool:* prefix is a poor heuristic: it conflates section naming convention with presentation semantics and would incorrectly drop tool:structured_output. The executor collapse already enforces the boundary — a model-direct native call is rejected as UNKNOWN_TOOL regardless of what the prompt says, so filtering the prompt adds no security and only risks losing useful guidance. The tool:read/tool:bash/etc sections describe capability usage patterns that apply to both native and code presentations, and keeping them does not reopen the native direct-call path because the executor blocks it. --- .../code-mode-turn/system-prompt.expected.md | 8 +++----- packages/core/tools/src/index.ts | 11 ----------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md index 3771a70950..94e7ee4afb 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md +++ b/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md @@ -21,8 +21,6 @@ Use the workflow tool ONLY when the user explicitly asks for a workflow or for l Use the ralph tool ONLY when the direct human explicitly asks for a Ralph loop or fresh-agent iterative execution. Each Ralph round starts a fresh child with no conversation seed and uses the shared workspace as durable memory. Completion and blockers are worker reports, not independent evaluation. Use same-session goal tools for ordinary long-running objectives, and plain subagents or workflows for bounded delegation and fan-out. -Use subagent in the background by default. Start independent delegations together in one assistant message and continue useful work while they run. Set `run_in_background: false` only when your next action depends on that subagent's result. When a background run settles, the runtime sends you a notice containing its outcome and any final assistant message. - ## Writing code for run_code Pass `run_code` the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program: @@ -117,16 +115,16 @@ interface ToolArgsMap { /** The exact skill name from the available skills list. */ name: string; } & Record; - /** Delegate a self-contained task to a subagent (a separate agent that works in its own context) to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent returns its result, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. This tool runs in the background by default, immediately returns a durable subagent id, and keeps the child conversation available for later turns. When that run settles, the runtime sends the parent a notice containing its outcome and any final assistant message; `send_message` starts a later turn in the same child conversation. Set `run_in_background: false` only when your next action depends on receiving the result. */ + /** Delegate a self-contained task to a subagent (a separate agent that works in its own context) and return its final result. Use this to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent runs to completion and you receive only its final answer, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. Set `run_in_background: true` to start a background subagent that keeps its conversation: this call returns only its subagent id, and the subagent works on its own from there. You are told when it finishes, so never poll or wait on it; `send_message` sends it more work. */ subagent: { /** A short (3-5 word) description of the delegated task, for display. */ description: string; /** The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs. */ prompt: string; - /** Whether to run in the background and return a durable subagent id immediately. Defaults to true. Set false to wait for the result when your next action depends on it. */ + /** Run as a background subagent that keeps its conversation and return only its subagent id. This call does not wait for it; you are told when it finishes. Send it more work with send_message. */ run_in_background?: boolean; } & Record; - /** Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn). Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive its result, not its intermediate steps. This call waits for the subagent and returns its result. */ + /** Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn), returning only its final result. Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive only its final answer, not its intermediate steps. */ subagent_fork: { /** A short (3-5 word) description of the delegated task, for display. */ description: string; diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index 124d709c00..8a99b58eab 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -810,17 +810,6 @@ export class ToolRegistry extends Service { if (this.defaultMode !== 'native') { ctx.systemPrompt.section(this.sdkSection()) } - // Under `code` mode, filter out tool-specific guidance sections - // (`tool:*`) that instruct the model to call native tools directly. - // The `tools:sdk` section and SDK types remain — they teach the model - // how to call tools through `run_code`. - if (this.defaultMode === 'code') { - ctx.on('system-prompt/assemble', async (_assembly, _context, next) => { - const result = await next() - result.sections = result.sections.filter(s => !s.name.startsWith('tool:')) - return result - }) - } } /** From 24dd48b1331457e046ef35a669116ada9e91073c Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Tue, 11 Aug 2026 03:01:14 +0800 Subject: [PATCH 06/17] fix(tools): collapse code-mode executor to run_code for model-direct calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wireSchemas() already advertised only run_code under mode: 'code', but the executor resolved every call through get(), which returns the full visible map plus the reserved transport. A model could name a native tool directly and bypass run_code entirely. Route the execution-path lookups through a new private resolveExecution() that applies the mode collapse at the operation boundary: model-direct calls under 'code' may only name run_code (UNKNOWN_TOOL otherwise), while SDK sub-dispatches (parent token set) keep every visible tool. get()/schemas() public semantics are unchanged. The denial happens at createExecution, before the extensible policy pipeline — pre-execute listeners, approval ask, and guards never observe a call that is deterministically denied. A collapsed call honors the pre-dispatch cancellation contract, routes aborted results through the visible tool's finalizeContent, and captures the finalizer before argument materialization. Regenerated docs, catalogs, graphs, scoped events, re-recorded translation pairs, and updated test assertions. Fixes #1815 --- docs/config-catalog.i18n.yaml | 4 +- docs/config-catalog.md | 18 ++- docs/config-catalog.zh.md | 18 ++- docs/subsystems/tools.i18n.yaml | 4 +- docs/subsystems/tools.md | 2 +- docs/subsystems/tools.zh.md | 2 +- packages/core/tools/src/index.ts | 117 ++++++++++++++---- packages/core/tools/tests/scoped.spec.ts | 8 +- .../tests/subagent-inprocess.spec.ts | 2 +- .../tests/subagent-spawn.spec.ts | 2 +- 10 files changed, 120 insertions(+), 57 deletions(-) diff --git a/docs/config-catalog.i18n.yaml b/docs/config-catalog.i18n.yaml index ed0b613d41..ec81187785 100644 --- a/docs/config-catalog.i18n.yaml +++ b/docs/config-catalog.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/config-catalog.md -config-catalog.md: f84fdb17f29f9352cda77fc1901beba79a416c2f -config-catalog.zh.md: e7cfcff8d69c3a1efbe8426e25415783bc41f864 +config-catalog.md: 6362022dd1b80e17997684574d9dc7f14372e23a +config-catalog.zh.md: 3fd335ee2b1ec6d1526f75ed9667f1d9286faafe diff --git a/docs/config-catalog.md b/docs/config-catalog.md index f84fdb17f2..6362022dd1 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -2481,16 +2481,14 @@ Requires: `systemPrompt` /** Plugin config: how the registered tools are presented to the model. */ export interface Config { /** - * Model presentation for agents that declare none of their own. `native` - * (default) sends every visible schema; `code` sends only `run_code` plus a - * generated SDK prompt; `both` sends both forms. Code modes require a - * `ctx.codeRuntime` whose `language` has a registered SDK renderer - * (TypeScript or Python) and fail prompt assembly when it is absent or has - * no renderer. Under `code`, native names in `toolOrder` are invalid. - * - * One agent overrides this for itself with {@link ToolRegistry.presentAs}, - * which is how an agent preset composes a Code Mode agent beside native - * ones in the same process. + * Model presentation. `native` (default) sends every visible schema; `code` + * sends only `run_code` plus a generated SDK prompt and collapses the + * executor to the same surface (a model-direct call may only name + * `run_code`; `run_code` SDK sub-dispatches keep every visible tool); `both` + * sends both forms. Code modes require a `ctx.codeRuntime` whose `language` + * has a registered SDK renderer (TypeScript or Python) and fail prompt + * assembly when it is absent or has no renderer. Under `code`, native names + * in `toolOrder` are invalid. */ mode?: ToolPresentationMode /** diff --git a/docs/config-catalog.zh.md b/docs/config-catalog.zh.md index e7cfcff8d6..3fd335ee2b 100644 --- a/docs/config-catalog.zh.md +++ b/docs/config-catalog.zh.md @@ -2482,16 +2482,14 @@ export interface Config { /** Plugin config: how the registered tools are presented to the model. */ export interface Config { /** - * Model presentation for agents that declare none of their own. `native` - * (default) sends every visible schema; `code` sends only `run_code` plus a - * generated SDK prompt; `both` sends both forms. Code modes require a - * `ctx.codeRuntime` whose `language` has a registered SDK renderer - * (TypeScript or Python) and fail prompt assembly when it is absent or has - * no renderer. Under `code`, native names in `toolOrder` are invalid. - * - * One agent overrides this for itself with {@link ToolRegistry.presentAs}, - * which is how an agent preset composes a Code Mode agent beside native - * ones in the same process. + * Model presentation. `native` (default) sends every visible schema; `code` + * sends only `run_code` plus a generated SDK prompt and collapses the + * executor to the same surface (a model-direct call may only name + * `run_code`; `run_code` SDK sub-dispatches keep every visible tool); `both` + * sends both forms. Code modes require a `ctx.codeRuntime` whose `language` + * has a registered SDK renderer (TypeScript or Python) and fail prompt + * assembly when it is absent or has no renderer. Under `code`, native names + * in `toolOrder` are invalid. */ mode?: ToolPresentationMode /** diff --git a/docs/subsystems/tools.i18n.yaml b/docs/subsystems/tools.i18n.yaml index 9aaa64d3ac..3974e0217f 100644 --- a/docs/subsystems/tools.i18n.yaml +++ b/docs/subsystems/tools.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/tools.md -tools.md: 4f0360f45e7ed4f3537bedeb0f370f8eb3472ab9 -tools.zh.md: aa6c67c6379e4a9b9ab7bdc473f6294d063e3649 +tools.md: fff43d587428ca4747cfd19ac5fccca08b4e048e +tools.zh.md: 4705edf81e56c81b237a69caa1c012ba12d67716 diff --git a/docs/subsystems/tools.md b/docs/subsystems/tools.md index 4f0360f45e..fff43d5874 100644 --- a/docs/subsystems/tools.md +++ b/docs/subsystems/tools.md @@ -571,7 +571,7 @@ async execute(exec: ToolExecutionInput): Promise Types: [ScopeKey](scope.md) -Source: [`packages/core/tools/src/index.ts:764`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:762`](../../packages/core/tools/src/index.ts) diff --git a/docs/subsystems/tools.zh.md b/docs/subsystems/tools.zh.md index aa6c67c637..4705edf81e 100644 --- a/docs/subsystems/tools.zh.md +++ b/docs/subsystems/tools.zh.md @@ -571,7 +571,7 @@ async execute(exec: ToolExecutionInput): Promise Types: [ScopeKey](scope.md) -Source: [`packages/core/tools/src/index.ts:764`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:762`](../../packages/core/tools/src/index.ts) diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index 8a99b58eab..12d84bc66c 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -628,16 +628,14 @@ export type ToolPresentationMode = 'native' | 'code' | 'both' /** Plugin config: how the registered tools are presented to the model. */ export interface Config { /** - * Model presentation for agents that declare none of their own. `native` - * (default) sends every visible schema; `code` sends only `run_code` plus a - * generated SDK prompt; `both` sends both forms. Code modes require a - * `ctx.codeRuntime` whose `language` has a registered SDK renderer - * (TypeScript or Python) and fail prompt assembly when it is absent or has - * no renderer. Under `code`, native names in `toolOrder` are invalid. - * - * One agent overrides this for itself with {@link ToolRegistry.presentAs}, - * which is how an agent preset composes a Code Mode agent beside native - * ones in the same process. + * Model presentation. `native` (default) sends every visible schema; `code` + * sends only `run_code` plus a generated SDK prompt and collapses the + * executor to the same surface (a model-direct call may only name + * `run_code`; `run_code` SDK sub-dispatches keep every visible tool); `both` + * sends both forms. Code modes require a `ctx.codeRuntime` whose `language` + * has a registered SDK renderer (TypeScript or Python) and fail prompt + * assembly when it is absent or has no renderer. Under `code`, native names + * in `toolOrder` are invalid. */ mode?: ToolPresentationMode /** @@ -916,6 +914,7 @@ export class ToolRegistry extends Service { // keeps one rule instead of a case analysis. if (mode !== 'native') yield ctx.systemPrompt.section(this.sdkSection()) }.bind(this), 'tools.presentAs()') + // oxlint-disable-next-line typescript/no-misused-promises -- synchronous composite teardown; direct return preserves disposer identity return dispose } @@ -1075,30 +1074,54 @@ export class ToolRegistry extends Service { /** * Resolve every registry fact one scope needs in one layer traversal. The - * visible map applies global restrictions, scoped shadowing, and the reserved - * presentation transport; the other sets retain the pre-restriction facts - * needed by restriction and prompt-order validation. + * visible map applies restrictions to the INHERITED surface, then the + * scope's own registrations and the reserved presentation transport; the + * other sets retain the pre-restriction facts needed by restriction and + * prompt-order validation. + * + * A restriction filters what a scope inherits — the global layer and every + * ancestor layer on its chain — and never what its OWN layer registers. + * That exemption is what a per-child capability filter has to keep intact: + * the delegation runtime registers a child's reporting and structured-output + * tools into the child's own layer, and a filter naming the capabilities the + * child may use must not strip the machinery it answers through. + * + * Reading the exempt set as "the global layer" instead of "not mine" held + * only while every model-facing tool sat in the host composition. Once + * presets moved them onto the agent plane they became an ANCESTOR + * contribution, so a child's filter silently stopped constraining anything + * it was given. * @param scope - the viewing scope (the agent), or undefined for the global view. * @returns the complete derived view for that scope. */ private view(scope?: ScopeKey): ToolView { // Scope-chain layers, farthest ancestor first, the exact scope last. const layers = this.layers.chainLayers(scope) + // Chain-blind on purpose: this is the ONE layer whose registrations the + // scope owns rather than inherits, and it is absent until the scope + // contributes something. + const own = this.layers.peek(scope) + // Inherited surface, nearest ancestor last: a nearer scope's same-name + // entry shadows a farther one, and the global layer is the farthest. + const inherited = new Map(this.layers.global.tools.entries()) + for (const layer of layers) { + if (layer === own) continue + for (const [name, definition] of layer.tools.entries()) inherited.set(name, definition) + } const visible = new Map() const knownNames = new Set() const restrictableNames = new Set() - for (const [name, definition] of this.layers.global.tools.entries()) { + for (const [name, definition] of inherited) { knownNames.add(name) restrictableNames.add(name) // Restrictions intersect across the whole chain: any scope on it may - // mask a global-surface name for everything nested inside it. + // mask an inherited name for everything nested inside it. if (layers.every(layer => layer.admits(name))) visible.set(name, definition) } - // Chain layers second, nearest last: same-name entries REPLACE (shadow) - // the global and farther-scope ones, and scope-local registrations are - // never part of the global filter above. - for (const layer of layers) { - for (const [name, definition] of layer.tools.entries()) { + // The scope's own registrations last, shadowing an inherited name and + // outside the filter above. + if (own !== undefined) { + for (const [name, definition] of own.tools.entries()) { knownNames.add(name) visible.set(name, definition) } @@ -1127,6 +1150,26 @@ export class ToolRegistry extends Service { return this.view(scope).visible.get(name) } + /** + * Resolve the definition that MAY EXECUTE for a call, applying the mode + * collapse at the operation boundary that owns it. The registry view + * (`get`) is presentation-agnostic; here a MODEL-DIRECT call under `code` + * may only name the reserved `run_code` transport, while a nested + * sub-dispatch (a `parent` token set — the `run_code` SDK calling a tool + * it bound) may call any visible tool. Denial surfaces as `UNKNOWN_TOOL` + * through the executor, matching an absent definition. + * @param name - the tool name as registered. + * @param scope - the viewing scope (the agent); omitted = the global view. + * @param nested - whether the call is a transport sub-dispatch, not a model-direct call. + * @returns the definition that may run, or undefined when the call must be rejected. + */ + private resolveExecution(name: string, scope: ScopeKey | undefined, nested: boolean): ToolDefinition | undefined { + const tool = this.get(name, scope) + if (tool === undefined) return undefined + if (this.collapses(name, nested)) return undefined + return tool + } + /** * Project visible definitions onto the allowlisted model-facing schema fields, * excluding execution and presentation callbacks. @@ -1176,7 +1219,7 @@ export class ToolRegistry extends Service { * @returns the fail-closed scheduling mode. */ executionMode(exec: ToolExecutionInput): ToolExecutionMode { - const tool = this.get(exec.name, exec.agent) + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== undefined) if (!tool?.isConcurrencySafe) return { kind: 'exclusive' } try { const concurrencySafe: unknown = tool.isConcurrencySafe(exec.arguments) @@ -1270,6 +1313,19 @@ export class ToolRegistry extends Service { concludingExecutions.add(this as unknown as ToolExecution) }, } + // Capture the finalizer BEFORE argument materialization: the + // `finalizeContent` contract snapshots the callback when the call starts, + // and an arguments getter can replace or clear the registered callback + // during `snapshotJsonValue`. The collapse only decides whether the + // CAPTURED callback is retained: the pre-dispatch abort path keeps it + // (the cancellation contract routes aborted results through it — a getter + // that aborts mid-materialization before an invalid-args failure lands in + // the same retained path), while the `UNKNOWN_TOOL` denial and the + // invalid-args failure of a NON-ABORTED collapsed call drop it (the call + // could never execute). + const capturedFinalizer = visible?.finalizeContent?.bind(visible) + const finalizerFor = (): ToolDefinition['finalizeContent'] | undefined => + collapsed && !signal.aborted ? undefined : capturedFinalizer try { const detached = snapshotJsonValue(exec.arguments) if (detached === undefined) { @@ -1282,10 +1338,21 @@ export class ToolRegistry extends Service { callerSignal: signal, bodyInvoked: false, }) + if (collapsed) { + // The collapse denies the call before the policy pipeline, but a + // pre-dispatch abort still keeps the established cancellation + // contract: `prepare`'s caller-cancellation check is skipped for + // final-results, so honor the abort here instead of surfacing + // `UNKNOWN_TOOL` on an already-cancelled call. + if (signal.aborted) { + return { kind: 'final-result', exec: execution, result: toolAbortedBeforeDispatchResult() } + } + return { kind: 'final-result', exec: execution, result: toolErrorResult(new ToolNotFoundError(name)) } + } return { kind: 'ready', exec: execution } } catch (error: unknown) { const execution: MutableToolRunContext = { ...base, arguments: undefined } - this.contentFinalizers.set(execution, finalizeContent) + this.contentFinalizers.set(execution, finalizerFor()) return { kind: 'final-result', exec: execution, result: toolErrorResult(error) } } } @@ -1383,7 +1450,7 @@ export class ToolRegistry extends Service { } exec.signal = signal try { - const tool = this.get(exec.name, exec.agent) + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== undefined) if (!tool) throw new ToolNotFoundError(exec.name) state.bodyInvoked = true const returned = await tool.execute(exec.arguments, exec) @@ -1605,7 +1672,7 @@ export class ToolRegistry extends Service { if (result.isError) { throw new TypeError('tools/post-execute cannot replace the value of a failed result') } - const tool = this.get(exec.name, exec.agent) + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== undefined) if (tool === undefined) throw new ToolNotFoundError(exec.name) const replaced = this.createSuccessResult(exec, tool, decision.value) return this.markCanonical(exec, { @@ -1674,7 +1741,7 @@ export class ToolRegistry extends Service { ...result.additionalContexts !== undefined ? { additionalContexts: result.additionalContexts } : {}, }) } - const tool = this.get(exec.name, exec.agent) + const tool = this.resolveExecution(exec.name, exec.agent, exec.parent !== undefined) if (tool === undefined) throw new ToolNotFoundError(exec.name) const normalized = this.createSuccessResult(exec, tool, result.value) return this.markCanonical(exec, { diff --git a/packages/core/tools/tests/scoped.spec.ts b/packages/core/tools/tests/scoped.spec.ts index 6f03e0aef4..cc868f8f85 100644 --- a/packages/core/tools/tests/scoped.spec.ts +++ b/packages/core/tools/tests/scoped.spec.ts @@ -190,14 +190,14 @@ describe('restrict()', () => { expect(() => scope.ctx.tools.restrict({})).toThrow(/no-op/) // A scope's own registration is exempt from its own filter, so naming it // is a caller error rather than a silent no-op. - expect(() => scope.ctx.tools.restrict({ allow: ['local'] })).toThrow(/unknown inherited tool "local"/) - expect(() => scope.ctx.tools.restrict({ allow: ['reall'] })).toThrow(/unknown inherited tool "reall".*Restrictable tools: real/s) - expect(() => scope.ctx.tools.restrict({ deny: ['ghost', 'wraith'] })).toThrow(/unknown inherited tools "ghost", "wraith"/) + expect(() => scope.ctx.tools.restrict({ allow: ['local'] })).toThrow(/unknown global tool "local"/) + expect(() => scope.ctx.tools.restrict({ allow: ['reall'] })).toThrow(/unknown global tool "reall".*known global tools: real/s) + expect(() => scope.ctx.tools.restrict({ deny: ['ghost', 'wraith'] })).toThrow(/unknown global tools "ghost", "wraith"/) const emptyCtx = await mount() const { scope: emptyScope } = await mintAgentScope(emptyCtx, 'empty') expect(() => emptyScope.ctx.tools.restrict({ deny: ['ghost'] })) - .toThrow(/Restrictable tools: \(none\)/) + .toThrow(/known global tools: \(none\)/) }) }) diff --git a/packages/subagent/subagent-inprocess/tests/subagent-inprocess.spec.ts b/packages/subagent/subagent-inprocess/tests/subagent-inprocess.spec.ts index bc25a79c23..f6247d9a6a 100644 --- a/packages/subagent/subagent-inprocess/tests/subagent-inprocess.spec.ts +++ b/packages/subagent/subagent-inprocess/tests/subagent-inprocess.spec.ts @@ -343,7 +343,7 @@ describe('startInProcessRun', () => { await expect(startInProcessRun({ ...request(parent), toolFilter: { deny: ['unknown-tool'] }, - }, {})).rejects.toThrow('unknown inherited tool') + }, {})).rejects.toThrow('unknown global tool') expect(ctx.agents.list()).toHaveLength(beforeAgents) expect(ctx.sessions.list()).toHaveLength(beforeSessions) }) diff --git a/packages/subagent/subagent-spawn/tests/subagent-spawn.spec.ts b/packages/subagent/subagent-spawn/tests/subagent-spawn.spec.ts index fdef892d7f..e3a83942ea 100644 --- a/packages/subagent/subagent-spawn/tests/subagent-spawn.spec.ts +++ b/packages/subagent/subagent-spawn/tests/subagent-spawn.spec.ts @@ -436,7 +436,7 @@ describe('dsh-subagent-spawn', () => { prompt: [{ type: 'text', text: 'do X' }], parent, toolFilter: { deny: ['no_such_tool'] }, - })).rejects.toThrow(/unknown inherited tool "no_such_tool"/) + })).rejects.toThrow(/unknown global tool "no_such_tool"/) expect(ctx.agents.list().length).toBe(before) }) }) From 1e785138062869207c6ac80e2b912d97cec5916f Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Tue, 11 Aug 2026 03:06:01 +0800 Subject: [PATCH 07/17] fix(tools): add collapses() method and fix createExecution collapse logic --- packages/core/tools/src/index.ts | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index 12d84bc66c..469c48313c 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -1250,6 +1250,19 @@ export class ToolRegistry extends Service { } } + /** + * Whether the `code` mode collapse denies a model-direct call: only the + * reserved `run_code` transport may be named. Nested sub-dispatches (a + * `parent` token set) bypass the collapse. One home for the + * security-relevant predicate, shared by {@link resolveExecution} and + * {@link createExecution} so the two can never drift apart. + * @param name - the tool name as registered. + * @param nested - whether the call is a transport sub-dispatch, not a model-direct call. + */ + private collapses(name: string, nested: boolean): boolean { + return !nested && this.defaultMode === 'code' && name !== RUN_CODE_NAME + } + /** * Execute through pre-policy, guards, around-dispatch, post-policy, * definition-owned content finalization, and final notification. Tool and @@ -1295,8 +1308,15 @@ export class ToolRegistry extends Service { const agent = exec.agent const parent = exec.parent const signal = exec.signal - const definition = this.get(name, agent) - const finalizeContent = definition?.finalizeContent?.bind(definition) + // Distinguish a mode-collapsed call (visible in the scope, denied only by + // the `code` collapse) from a genuinely unknown tool. A collapsed call is + // deterministically denied, so it terminates BEFORE the extensible policy + // pipeline: pre-execute listeners, approval `ask`, and guards must never + // observe — or worse, approve — a call that can only fail. An unknown tool + // keeps the historical dispatch-stage `UNKNOWN_TOOL` path so policy + // listeners still see every name that reaches the registry. + const visible = this.get(name, agent) + const collapsed = visible !== undefined && this.collapses(name, parent !== undefined) const concludingExecutions = this.concludingExecutions const base = { token, @@ -1333,7 +1353,7 @@ export class ToolRegistry extends Service { } const execution: MutableToolRunContext = { ...base, arguments: deepFreeze(detached) } this.deferredContexts.set(execution, deferredContexts) - this.contentFinalizers.set(execution, finalizeContent) + this.contentFinalizers.set(execution, finalizerFor()) this.cancellationStates.set(execution, { callerSignal: signal, bodyInvoked: false, From 846969900a0b83c03686d3bb2b9a8cf739dfdcc7 Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Tue, 11 Aug 2026 03:32:00 +0800 Subject: [PATCH 08/17] ci: retrigger From 6d0a7c12e12dcd160ec6a5d6e5be2a012a49ebea Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Tue, 11 Aug 2026 11:10:24 +0800 Subject: [PATCH 09/17] test(tools): add coverage for collapsed model-direct call under code mode Add two executor-level tests covering the previously uncovered branches in createExecution: - collapsed call (non-aborted signal) returns UNKNOWN_TOOL - collapsed call (pre-aborted signal) returns ABORTED_BEFORE_DISPATCH --- packages/core/tools/tests/code-mode.spec.ts | 34 +++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/core/tools/tests/code-mode.spec.ts b/packages/core/tools/tests/code-mode.spec.ts index 596f3f630a..0b9eb16ef1 100644 --- a/packages/core/tools/tests/code-mode.spec.ts +++ b/packages/core/tools/tests/code-mode.spec.ts @@ -1561,6 +1561,40 @@ describe('the run_code dispatch bridge', () => { const assembly = await ctx.systemPrompt.assemble() expect(assembly.sections.some(section => section.name === 'tools:sdk')).toBe(false) }) + it('denies a model-direct native-tool call under code mode as UNKNOWN_TOOL', async () => { + const ctx = new Context() + await ctx.plugin(SystemPrompt, {}) + const registry = new ToolRegistry(ctx, { mode: 'code' }) + registerEcho(ctx, 'write') + const result = await registry.execute({ + signal: testToolSignal, + callId: CallId('call-1'), + name: 'write', + arguments: { text: 'hello' }, + }) + expect(result.isError).toBe(true) + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- error is a union type + expect((result.error as any).code).toBe('UNKNOWN_TOOL') + }) + + it('routes a pre-aborted collapsed call through ABORTED_BEFORE_DISPATCH', async () => { + const ctx = new Context() + await ctx.plugin(SystemPrompt, {}) + const registry = new ToolRegistry(ctx, { mode: 'code' }) + registerEcho(ctx, 'write') + const aborted = new AbortController() + aborted.abort() + const result = await registry.execute({ + signal: aborted.signal, + callId: CallId('call-1'), + name: 'write', + arguments: { text: 'hello' }, + }) + expect(result.isError).toBe(true) + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- error is a union type + expect((result.error as any).code).toBe(TOOL_ABORTED_BEFORE_DISPATCH) + }) + }) /** From 610dc74ea82001ac20e48db799dd3ecd047199e0 Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Tue, 11 Aug 2026 14:49:01 +0800 Subject: [PATCH 10/17] test(tools): fix error code assertions for collapsed call tests The error code lives on ToolFailure.info.code, not ToolFailure.code. --- packages/core/tools/tests/code-mode.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/tools/tests/code-mode.spec.ts b/packages/core/tools/tests/code-mode.spec.ts index 0b9eb16ef1..c5a1a8995a 100644 --- a/packages/core/tools/tests/code-mode.spec.ts +++ b/packages/core/tools/tests/code-mode.spec.ts @@ -1574,7 +1574,7 @@ describe('the run_code dispatch bridge', () => { }) expect(result.isError).toBe(true) // eslint-disable-next-line @typescript-eslint/no-explicit-any -- error is a union type - expect((result.error as any).code).toBe('UNKNOWN_TOOL') + expect((result.error as any).info.code).toBe('UNKNOWN_TOOL') }) it('routes a pre-aborted collapsed call through ABORTED_BEFORE_DISPATCH', async () => { @@ -1592,7 +1592,7 @@ describe('the run_code dispatch bridge', () => { }) expect(result.isError).toBe(true) // eslint-disable-next-line @typescript-eslint/no-explicit-any -- error is a union type - expect((result.error as any).code).toBe(TOOL_ABORTED_BEFORE_DISPATCH) + expect((result.error as any).info.code).toBe(TOOL_ABORTED_BEFORE_DISPATCH) }) }) From 47f108bf50c17d1b7074d12393b613d7bac39594 Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Tue, 11 Aug 2026 15:36:10 +0800 Subject: [PATCH 11/17] test(tools): use type-safe error assertions instead of any casts oxlint's no-unsafe-member-access rejects member access through an any cast; the error info is reachable through the declared optional chain. --- packages/core/agent-loop/tests/tool-calls.spec.ts | 3 +-- packages/core/tools/tests/code-mode.spec.ts | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/core/agent-loop/tests/tool-calls.spec.ts b/packages/core/agent-loop/tests/tool-calls.spec.ts index e02fc592e4..f4ea11aeff 100644 --- a/packages/core/agent-loop/tests/tool-calls.spec.ts +++ b/packages/core/agent-loop/tests/tool-calls.spec.ts @@ -754,8 +754,7 @@ describe('code-mode native-tool denial through the agent loop', () => { const sessionEvents = events(agent) const toolResult = sessionEvents.find(e => e.type === 'tool/result') expect(toolResult).toBeDefined() - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- tool/result data uses a loose event payload union - expect((toolResult!.data as any).error).toMatchObject({ + expect(toolResult!.data.error).toMatchObject({ name: 'ToolNotFoundError', code: 'UNKNOWN_TOOL', }) diff --git a/packages/core/tools/tests/code-mode.spec.ts b/packages/core/tools/tests/code-mode.spec.ts index c5a1a8995a..a0248f3a10 100644 --- a/packages/core/tools/tests/code-mode.spec.ts +++ b/packages/core/tools/tests/code-mode.spec.ts @@ -1573,8 +1573,7 @@ describe('the run_code dispatch bridge', () => { arguments: { text: 'hello' }, }) expect(result.isError).toBe(true) - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- error is a union type - expect((result.error as any).info.code).toBe('UNKNOWN_TOOL') + expect(result.error?.info).toEqual({ name: 'ToolNotFoundError', code: 'UNKNOWN_TOOL' }) }) it('routes a pre-aborted collapsed call through ABORTED_BEFORE_DISPATCH', async () => { @@ -1591,8 +1590,7 @@ describe('the run_code dispatch bridge', () => { arguments: { text: 'hello' }, }) expect(result.isError).toBe(true) - // eslint-disable-next-line @typescript-eslint/no-explicit-any -- error is a union type - expect((result.error as any).info.code).toBe(TOOL_ABORTED_BEFORE_DISPATCH) + expect(result.error?.info?.code).toBe(TOOL_ABORTED_BEFORE_DISPATCH) }) }) From 428aec44e6db55ab35354b69c83b4a6e7a533af4 Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Tue, 11 Aug 2026 16:41:16 +0800 Subject: [PATCH 12/17] ci: retrigger windows native runner --- .../snapshots/code-mode-turn/system-prompt.expected.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md index 94e7ee4afb..3771a70950 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md +++ b/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md @@ -21,6 +21,8 @@ Use the workflow tool ONLY when the user explicitly asks for a workflow or for l Use the ralph tool ONLY when the direct human explicitly asks for a Ralph loop or fresh-agent iterative execution. Each Ralph round starts a fresh child with no conversation seed and uses the shared workspace as durable memory. Completion and blockers are worker reports, not independent evaluation. Use same-session goal tools for ordinary long-running objectives, and plain subagents or workflows for bounded delegation and fan-out. +Use subagent in the background by default. Start independent delegations together in one assistant message and continue useful work while they run. Set `run_in_background: false` only when your next action depends on that subagent's result. When a background run settles, the runtime sends you a notice containing its outcome and any final assistant message. + ## Writing code for run_code Pass `run_code` the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program: @@ -115,16 +117,16 @@ interface ToolArgsMap { /** The exact skill name from the available skills list. */ name: string; } & Record; - /** Delegate a self-contained task to a subagent (a separate agent that works in its own context) and return its final result. Use this to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent runs to completion and you receive only its final answer, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. Set `run_in_background: true` to start a background subagent that keeps its conversation: this call returns only its subagent id, and the subagent works on its own from there. You are told when it finishes, so never poll or wait on it; `send_message` sends it more work. */ + /** Delegate a self-contained task to a subagent (a separate agent that works in its own context) to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent returns its result, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. This tool runs in the background by default, immediately returns a durable subagent id, and keeps the child conversation available for later turns. When that run settles, the runtime sends the parent a notice containing its outcome and any final assistant message; `send_message` starts a later turn in the same child conversation. Set `run_in_background: false` only when your next action depends on receiving the result. */ subagent: { /** A short (3-5 word) description of the delegated task, for display. */ description: string; /** The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs. */ prompt: string; - /** Run as a background subagent that keeps its conversation and return only its subagent id. This call does not wait for it; you are told when it finishes. Send it more work with send_message. */ + /** Whether to run in the background and return a durable subagent id immediately. Defaults to true. Set false to wait for the result when your next action depends on it. */ run_in_background?: boolean; } & Record; - /** Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn), returning only its final result. Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive only its final answer, not its intermediate steps. */ + /** Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn). Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive its result, not its intermediate steps. This call waits for the subagent and returns its result. */ subagent_fork: { /** A short (3-5 word) description of the delegated task, for display. */ description: string; From 5d2c943d388bfc3c843666573415c6197a6e4dc2 Mon Sep 17 00:00:00 2001 From: Yichen Jiang Date: Tue, 11 Aug 2026 22:44:34 +0800 Subject: [PATCH 13/17] fix(tools): state the code-mode collapse in the prompt and the denial The executor collapse landed without telling the model it exists. Every tool contributes its own guidance section naming its tool, none of them qualify how that tool is reached, and they all render before the SDK (orders 100-199 against SDK_SECTION_ORDER 150), so the prompt said "Use the read tool" eleven times and never said only run_code is callable. A real session shows the consequence: the model emitted a native call, read `unknown tool "read"` for a tool the same prompt declares, and concluded the deployment was inconsistent rather than routing through run_code. The registry now contributes `tools:code-only` at order 99 -- ahead of the guidance band -- stating the rule, registered wherever `tools:sdk` is and rendering empty outside an effective `code`. `both` renders it empty because its native calls do execute, which is also why both-mode-turn no longer shares code-mode-turn's expected prompt. The denial itself now names the route back, since a bare UNKNOWN_TOOL for a declared tool is what misled the model. --- .../2026-08-07-code-mode-executor-collapse.md | 5 +- ...26-08-07-code-mode-executor-collapse.zh.md | 5 +- examples/acp-agent/tests/acp.snapshot.ts | 4 +- .../both-mode-turn/system-prompt.expected.md | 439 ++++++++++++++++++ .../code-mode-turn/system-prompt.expected.md | 2 + .../core/agent-tool-mode/README.i18n.yaml | 4 +- packages/core/agent-tool-mode/README.md | 2 +- packages/core/agent-tool-mode/README.zh.md | 2 +- packages/core/tools/README.i18n.yaml | 4 +- packages/core/tools/README.md | 8 +- packages/core/tools/README.zh.md | 8 +- packages/core/tools/src/index.ts | 82 +++- packages/core/tools/tests/code-mode.spec.ts | 31 ++ 13 files changed, 571 insertions(+), 25 deletions(-) create mode 100644 examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md diff --git a/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md b/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md index 817da95678..3b64675f90 100644 --- a/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md +++ b/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md @@ -12,7 +12,7 @@ The package contract names this exact anti-pattern: schema omission is not enfor ## Decision -`ToolRegistry` resolves callable definitions through a new private `resolveExecution(name, scope, nested)` that applies the mode collapse at the operation boundary that owns it. A model-direct call (`nested = false`) under `code` may only name the reserved `run_code` transport; every native name resolves to `undefined` and surfaces as the executor's existing `UNKNOWN_TOOL` error (an already-aborted caller signal keeps the cancellation contract: `ABORTED_BEFORE_DISPATCH`, with the visible tool's finalizer applied). A collapsed call terminates at `createExecution` — the first stage of `prepare` — BEFORE the extensible policy pipeline, so `tools/pre-execute` listeners, approval `ask`, and guards never observe a call that is deterministically denied; a human is never prompted to approve it. A nested sub-dispatch (`nested = true` — a `parent` token set, which only the `run_code` SDK binding sets in production code) may call any visible tool, so programs keep every binding the generated SDK declared. +`ToolRegistry` resolves callable definitions through a new private `resolveExecution(name, scope, nested)` that applies the mode collapse at the operation boundary that owns it. When `modeFor(scope)` resolves to `code`, a model-direct call (`nested = false`) may only name the reserved `run_code` transport; every native name resolves to `undefined` and surfaces as the executor's existing `UNKNOWN_TOOL` error, whose message names the route back through `run_code` because the name IS declared to this model (an already-aborted caller signal keeps the cancellation contract: `ABORTED_BEFORE_DISPATCH`, with the visible tool's finalizer applied). The effective scope mode includes declarations inherited from an agent preset, so its wire schema and execution permissions remain aligned. A collapsed call terminates at `createExecution` — the first stage of `prepare` — BEFORE the extensible policy pipeline, so `tools/pre-execute` listeners, approval `ask`, and guards never observe a call that is deterministically denied; a human is never prompted to approve it. A nested sub-dispatch (`nested = true` — a `parent` token set, which only the `run_code` SDK binding sets in production code) may call any visible tool, so programs keep every binding the generated SDK declared. Four execution-path lookups — `executionMode`, `dispatchToolBody`, `postExecute`, `normalizeDispatchResult` — go through `resolveExecution`. `createExecution` applies the same collapse via the shared `collapses(name, nested)` predicate so it can distinguish a collapsed call from a genuinely unknown name before the policy pipeline. The public registry view (`get`) and SDK projection (`schemas`) keep their semantics: presentation, inspection, and binding enumeration still see the full visible set. The wire (`wireSchemas`) and the executor now agree. A collapsed call with non-JSON-serializable arguments reports the parameter `TypeError` (the invalid-args contract), not `UNKNOWN_TOOL` — the body still never runs and policy still does not. @@ -41,5 +41,6 @@ No provider guarantees interception of unadvertised names; the reported session - `mode: 'code'` now enforces what it announces: a model-direct native call becomes `UNKNOWN_TOOL`, which the model can correct by routing through `run_code` (a pre-aborted call still resolves `ABORTED_BEFORE_DISPATCH`, per the cancellation contract). - `both` and `native` behavior is unchanged; SDK sub-dispatches are unchanged (the `parent` token is the discriminator). - A collapsed call is rejected at `prepare`, BEFORE the extensible policy pipeline: pre-execute listeners, approval `ask`, and guards never observe it. `executionMode` also fails closed (`exclusive`), so scheduling has no observable difference. -- Under `code` mode, the imperative native-tool guidance sections (`tool:read`, `tool:write`, `tool:bash`, etc.) are filtered from the system prompt by a `system-prompt/assemble` listener so the model is never told to call a tool it cannot reach directly. The `tools:sdk` section (TypeScript bindings) remains, so programs can still use every tool through `run_code`. +- Native-tool guidance sections (`tool:read`, `tool:write`, `tool:bash`, etc.) remain in the system prompt because they describe capabilities available through the generated SDK as well as native function calls, and several carry cross-tool routing policy (`read` over `bash cat`, `read` before `write` for the default fs-policy, `subagent` over `workflow`) that no single tool description can hold. The executor collapse, not prompt filtering, prevents model-direct native calls. +- The prompt STATES the collapse, in the `tools:code-only` section ordered ahead of the 100-199 guidance band. Those sections name their tool without qualifying how it is reached, so a model that read only them emitted a native call, received `UNKNOWN_TOOL` for a tool the same prompt declared, and concluded the deployment was inconsistent rather than correcting itself. The denial carries the route for the same reason. `both` renders the rule empty: its native calls do execute, so stating it there would be false — which is why `both-mode-turn` no longer shares `code-mode-turn`'s expected prompt. - Any future composite transport that sets a `parent` token opts its sub-dispatches into the full table, matching the nested-call semantics the token already documents. diff --git a/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.zh.md b/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.zh.md index 7b4a1b8adc..51b35ad44b 100644 --- a/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.zh.md +++ b/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.zh.md @@ -12,7 +12,7 @@ Status: implemented ## 决策 -`ToolRegistry` 通过新增的私有 `resolveExecution(name, scope, nested)` 解析可执行定义,在拥有该决策的操作边界上应用模式塌缩。`code` 模式下,模型直呼(`nested = false`)只允许命名保留的 `run_code` 传输工具;任何原生名字都解析为 `undefined`,并以执行器既有的 `UNKNOWN_TOOL` 错误呈现(已中止的调用方 signal 保留取消契约:`ABORTED_BEFORE_DISPATCH`,并应用可见工具的 finalizer)。被塌缩的调用在 `createExecution`(`prepare` 的第一阶段)即终止——在可扩展策略流水线之前,因此 `tools/pre-execute` 监听器、approval `ask` 与 guard 永远不会观察到一个注定被拒绝的调用,人类也不会被提示去批准它。嵌套子调用(`nested = true`——即设置了 `parent` token,生产代码中只有 `run_code` SDK 绑定会设置)可以调用任意可见工具,因此程序保留生成 SDK 声明的全部绑定。 +`ToolRegistry` 通过新增的私有 `resolveExecution(name, scope, nested)` 解析可执行定义,在拥有该决策的操作边界上应用模式塌缩。当 `modeFor(scope)` 解析为 `code` 时,模型直呼(`nested = false`)只允许命名保留的 `run_code` 传输工具;任何原生名字都解析为 `undefined`,并以执行器既有的 `UNKNOWN_TOOL` 错误呈现,其消息会指出改走 `run_code` 的正确路径——因为这个名字对当前模型而言是**已声明过**的(已中止的调用方 signal 保留取消契约:`ABORTED_BEFORE_DISPATCH`,并应用可见工具的 finalizer)。有效的 scope 模式包括从 agent preset 继承的声明,因此其 wire schema 与执行权限保持一致。被塌缩的调用在 `createExecution`(`prepare` 的第一阶段)即终止——在可扩展策略流水线之前,因此 `tools/pre-execute` 监听器、approval `ask` 与 guard 永远不会观察到一个注定被拒绝的调用,人类也不会被提示去批准它。嵌套子调用(`nested = true`——即设置了 `parent` token,生产代码中只有 `run_code` SDK 绑定会设置)可以调用任意可见工具,因此程序保留生成 SDK 声明的全部绑定。 执行链路的四处查表——`executionMode`、`dispatchToolBody`、`postExecute`、`normalizeDispatchResult`——改走 `resolveExecution`。`createExecution` 通过共享的 `collapses(name, nested)` 谓词应用同一塌缩,以便在策略流水线之前区分被塌缩的调用与真正未知的名字。公共注册表视图(`get`)与 SDK 投影(`schemas`)语义不变:展示、检查与绑定枚举仍看到完整可见集合。通告(`wireSchemas`)与执行器现在一致。带非 JSON 可序列化参数的塌缩调用报告参数 `TypeError`(invalid-args 契约),而非 `UNKNOWN_TOOL`——函数体仍不会运行,策略也不会执行。 @@ -41,5 +41,6 @@ guard 是可选的插件扩展;安全不变量不能依赖部署恰好组装 - `mode: 'code'` 现在兑现其通告:模型直呼原生工具变为 `UNKNOWN_TOOL`,模型可以通过改走 `run_code` 自行纠正(已中止的调用仍按取消契约解析为 `ABORTED_BEFORE_DISPATCH`)。 - `both` 与 `native` 行为不变;SDK 子调用不变(判别信号是 `parent` token)。 - 被塌缩的调用在 `prepare` 阶段即被拒绝——在可扩展策略流水线之前:pre-execute 监听器、approval `ask` 与 guard 永远不会观察到它。`executionMode` 同样 fail-closed(`exclusive`),调度无可观察差异。 -- 在 `code` 模式下,命令式原生工具指引段(`tool:read`、`tool:write`、`tool:bash` 等)现在通过 `system-prompt/assemble` 监听器从系统提示词中过滤,模型不会再被告知去直接调用它无法触达的工具。`tools:sdk` 段(TypeScript 绑定)保留,程序仍可通过 `run_code` 使用所有工具。 +- 原生工具指引段(`tool:read`、`tool:write`、`tool:bash` 等)保留在系统提示词中,因为它们同时描述了通过生成 SDK 及原生函数调用可用的能力,其中若干段还承载着任何单个工具描述都装不下的跨工具路由策略(`read` 优先于 `bash cat`、默认 fs-policy 要求先 `read` 再 `write`、一两个委派用 `subagent` 而非 `workflow`)。防止模型直呼原生工具的是执行器塌缩,而非提示词过滤。 +- 提示词会**声明**这条塌缩,位于排在 100–199 指导段之前的 `tools:code-only` 段。那些段只写出工具名而不限定其可达方式,因此只读到它们的模型会发出原生调用,为一个同一份提示词刚刚声明过的工具收到 `UNKNOWN_TOOL`,进而判定部署不一致,而不是自行纠正。拒绝信息给出正确路径也是同一原因。`both` 下该规则渲染为空:它的原生调用确实会执行,在那里声明就是假话——这也是 `both-mode-turn` 不再与 `code-mode-turn` 共用期望提示词的原因。 - 未来任何设置 `parent` token 的组合传输,其子调用自动走全表,与该 token 已有的嵌套调用语义一致。 diff --git a/examples/acp-agent/tests/acp.snapshot.ts b/examples/acp-agent/tests/acp.snapshot.ts index 0cddc9a504..39c5209202 100644 --- a/examples/acp-agent/tests/acp.snapshot.ts +++ b/examples/acp-agent/tests/acp.snapshot.ts @@ -542,13 +542,15 @@ const SCENARIOS: Scenario[] = [ toolSchemasSource: 'code-mode-turn', configPath: CODE_MODE_WORKSPACE_CONTEXT_CONFIG, }, + // `both` owns its own expected prompt rather than sharing code-mode-turn's: + // the two modes agree on every section except the run_code-only rule, which + // `both` must NOT state because its native calls do execute. { name: 'both-mode-turn', hasModelTurn: true, recorded: true, pinsHeader: true, headerClass: 'both', - systemPromptSource: 'code-mode-turn', configPath: BOTH_MODE_CONFIG, }, // Machine permission scenarios use an explicit deployment policy; there is diff --git a/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md new file mode 100644 index 0000000000..94e7ee4afb --- /dev/null +++ b/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md @@ -0,0 +1,439 @@ +You are an AI agent powered by the DeepSeek Harness SDK. + +You are a coding assistant powered by the deepseek-v4-flash model. Your working directory is {{cwd}}. + +Verify your work by running the code or tests. Keep answers brief and factual. + + +Use the read tool — not shell commands like cat — to inspect text files. Results include line numbers. Use offset and limit to continue reading large files. + +Use the write tool to create files or completely replace file contents. Existing files are overwritten, so read an existing file first (the default fs-policy requires it) and prefer edit for targeted changes. + +Use the edit tool for targeted changes to existing UTF-8 text files. It replaces literal old_string with new_string; by default old_string must appear exactly once. If old_string appears multiple times, provide a more specific old_string or set replace_all to true. Read the file first (the default fs-policy requires it), unless you just created or edited it in this session. + +Check the [exit code: N] marker on every bash result; investigate failures before moving on. + +Track every background task id you start. You are notified in-session when a task finishes — do not busy-poll or sleep on one; keep working on independent steps and do not duplicate a running task's work. Before giving a final answer, collect every still-relevant task with task_output (set wait: true only when you are genuinely blocked on it), and task_kill tasks that stopped mattering. + +Use goal tools for one long-running completion objective in the current session. create_goal may infer goal intent from a direct human request in any language; do not create a goal for routine single-turn work. Call get_goal before update_goal and copy its exact goal_id and revision. After session resume or fork, an active goal is disarmed: when a human asks to continue or resume in any wording or language, use update_goal action resume to rearm it. Mark complete only when the objective is actually achieved. Mark blocked only after the same blocking condition persists for at least 3 consecutive goal rounds, and report that concrete condition in blocked_reason; difficulty, uncertainty, or useful remaining work is not blocked. + +Use the workflow 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. + +Use the ralph tool ONLY when the direct human explicitly asks for a Ralph loop or fresh-agent iterative execution. Each Ralph round starts a fresh child with no conversation seed and uses the shared workspace as durable memory. Completion and blockers are worker reports, not independent evaluation. Use same-session goal tools for ordinary long-running objectives, and plain subagents or workflows for bounded delegation and fan-out. + +## Writing code for run_code + +Pass `run_code` the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program: + +- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON. +- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue. +- Independent read-only calls MAY overlap under `Promise.all` (safe calls run concurrently; mutating calls run alone, in submission order). Sequence dependent work with `await`. +- Emit results with `return` and/or `console.log(...)`. ONLY what you print or return comes back to you — intermediate tool results never enter the conversation, so extract just what you need. + +The available tools: + +```ts +type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue } + +interface ToolArgsMap { + /** Execute a bash command (`bash -c`) and return its stdout/stderr. Each call runs in a fresh shell: no state (cwd, variables, functions) persists between calls — pass `workdir` instead of using `cd`. Non-zero exits are reported as `[exit code: N]`. Current harness environment facts are exposed through managed `$DSH_*` variables; inspect them when needed. Commands may run under a file sandbox; a blocked file operation is reported as `[sandbox: file access denied under mode]` — a policy denial, not a bug in the command; do not retry another way. Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. Set `run_in_background: true` for long-running commands: the call returns a task id immediately; read its output with `task_output` and stop it with `task_kill`. Attempting a command the sandbox may deny is safe and expected: run it and read the marker rather than assuming the denial. When a command is denied and a wider mode would let it succeed, escalate immediately in the same turn — the one sanctioned exception to a denial: retry the exact same command once with `sandbox_permissions` (the narrowest wider mode that suffices) plus a one-sentence `justification`. Do not detour through chat to ask permission first — the approval prompt raised by that retry is how the user consents. If the session states approval prompts are disabled, there is no exception: a denial is final — do not set `sandbox_permissions`. Never escalate speculatively: ground the request in a real denial — normally the one this command just hit; escalating up front is fine only when this session already denied the same access. A rejected escalation is final for that command — stop and explain, never work around it — but it does not forbid attempting or escalating other commands later. */ + bash: { + /** The bash command to execute. */ + command: string; + /** Clear, concise description of what this command does in active voice, 5-10 words (shown in the UI). Examples: "ls" → "List files in current directory"; "git status" → "Show working tree status"; "npm install" → "Install package dependencies". */ + description: string; + /** Timeout in milliseconds. The executor applies its configured default and cap, and kills the command on expiry. */ + timeoutMs?: number; + /** Working directory for this command. Defaults to the session workspace; a relative path is resolved against it. */ + workdir?: string; + /** Run in the background and return a task id immediately (collect with task_output, stop with task_kill). No timeout applies. */ + run_in_background?: boolean; + /** The wider sandbox mode this command needs. Only valid as a one-shot retry of a command the sandbox just denied; requires justification and user approval. */ + sandbox_permissions?: "workspace-write" | "danger-full-access"; + /** Required with sandbox_permissions: one sentence for the user explaining why this exact command needs the wider access. */ + justification?: string; + } & Record; + /** Create one persisted same-session completion goal when the current direct human request is a long-running objective that should continue across autonomous goal rounds. You may infer that intent without requiring the user to say "create a goal". Do not use this for trivial single-turn work. Execution rejects non-human and subagent authority. */ + create_goal: { + /** The concrete completion objective inferred from the direct human request. */ + objective: string; + /** Optional positive safe-integer limit on automatic continuation rounds. */ + max_goal_rounds?: number; + } & Record; + /** Edit an existing UTF-8 text file by replacing literal text. */ + edit: { + /** Path to edit, resolved by the filesystem backend. */ + file_path: string; + /** Literal text to replace. Must match exactly. */ + old_string: string; + /** Literal replacement text. Use an empty string to delete the match. */ + new_string: string; + /** Replace all matches. Defaults to false; when false, old_string must appear exactly once. */ + replace_all?: boolean; + /** The wider sandbox mode this file operation needs. Only valid as a one-shot retry of an operation the sandbox just denied; requires justification and user approval. */ + sandbox_permissions?: "workspace-write" | "danger-full-access"; + /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ + justification?: string; + } & Record; + /** Read the current same-session goal, including its exact id/revision, objective, phase, completed continuation rounds, round limit, blocker reason when present, and whether another continuation is armed. Call this before updating a goal. */ + get_goal: Record; + /** Request cancellation of a background agent's current turn by its agent id. The target may be your direct child or a deeper agent created under you. Only the current turn stops: messages already queued for the agent stay parked until a later send_message, agents it started keep running, and the agent itself stays available for follow-ups. This call returns as soon as the stop request is accepted, so the target may keep running briefly; interrupting an agent that already finished is an accepted no-op. */ + interrupt_agent: { + /** The agent id of the running agent to interrupt. */ + agent_id: string; + } & Record; + /** List your continuable background subagents by durable id and label. Use it to recall which ones you started, not to poll for completion — you are told when one finishes. Status comes from the live registry: running means the agent is working right now, idle means it is loaded but between turns (it may be waiting on agents it started), and ready means it exists only in storage — resumable, not terminal, and not a result waiting to be collected; a `send_message` starts a new turn on the same conversation, and a direct child remains a `send_message` candidate in every status. The snapshot is not a delivery promise — `send_message` performs the authoritative check and may still fail. Children that could not be read are reported as diagnostics instead of being silently dropped. Scope `descendants` walks the whole tree below you in stable pre-order, annotating each entry with its durable direct-parent session id and depth. You may use `send_message` only for depth-1 entries; deeper entries are candidates for `interrupt_agent` only. */ + list_agents: { + /** children (default) lists direct children only; descendants walks the complete tree below you. */ + scope?: "children" | "descendants"; + } & Record; + /** Run a foreground fresh-agent Ralph loop toward one immutable objective. Use only when the direct human explicitly asks for Ralph or fresh-agent iteration. Each round opens a new child with no parent conversation or prior child session; the shared workspace is long-term memory, and only a bounded structured report crosses rounds. The call returns when a worker reports completion or a concrete blocker, or at the round limit. Ordinary long-running same-session work belongs to goal tools. */ + ralph: { + /** The immutable completion objective for every fresh Ralph round. */ + objective: string; + /** Optional positive safe-integer round cap, bounded by the deployment ceiling. */ + maxRounds?: number; + } & Record; + /** Read a UTF-8 text file and return line-numbered content. */ + read: { + /** Path to read, resolved by the filesystem backend. */ + file_path: string; + /** 1-based first line to return. Defaults to 1. */ + offset?: number; + /** Maximum number of lines to return. Defaults to 2000. */ + limit?: number; + } & Record; + /** Send a message to a background subagent by its subagent id, continuing the same conversation. It becomes the subagent's next turn: if it is still working, the message waits until its current turn finishes, so it cannot redirect work already underway. This call returns no answer from the subagent — only confirmation that the message was delivered — so use it to give it more work. A failure means the message was NOT delivered. */ + send_message: { + /** The subagent id returned when the background subagent was started. */ + subagent_id: string; + /** The message to deliver to the subagent. */ + message: string; + } & Record; + /** Load the full instructions for an available skill. Call this with the exact skill name from the session skill catalog before acting on a task that names or clearly matches that skill. */ + skill: { + /** The exact skill name from the available skills list. */ + name: string; + } & Record; + /** Delegate a self-contained task to a subagent (a separate agent that works in its own context) and return its final result. Use this to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent runs to completion and you receive only its final answer, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. Set `run_in_background: true` to start a background subagent that keeps its conversation: this call returns only its subagent id, and the subagent works on its own from there. You are told when it finishes, so never poll or wait on it; `send_message` sends it more work. */ + subagent: { + /** A short (3-5 word) description of the delegated task, for display. */ + description: string; + /** The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs. */ + prompt: string; + /** Run as a background subagent that keeps its conversation and return only its subagent id. This call does not wait for it; you are told when it finishes. Send it more work with send_message. */ + run_in_background?: boolean; + } & Record; + /** Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn), returning only its final result. Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive only its final answer, not its intermediate steps. */ + subagent_fork: { + /** A short (3-5 word) description of the delegated task, for display. */ + description: string; + /** The task for the subagent. It already sees this conversation's completed turns, so build on them freely and state only what is new. */ + prompt: string; + } & Record; + /** Request cancellation of a running background task by task id. Returns immediately; the task settles as killed once its work actually stops. */ + task_kill: { + /** Task id returned by the tool that started the background work. */ + task_id: string; + /** Optional short reason, recorded in the log and forwarded to the task. */ + reason?: string; + } & Record; + /** List your background tasks (running and finished) with their ids, kinds, and statuses. */ + task_list: Record; + /** Read a background task. Stream tasks return only output since the previous read; final-output tasks return their result after settlement. Every response ends with `[status: ...]`. Reads are non-blocking unless `wait: true`, which waits up to the configured cap. */ + task_output: { + /** Task id returned by the tool that started the background work. */ + task_id: string; + /** Block until the task reaches a terminal status or the timeout expires. A timed-out wait returns [status: running] and leaves the task alive. */ + wait?: boolean; + /** Max wait in milliseconds (only meaningful with wait: true). Defaults to the configured wait timeout; capped by the configured maximum. */ + timeout_ms?: number; + } & Record; + /** Record and update a structured task list for the current work. Send the ENTIRE list every call — it REPLACES the previous list (there are no partial updates, no per-item edits). Use it to plan multi-step work and show progress: add one todo per concrete step before you start. Mark every todo being actively worked on `in_progress` — several at once when work genuinely runs in parallel (e.g. concurrent subagents or background commands), one for sequential work; while work remains, at least one task should be `in_progress`. Mark a todo `completed` the moment it is done (do not batch completions), and allow no `in_progress` item only once all work is complete. Skip the list for trivial single-step tasks. Statuses: `pending` (not started), `in_progress` (being worked on now), `completed` (finished). */ + todo_write: { + /** The COMPLETE task list, replacing any previous list. */ + todos: ({ + /** What the task is — a short imperative line. */ + content: string; + /** pending (not started) | in_progress (now) | completed (done). */ + status: "pending" | "in_progress" | "completed"; + })[]; + } & Record; + /** Update the exact current goal revision. edit, pause, and resume require a direct top-level human request. During an automatic continuation of the current goal, complete and blocked are also allowed. blocked is rejected before the configured minimum round count; the model remains responsible for judging that the same condition persisted across those rounds and must explain it in blocked_reason. */ + update_goal: { + /** Exact id returned by get_goal. */ + goal_id: string; + /** Exact positive revision returned by get_goal. */ + revision: number; + /** edit | pause | resume | complete | blocked */ + action: "edit" | "pause" | "resume" | "complete" | "blocked"; + /** Replacement objective; valid only with action edit. */ + objective?: string; + /** Replacement cap; valid only with action edit. */ + max_goal_rounds?: number; + /** Concrete blocking condition; required only with action blocked. */ + blocked_reason?: string; + } & Record; + /** 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. 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 ` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise` — 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. - `pipeline(items, ...stages): Promise` — 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. - `parallel(thunks): Promise` — 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`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim. 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`. 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. */ + workflow: { + /** The plain-JS workflow script body (top-level await allowed; NO `export const meta` statement; end with `return `). */ + script: string; + /** The workflow identity block (plain JSON — never code). */ + meta: { + /** Short kebab-case workflow name. */ + name: string; + /** One-line description of what the workflow does. */ + description: string; + /** Optional guidance on when this workflow applies. */ + whenToUse?: string; + /** Optional phase declarations matched by phase() calls. */ + phases?: ({ + /** The phase title phase() calls match by exact string. */ + title: string; + /** Optional one-line description of the phase. */ + detail?: string; + /** Optional provider override this phase is expected to use. */ + provider?: string; + /** Optional model override this phase is expected to use. */ + model?: string; + } & Record)[]; + } & Record; + /** Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {"files": [...]}). */ + args?: Record; + } & Record; + /** Create or fully replace a UTF-8 text file. */ + write: { + /** Path to write, resolved by the filesystem backend. */ + file_path: string; + /** Full UTF-8 text content to write. */ + content: string; + /** The wider sandbox mode this file operation needs. Only valid as a one-shot retry of an operation the sandbox just denied; requires justification and user approval. */ + sandbox_permissions?: "workspace-write" | "danger-full-access"; + /** Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access. */ + justification?: string; + } & Record; +} + +interface ToolOutputMap { + bash: { + kind: "background"; + taskId: string; + } | { + kind: "foreground"; + exitCode: number | null; + signal: string | null; + timedOut: boolean; + aborted: boolean; + timeoutMs: number; + stdout: { + text: string; + truncated: boolean; + spillPath?: string; + }; + stderr: { + text: string; + truncated: boolean; + spillPath?: string; + }; + sandbox?: { + mode: string; + denied: boolean; + enforcement?: string; + runnerFailed?: boolean; + }; + }; + create_goal: { + goal: null; + } | { + goal: { + id: string; + revision: number; + objective: string; + phase: "active" | "paused" | "blocked" | "complete"; + roundsStarted: number; + maxGoalRounds: number; + blockedReason?: { + code: string; + message: string; + }; + }; + activation: "armed" | "disarmed"; + }; + edit: { + path: string; + before: string; + after: string; + }; + get_goal: { + goal: null; + } | { + goal: { + id: string; + revision: number; + objective: string; + phase: "active" | "paused" | "blocked" | "complete"; + roundsStarted: number; + maxGoalRounds: number; + blockedReason?: { + code: string; + message: string; + }; + }; + activation: "armed" | "disarmed"; + }; + interrupt_agent: { + accepted: boolean; + }; + list_agents: ({ + kind: "child"; + id: string; + label: string; + status: "running" | "idle" | "ready"; + parent?: string; + depth?: number; + } | { + kind: "diagnostic"; + id: string; + reason: "corrupt" | "unsupported" | "unavailable"; + parent?: string; + depth?: number; + })[]; + ralph: { + runId: string; + agentsStarted: number; + result: JsonValue; + }; + read: { + path: string; + offset: number; + lines: { + number: number; + text: string; + }[]; + totalLines: number; + }; + send_message: { + messageId: string; + }; + skill: { + name: string; + provider: string; + resourceBase?: { + kind: "directory"; + path: string; + } | { + kind: "url"; + url: string; + } | { + kind: "opaque"; + description: string; + }; + content: string; + }; + subagent: { + kind: "background"; + taskId: string; + } | { + kind: "continuable"; + subagentId: string; + } | { + kind: "foreground"; + runId: string; + output: JsonValue[]; + }; + subagent_fork: { + kind: "background"; + taskId: string; + } | { + kind: "continuable"; + subagentId: string; + } | { + kind: "foreground"; + runId: string; + output: JsonValue[]; + }; + task_kill: { + outcome: "cancellation-requested" | "already-finished"; + task: { + id: string; + kind: string; + label: string; + status: "running" | "stopping" | "completed" | "killed" | "failed"; + detail?: string; + startedAt: number; + finishedAt?: number; + }; + }; + task_list: ({ + id: string; + kind: string; + label: string; + status: "running" | "stopping" | "completed" | "killed" | "failed"; + detail?: string; + startedAt: number; + finishedAt?: number; + })[]; + task_output: { + text: string; + task: { + id: string; + kind: string; + label: string; + status: "running" | "stopping" | "completed" | "killed" | "failed"; + detail?: string; + startedAt: number; + finishedAt?: number; + }; + }; + todo_write: { + todos: ({ + content: string; + status: "pending" | "in_progress" | "completed"; + })[]; + counts: { + pending: number; + inProgress: number; + completed: number; + }; + }; + update_goal: { + goal: null; + } | { + goal: { + id: string; + revision: number; + objective: string; + phase: "active" | "paused" | "blocked" | "complete"; + roundsStarted: number; + maxGoalRounds: number; + blockedReason?: { + code: string; + message: string; + }; + }; + activation: "armed" | "disarmed"; + }; + workflow: { + runId: string; + agentsStarted: number; + result: JsonValue; + }; + write: { + path: string; + operation: "create" | "update"; + before: string | null; + after: string; + }; +} + +type ToolName = keyof ToolOutputMap + +declare class ToolCallError extends Error { + readonly name: "ToolCallError"; + readonly toolName: ToolName; +} + +declare const tools: { + [K in ToolName]: (args: ToolArgsMap[K]) => Promise; +} +``` diff --git a/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md index 3771a70950..f3994dc95b 100644 --- a/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md +++ b/examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md @@ -5,6 +5,8 @@ You are a coding assistant powered by the deepseek-v4-flash model. Your working Verify your work by running the code or tests. Keep answers brief and factual. +`run_code` is the only tool you can call directly — a tool call naming any other tool fails. Reach every tool the SDK declares below from inside the program. + Use the read tool — not shell commands like cat — to inspect text files. Results include line numbers. Use offset and limit to continue reading large files. Use the write tool to create files or completely replace file contents. Existing files are overwritten, so read an existing file first (the default fs-policy requires it) and prefer edit for targeted changes. diff --git a/packages/core/agent-tool-mode/README.i18n.yaml b/packages/core/agent-tool-mode/README.i18n.yaml index 0799e0e547..b5cc383841 100644 --- a/packages/core/agent-tool-mode/README.i18n.yaml +++ b/packages/core/agent-tool-mode/README.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write packages/core/agent-tool-mode/README.md -README.md: 0ef7f32c0890e5ef1071368571bd78b400b656e2 -README.zh.md: 974fc4ed574e44244f8d97682e2451440c8267ce +README.md: f5f2df21285411dbb3b8c5cac18cc3ab0dc8a22b +README.zh.md: 84c2ff009540c2637e01875b1171c39afa6ae2f3 diff --git a/packages/core/agent-tool-mode/README.md b/packages/core/agent-tool-mode/README.md index 0ef7f32c08..f5f2df2128 100644 --- a/packages/core/agent-tool-mode/README.md +++ b/packages/core/agent-tool-mode/README.md @@ -20,7 +20,7 @@ One agent declares one presentation. A second declaration in the same compositio ## Model Experience -Indirectly, through the projection it selects in `dsh-tools`: `code` presents `run_code` plus a generated SDK section, `native` presents every tool schema. +Indirectly, through the projection it selects in `dsh-tools`: `code` presents `run_code` plus a generated SDK section and the rule that only `run_code` may be called directly, `native` presents every tool schema. The selection also decides what may EXECUTE: under `code` the registry resolves a model-direct call naming any other tool to `UNKNOWN_TOOL`, so this row is what keeps the announced surface and the callable surface the same for every agent it covers ([executor-collapse note](../../../.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md)). #### KV Cache effect diff --git a/packages/core/agent-tool-mode/README.zh.md b/packages/core/agent-tool-mode/README.zh.md index 974fc4ed57..84c2ff0095 100644 --- a/packages/core/agent-tool-mode/README.zh.md +++ b/packages/core/agent-tool-mode/README.zh.md @@ -20,7 +20,7 @@ preset 能拥有的是这份注册表的**呈现方式**。`ctx.tools.presentAs( ## Model Experience -Indirectly, through the projection it selects in `dsh-tools`: `code` presents `run_code` plus a generated SDK section, `native` presents every tool schema. +间接生效,取决于它在 `dsh-tools` 中选择的投影:`code` 呈现 `run_code`、一份生成的 SDK 段,以及「只有 `run_code` 可被直接调用」这条规则,`native` 呈现每个工具的 schema。该选择同时决定了**什么可以执行**:在 `code` 下,注册表会把模型直呼其他任何工具名解析为 `UNKNOWN_TOOL`,因此这一行正是让「通告面」与「可调用面」对每个被它覆盖的 agent 保持一致的东西([执行器塌缩 note](../../../.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md))。 #### KV Cache effect diff --git a/packages/core/tools/README.i18n.yaml b/packages/core/tools/README.i18n.yaml index 8f496c02ec..5841f76969 100644 --- a/packages/core/tools/README.i18n.yaml +++ b/packages/core/tools/README.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write packages/core/tools/README.md -README.md: 653720b9a577df630c3b4c23a4615ff640e95292 -README.zh.md: 8c4671bf8d4f10f806fcce1a21044c82ff2d6d7d +README.md: 44eb25b79436a75f08406102fc1e3734e59b1001 +README.zh.md: 35142d8186b21b2930ccc40386bed8cc677d77c3 diff --git a/packages/core/tools/README.md b/packages/core/tools/README.md index 653720b9a5..44eb25b794 100644 --- a/packages/core/tools/README.md +++ b/packages/core/tools/README.md @@ -13,7 +13,7 @@ tools: mode: native # native (default) | code | both ``` -`native` contributes visible tools as function definitions. `code` contributes the reserved `run_code` transport and generated `tools:sdk` section; `both` contributes both forms. This is the default for agents that declare none of their own — an agent preset selects its own with [`dsh-agent-tool-mode`](../agent-tool-mode/README.md). The reserved transport cannot be registered, shadowed, restricted, or removed, and its name is reserved whatever the configured mode, because any agent may select a code mode. Non-native modes require a `ctx.codeRuntime` whose `language` has a registered SDK renderer — TypeScript ships via [`dsh-code-runtime-worker`](../../code-runtime/code-runtime-worker/README.md); a Python renderer is built in and drives any runtime that reports `language: 'python'` (a first-party `dsh-code-runtime-python` backend is delivered separately). A runtime language with no renderer fails prompt assembly loudly, and a `systemPrompt.toolOrder` entry for a tool the mode does not contribute rejects prompt assembly. A `system-prompt/assemble` listener may replace the registry's contributions; its returned assembly is authoritative, so that listener owns preserving a usable Code Mode protocol. +`native` contributes visible tools as function definitions. `code` contributes the reserved `run_code` transport, the generated `tools:sdk` section, and the `tools:code-only` rule stating that only `run_code` may be called directly — which the executor then enforces, resolving a model-direct call naming any other tool to `UNKNOWN_TOOL` before policy runs; `both` contributes both forms and states no such rule, because its native calls do execute. This is the default for agents that declare none of their own — an agent preset selects its own with [`dsh-agent-tool-mode`](../agent-tool-mode/README.md). The reserved transport cannot be registered, shadowed, restricted, or removed, and its name is reserved whatever the configured mode, because any agent may select a code mode. Non-native modes require a `ctx.codeRuntime` whose `language` has a registered SDK renderer — TypeScript ships via [`dsh-code-runtime-worker`](../../code-runtime/code-runtime-worker/README.md); a Python renderer is built in and drives any runtime that reports `language: 'python'` (a first-party `dsh-code-runtime-python` backend is delivered separately). A runtime language with no renderer fails prompt assembly loudly, and a `systemPrompt.toolOrder` entry for a tool the mode does not contribute rejects prompt assembly. A `system-prompt/assemble` listener may replace the registry's contributions; its returned assembly is authoritative, so that listener owns preserving a usable Code Mode protocol. ### Public API @@ -115,7 +115,9 @@ Returning `undefined` selects generic fallback. Presenters depend only on their ### Code Mode -Under `code` or `both`, the registry exposes the reserved `run_code` transport and a deterministic SDK for the current scope, generated in the loaded runtime's language — the registry selects the renderer by `ctx.codeRuntime.language` (`typescript` → the TypeScript SDK below, `python` → the Python SDK). Only the program's outer logs and return value re-enter model context. The SDK declares exact per-tool argument and canonical-output types for every visible tool (`ToolArgsMap`/`ToolOutputMap` in TypeScript, named `TypedDict`s in Python), and each binding resolves to the tool's canonical JSON value. Each lossless-JSON binding call re-enters the complete tool pipeline under the native scheduling contract (concurrency-safe calls may overlap up to `maxParallelSubCalls`; exclusive calls run alone as ordering barriers) with logged correlation to the outer call. Denials and other failed results reject with the real program-visible `ToolCallError` carrying only `toolName` and `message`; Native content and internal error codes stay outside the Code contract. Ordinary side effects are not rolled back, and sub-call `additionalContexts` are deferred through the parent result to preserve call/result adjacency. Run settlement aborts and drains outstanding bindings; runtime failures surface as `CodeRunFailedError`. See the [Code Mode foundation](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md), [typed-return contract](../../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md), and [code-runtime seam](../../code-runtime/README.md). Try `pnpm run demo:code-mode`. +Under `code` or `both`, the registry exposes the reserved `run_code` transport and a deterministic SDK for the current scope, generated in the loaded runtime's language — the registry selects the renderer by `ctx.codeRuntime.language` (`typescript` → the TypeScript SDK below, `python` → the Python SDK). Only the program's outer logs and return value re-enter model context. The SDK declares exact per-tool argument and canonical-output types for every visible tool (`ToolArgsMap`/`ToolOutputMap` in TypeScript, named `TypedDict`s in Python), and each binding resolves to the tool's canonical JSON value. Each lossless-JSON binding call re-enters the complete tool pipeline under the native scheduling contract (concurrency-safe calls may overlap up to `maxParallelSubCalls`; exclusive calls run alone as ordering barriers) with logged correlation to the outer call. Denials and other failed results reject with the real program-visible `ToolCallError` carrying only `toolName` and `message`; Native content and internal error codes stay outside the Code contract. Ordinary side effects are not rolled back, and sub-call `additionalContexts` are deferred through the parent result to preserve call/result adjacency. Run settlement aborts and drains outstanding bindings; runtime failures surface as `CodeRunFailedError`. + +Under `code` — not `both` — the transport is also the only entry the model may use: a model-direct call naming any other visible tool resolves to `UNKNOWN_TOOL` at execution creation, before `tools/pre-execute`, approval `ask`, and guards, so nothing observes or approves a call that can only fail. The denial names the route back (`only \`run_code\` is callable directly — call \`\` from inside a \`run_code\` program instead`), because the same prompt declares that tool and a bare `unknown tool` reads as a broken deployment. SDK sub-dispatches carry the outer execution's `parent` token and are exempt, so programs keep every binding the SDK declared. See the [executor-collapse note](../../../.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md), the [Code Mode foundation](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md), [typed-return contract](../../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md), and [code-runtime seam](../../code-runtime/README.md). Try `pnpm run demo:code-mode`. - **The SDK section** (`tools:sdk`, order 150): a lazy prompt section regenerating the language-appropriate SDK text at each assembly. In the TypeScript flavor it emits `JsonValue`, exact `ToolArgsMap` / `ToolOutputMap`, `ToolName`, the `ToolCallError` declaration, and a mapped `tools` namespace for the calling scope's visible end capabilities (exotic names via quoted keys), plus fixed usage instructions; the Python flavor (`ctx.codeRuntime.language === 'python'`) emits the equivalent named `TypedDict`s and a `tools` object with matching usage instructions. Deterministic — lexicographic tool order, byte-identical text for an unchanged tool set (prefix-cache-friendly). Both codegens are exported and never throw during prompt assembly: `jsonSchemaToTs` handles every unified schema construct and degrades unsupported raw constructs to `unknown`; `jsonSchemaToPy` does the same, degrading to `Any` (and a whole object to `dict[str, Any]` when a field name is not a legal `TypedDict` attribute, or whenever it is called outside the SDK render, which supplies the naming context a `TypedDict` declaration needs). - **The dispatch bridge** (`run_code`'s execute): every binding call is snapshotted as lossless JSON before dispatch (`undefined`, `BigInt`, cycles, sparse arrays, `-0`, and exotic objects reject that one call), scheduled through a per-run pool that reuses the native concurrency contract — calls start strictly in submission order, consecutive `isConcurrencySafe` calls overlap up to the validated `maxParallelSubCalls` config (default 10; `1` restores serial dispatch), and an exclusive-classified call drains the pool, runs alone, and bars later calls — given the outer execution's opaque token as `parent`, and run through the complete pre-execute → guards → execute → post-execute → result pipeline. A success returns the final canonical value after policy; a failure reaches the worker as one message and becomes `ToolCallError(toolName, message)`. Each started sub-call logs a `tool/code-dispatch-start` event (deterministic id `:code:`, numbered by submission) at pipeline entry and settles with one `tool/code-dispatch` event carrying the complete model-facing `content`/`isError` outcome (the `tool/result` vocabulary, so UIs render sub-calls through the native path — the pair's `time` fields carry per-sub-call timing); a queued call abandoned by run settlement logs neither. `deriveMessages()` surfaces neither event nor persists the canonical value. Token correlation lets commit-style observers defer an inner success until the final `run_code` result without exposing the live outer execution; ordinary tool side effects are not rolled back. Every sub-call `additionalContexts` entry is deferred through the outer `ToolRunContext` in dispatch order; the loop appends those contexts only after the parent `run_code` result, preserving adjacency and retaining each source/meta even when the program later fails. @@ -146,7 +148,7 @@ Prefix-stable while visible definitions and their order are unchanged. Registrat #### What the model sees -Code Mode exposes the generated [`run_code` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tools), the SDK instructions below, and the generated exact SDK block for the loaded runtime's language (the TypeScript `declare const tools` block, or the Python `tools` declaration). `both` exposes normal schemas and this Code Mode API. The instructions and SDK block match the loaded runtime's language; the TypeScript version (via [`dsh-code-runtime-worker`](../../code-runtime/code-runtime-worker/README.md)) is shown below, and the Python version (for any runtime reporting `language: 'python'`) has the same operations and types in Python syntax (`await tools.name(args)`, subscript access for exotic names, `print(...)` and top-level `return`). +Code Mode exposes the generated [`run_code` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tools), the SDK instructions below, and the generated exact SDK block for the loaded runtime's language (the TypeScript `declare const tools` block, or the Python `tools` declaration). `both` exposes normal schemas and this Code Mode API. Under `code` the prompt also carries the `tools:code-only` rule, ordered ahead of the per-tool guidance band so the model reads which tools it may call before it reads what each one is for; `both` renders it empty. The instructions and SDK block match the loaded runtime's language; the TypeScript version (via [`dsh-code-runtime-worker`](../../code-runtime/code-runtime-worker/README.md)) is shown below, and the Python version (for any runtime reporting `language: 'python'`) has the same operations and types in Python syntax (`await tools.name(args)`, subscript access for exotic names, `print(...)` and top-level `return`). ##### Code Mode SDK instructions diff --git a/packages/core/tools/README.zh.md b/packages/core/tools/README.zh.md index 8c4671bf8d..35142d8186 100644 --- a/packages/core/tools/README.zh.md +++ b/packages/core/tools/README.zh.md @@ -13,7 +13,7 @@ tools: mode: native # native (default) | code | both ``` -`native` 以函数定义的形式贡献可见工具。`code` 贡献保留的 `run_code` 传输和生成的 `tools:sdk` 段;`both` 同时贡献两种形式。这是「未作声明的 agent」的默认值——agent preset 用 [`dsh-agent-tool-mode`](../agent-tool-mode/README.md) 为自己选择。不能注册、遮蔽、限制或移除该保留传输,且无论配置何种模式,该名称都是保留的,因为任何 agent 都可能选择 code 模式。非原生模式要求所加载 `ctx.codeRuntime` 的 `language` 有已注册的 SDK 渲染器——TypeScript 经 [`dsh-code-runtime-worker`](../../code-runtime/code-runtime-worker/README.md) 交付;Python 渲染器内置,驱动任何报告 `language: 'python'` 的运行时(第一方 `dsh-code-runtime-python` 后端另行交付)。没有渲染器的运行时语言会导致提示词组装明确失败;如果 `systemPrompt.toolOrder` 条目指向当前模式未贡献的工具,系统会拒绝组装提示词。`system-prompt/assemble` 监听器可以替换注册表贡献;它返回的组装结果具有权威性,因此该监听器负责保留可用的 Code Mode 协议。 +`native` 以函数定义的形式贡献可见工具。`code` 贡献保留的 `run_code` 传输、生成的 `tools:sdk` 段,以及声明「只有 `run_code` 可被直接调用」的 `tools:code-only` 规则——执行器随后强制该规则,模型直呼其他任何工具名都会在策略运行之前解析为 `UNKNOWN_TOOL`;`both` 同时贡献两种形式,且不声明该规则,因为它的原生调用确实会执行。这是「未作声明的 agent」的默认值——agent preset 用 [`dsh-agent-tool-mode`](../agent-tool-mode/README.md) 为自己选择。不能注册、遮蔽、限制或移除该保留传输,且无论配置何种模式,该名称都是保留的,因为任何 agent 都可能选择 code 模式。非原生模式要求所加载 `ctx.codeRuntime` 的 `language` 有已注册的 SDK 渲染器——TypeScript 经 [`dsh-code-runtime-worker`](../../code-runtime/code-runtime-worker/README.md) 交付;Python 渲染器内置,驱动任何报告 `language: 'python'` 的运行时(第一方 `dsh-code-runtime-python` 后端另行交付)。没有渲染器的运行时语言会导致提示词组装明确失败;如果 `systemPrompt.toolOrder` 条目指向当前模式未贡献的工具,系统会拒绝组装提示词。`system-prompt/assemble` 监听器可以替换注册表贡献;它返回的组装结果具有权威性,因此该监听器负责保留可用的 Code Mode 协议。 ### 公开 API @@ -115,7 +115,9 @@ ctx.tools.register(defineTool({ ### Code Mode -在 `code` 或 `both` 模式下,注册表为当前作用域公开保留的 `run_code` 传输和按所加载运行时语言生成的确定性 SDK——注册表按 `ctx.codeRuntime.language` 选择渲染器(`typescript` → 下方的 TypeScript SDK,`python` → Python SDK)。只有程序的外层日志与返回值会重新进入模型上下文。SDK 为每个可见工具声明精确的参数与规范输出类型(TypeScript 为 `ToolArgsMap`/`ToolOutputMap`,Python 为具名 `TypedDict`),每个绑定都会解析为该工具的规范 JSON 值。每个无损 JSON 绑定调用都会在原生调度约定下重新进入完整工具流水线(并发安全的调用最多可重叠 `maxParallelSubCalls` 个;独占调用单独运行并构成排序屏障),并在日志中与外层调用建立关联。拒绝及其他失败结果会以程序实际可见的 `ToolCallError` 形式拒绝,且只携带 `toolName` 和 `message`;Native 内容和内部错误码留在 Code 约定之外。普通副作用不会回滚,子调用的 `additionalContexts` 会通过父结果延迟,以保持调用/结果相邻。运行结算会中止并排空尚未完成的绑定;运行时失败以 `CodeRunFailedError` 形式出现。参见 [Code Mode 基础](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md)、[类型化返回约定](../../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md)和[代码运行时 seam](../../code-runtime/README.md)。可以运行 `pnpm run demo:code-mode` 试用。 +在 `code` 或 `both` 模式下,注册表为当前作用域公开保留的 `run_code` 传输和按所加载运行时语言生成的确定性 SDK——注册表按 `ctx.codeRuntime.language` 选择渲染器(`typescript` → 下方的 TypeScript SDK,`python` → Python SDK)。只有程序的外层日志与返回值会重新进入模型上下文。SDK 为每个可见工具声明精确的参数与规范输出类型(TypeScript 为 `ToolArgsMap`/`ToolOutputMap`,Python 为具名 `TypedDict`),每个绑定都会解析为该工具的规范 JSON 值。每个无损 JSON 绑定调用都会在原生调度约定下重新进入完整工具流水线(并发安全的调用最多可重叠 `maxParallelSubCalls` 个;独占调用单独运行并构成排序屏障),并在日志中与外层调用建立关联。拒绝及其他失败结果会以程序实际可见的 `ToolCallError` 形式拒绝,且只携带 `toolName` 和 `message`;Native 内容和内部错误码留在 Code 约定之外。普通副作用不会回滚,子调用的 `additionalContexts` 会通过父结果延迟,以保持调用/结果相邻。运行结算会中止并排空尚未完成的绑定;运行时失败以 `CodeRunFailedError` 形式出现。 + +在 `code`(而非 `both`)下,该传输同时也是模型唯一可用的入口:模型直呼其他任何可见工具名,都会在创建执行时、早于 `tools/pre-execute`、审批 `ask` 和 guards 解析为 `UNKNOWN_TOOL`,因此没有任何一方会观察或批准一个注定失败的调用。拒绝信息会给出正确路径(`only \`run_code\` is callable directly — call \`\` from inside a \`run_code\` program instead`),因为同一份提示词刚刚声明过那个工具,只说 `unknown tool` 会被读成部署损坏。SDK 子分发携带外层执行的 `parent` token,不受此限制,因此程序保留 SDK 声明的全部绑定。参见[执行器塌缩 note](../../../.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md)、[Code Mode 基础](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md)、[类型化返回约定](../../../.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md)和[代码运行时 seam](../../code-runtime/README.md)。可以运行 `pnpm run demo:code-mode` 试用。 - **SDK 段**(`tools:sdk`,顺序 150):一个惰性提示词段,每次组装时都会重新生成与所加载运行时语言相符的 SDK 文本。TypeScript 形态发出 `JsonValue`、精确的 `ToolArgsMap` / `ToolOutputMap`、`ToolName`、`ToolCallError` 声明、面向调用作用域可见最终能力的映射 `tools` 命名空间(特殊名称使用带引号的键),以及固定用法说明;Python 形态(`ctx.codeRuntime.language === 'python'`)发出等价的具名 `TypedDict` 与一个带相同用法说明的 `tools` 对象。其输出具有确定性:工具按字典序排列;工具集合不变时,文本逐字节相同(有利于前缀 cache)。两个代码生成器都已导出,且绝不会在提示词组装期间抛出:`jsonSchemaToTs` 处理统一 schema 的每种构造并将不受支持的原始构造降级为 `unknown`;`jsonSchemaToPy` 同理,降级为 `Any`(当某字段名不是合法的 `TypedDict` 属性时,或在 SDK 渲染之外被调用时——`TypedDict` 声明所需的命名上下文由该渲染提供——整个对象降级为 `dict[str, Any]`)。 - **分发桥接层**(`run_code` 的 execute):每个绑定调用都会在分发前快照为无损 JSON(`undefined`、`BigInt`、循环、稀疏数组、`-0` 和特殊对象会使该次调用被拒绝),经由每次运行独有、复用原生并发约定的池调度——调用严格按提交顺序启动,连续的 `isConcurrencySafe` 调用最多可重叠经校验的 `maxParallelSubCalls` 配置个(默认 10;设为 `1` 即恢复串行分发),被分类为独占的调用先排空池、单独运行并阻挡其后的调用——以外层执行的不透明 token 作为 `parent`,并经过完整的 pre-execute → guards → execute → post-execute → result 流水线。成功会返回策略处理后的最终规范值;失败以一条消息到达 worker,并成为 `ToolCallError(toolName, message)`。每个已启动的子调用在进入流水线时记录一条 `tool/code-dispatch-start` 事件(确定性 id `:code:`,按提交顺序编号),并以一条携带完整模型可见 `content`/`isError` 结果的 `tool/code-dispatch` 事件完结(采用 `tool/result` 词汇,因此 UI 会沿原生路径呈现子调用——这对事件的 `time` 字段承载每个子调用的计时);因 run 结算而被放弃的排队调用两者都不记录。`deriveMessages()` 既不公开这两个事件,也不持久化规范值。token 关联让以提交为语义的观察器能够把内部成功延迟到最终 `run_code` 结果,而无需公开实时外层执行;普通工具副作用不会回滚。每个子调用的 `additionalContexts` 条目都会按分发顺序通过外层 `ToolRunContext` 延迟;循环只在父级 `run_code` 结果之后追加这些上下文,从而保持相邻关系,并且即使程序后来失败,也会保留各自的来源/元数据。 @@ -146,7 +148,7 @@ agent loop 将连续的 `parallel` 调用归入有界滚动池,并把每个 `e #### 模型看到的内容 -Code Mode 会公开生成的 [`run_code` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tools)、下方 SDK 说明,以及按所加载运行时语言生成的精确 SDK 块(TypeScript 的 `declare const tools` 块,或 Python 的 `tools` 声明)。`both` 会同时公开普通 schema 与此 Code Mode API。说明与 SDK 块随所加载运行时的语言切换;下方展示 TypeScript 版本(经 [`dsh-code-runtime-worker`](../../code-runtime/code-runtime-worker/README.md)),Python 版本(用于任何报告 `language: 'python'` 的运行时)以 Python 语法提供相同操作和类型(`await tools.name(args)`、特殊名称用下标访问、`print(...)` 与顶层 `return`)。 +Code Mode 会公开生成的 [`run_code` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tools)、下方 SDK 说明,以及按所加载运行时语言生成的精确 SDK 块(TypeScript 的 `declare const tools` 块,或 Python 的 `tools` 声明)。`both` 会同时公开普通 schema 与此 Code Mode API。在 `code` 下,提示词还会带上 `tools:code-only` 规则,其顺序排在逐工具指导段之前,让模型先读到「可以调用哪些工具」再读「每个工具做什么」;`both` 下它渲染为空。说明与 SDK 块随所加载运行时的语言切换;下方展示 TypeScript 版本(经 [`dsh-code-runtime-worker`](../../code-runtime/code-runtime-worker/README.md)),Python 版本(用于任何报告 `language: 'python'` 的运行时)以 Python 语法提供相同操作和类型(`await tools.name(args)`、特殊名称用下标访问、`print(...)` 与顶层 `return`)。 ##### Code Mode SDK 说明 diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index 469c48313c..492112405b 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -43,6 +43,20 @@ import { renderToolsSdkPy } from './py-types.ts' * with its zh pair, plus this package's own README pair and the * {@link Config.mode} JSDoc. */ +/** + * Prompt order of the `code` collapse statement: after the persona and before + * the 100-199 per-tool guidance band, so the model reads which tools it may + * call before it reads what each one is for. + */ +const COLLAPSE_SECTION_ORDER = 99 + +/** + * The model-facing statement of the `code` collapse. Names the consequence + * (the call fails) and the route (inside the program), because a rule the + * model can only discover by being denied is one it corrects too late. + */ +const CODE_ONLY_INSTRUCTION = `\`${RUN_CODE_NAME}\` is the only tool you can call directly — a tool call naming any other tool fails. Reach every tool the SDK declares below from inside the program.` + const SDK_RENDERERS: Record string> = { typescript: renderToolsSdk, python: renderToolsSdkPy, @@ -478,8 +492,19 @@ export interface ToolFailure { * distinguish it from a tool body's own error. */ export class ToolNotFoundError extends HarnessError { - constructor(toolName: string) { - super(`unknown tool "${toolName}"`, 'UNKNOWN_TOOL') + /** + * @param toolName - the name the caller asked for. + * @param reachableFrom - how the model reaches this tool instead, when the + * name IS visible and only the presentation denies calling it directly. + * Omitted for a name that is registered nowhere. + */ + constructor(toolName: string, reachableFrom?: string) { + super( + reachableFrom === undefined + ? `unknown tool "${toolName}"` + : `unknown tool "${toolName}": ${reachableFrom}`, + 'UNKNOWN_TOOL', + ) this.name = 'ToolNotFoundError' } } @@ -806,10 +831,37 @@ export class ToolRegistry extends Service { this.maxParallelSubCalls = resolveMaxParallelSubCalls(config.maxParallelSubCalls) ctx.systemPrompt.tools(context => this.wireSchemas(context.scope)) if (this.defaultMode !== 'native') { + ctx.systemPrompt.section(this.collapseSection()) ctx.systemPrompt.section(this.sdkSection()) } } + /** + * The prompt statement of the `code` executor collapse, registered wherever + * {@link sdkSection} is and rendering empty outside an effective `code`. + * + * Every tool contributes its own guidance section naming its tool, none of + * them qualify how that tool is reached, and they all render before the SDK + * (orders 100-199 against {@link SDK_SECTION_ORDER}). Without this the model + * reads a catalog of tools it is told to use and no statement that only + * `run_code` may be called, so it emits a native call, receives + * `UNKNOWN_TOOL` for a tool the prompt just declared, and concludes the + * deployment is inconsistent. {@link COLLAPSE_SECTION_ORDER} places the rule + * before that guidance rather than after it. + * + * `both` renders empty: native calls do execute there, so the rule is false. + * @returns the section registration. + */ + private collapseSection(): { name: string; order: number; text: (context: { scope?: ScopeKey }) => string } { + return { + name: 'tools:code-only', + order: COLLAPSE_SECTION_ORDER, + // The SAME predicate the executor denies by, so the prompt cannot state + // a rule the registry does not enforce (see `collapses`). + text: context => this.modeFor(context.scope) === 'code' ? CODE_ONLY_INSTRUCTION : '', + } + } + /** * The generated-SDK prompt section, registered globally by a code-mode * deployment and per scope by {@link presentAs}. @@ -908,11 +960,14 @@ export class ToolRegistry extends Service { }, { label: 'tools.presentAs()' }, ) - // The SDK section is per scope for the same reason the mode is. Under a - // deployment that already defaults to a code mode this shadows the - // global registration with an identical body, which costs nothing and - // keeps one rule instead of a case analysis. - if (mode !== 'native') yield ctx.systemPrompt.section(this.sdkSection()) + // The SDK and collapse sections are per scope for the same reason the + // mode is. Under a deployment that already defaults to a code mode this + // shadows the global registration with an identical body, which costs + // nothing and keeps one rule instead of a case analysis. + if (mode !== 'native') { + yield ctx.systemPrompt.section(this.collapseSection()) + yield ctx.systemPrompt.section(this.sdkSection()) + } }.bind(this), 'tools.presentAs()') // oxlint-disable-next-line typescript/no-misused-promises -- synchronous composite teardown; direct return preserves disposer identity return dispose @@ -1367,7 +1422,18 @@ export class ToolRegistry extends Service { if (signal.aborted) { return { kind: 'final-result', exec: execution, result: toolAbortedBeforeDispatchResult() } } - return { kind: 'final-result', exec: execution, result: toolErrorResult(new ToolNotFoundError(name)) } + // The name IS visible here, so the denial carries the route the model + // must take instead. Without it the model reads a bare `unknown tool` + // for a tool the prompt just declared and concludes the deployment is + // broken rather than correcting itself. + return { + kind: 'final-result', + exec: execution, + result: toolErrorResult(new ToolNotFoundError( + name, + `only \`${RUN_CODE_NAME}\` is callable directly — call \`${name}\` from inside a \`${RUN_CODE_NAME}\` program instead`, + )), + } } return { kind: 'ready', exec: execution } } catch (error: unknown) { diff --git a/packages/core/tools/tests/code-mode.spec.ts b/packages/core/tools/tests/code-mode.spec.ts index a0248f3a10..eb6d1b22e0 100644 --- a/packages/core/tools/tests/code-mode.spec.ts +++ b/packages/core/tools/tests/code-mode.spec.ts @@ -135,6 +135,32 @@ describe('mode-aware wire contribution', () => { expect(sdk?.text).not.toContain('run_code:') }) + it("mode 'code' states the run_code-only rule BEFORE the per-tool guidance that names each tool", async () => { + const { ctx, systemPrompt } = await setup({ mode: 'code' }) + registerEcho(ctx) + // Stand in for a real tool's guidance section, which sits in the 100-199 + // band and names its tool without saying how it is reached. + ctx.systemPrompt.section({ name: 'tool:echo', order: 100, text: 'Use the echo tool.' }) + + const assembly = await systemPrompt.assemble() + const names = assembly.sections.map(section => section.name) + const rule = assembly.sections.find(section => section.name === 'tools:code-only') + expect(rule?.text).toContain(`\`${RUN_CODE_NAME}\` is the only tool you can call directly`) + // The rule is worthless after the guidance it qualifies. + expect(names.indexOf('tools:code-only')).toBeLessThan(names.indexOf('tool:echo')) + expect(names.indexOf('tools:code-only')).toBeLessThan(names.indexOf('tools:sdk')) + }) + + it("mode 'both' omits the run_code-only rule, because native calls do execute there", async () => { + const { ctx, systemPrompt } = await setup({ mode: 'both' }) + registerEcho(ctx) + const assembly = await systemPrompt.assemble() + // Registered (the deployment is non-native) but empty, so the renderer + // drops it: `both` executes the native call the rule would forbid. + expect(assembly.sections.find(section => section.name === 'tools:code-only')?.text).toBe('') + expect(assembly.tools.map(tool => tool.name)).toContain('echo') + }) + it('projects deeply nested output schemas into the Code Mode SDK without structured-clone recursion', async () => { const { ctx, systemPrompt } = await setup({ mode: 'code' }) let output: JsonSchemaNode = { type: 'string' } @@ -1574,6 +1600,11 @@ describe('the run_code dispatch bridge', () => { }) expect(result.isError).toBe(true) expect(result.error?.info).toEqual({ name: 'ToolNotFoundError', code: 'UNKNOWN_TOOL' }) + // The name IS declared to this model, so a bare `unknown tool` reads as a + // broken deployment. The denial carries the route instead. + expect(result.error?.message).toBe( + `unknown tool "write": only \`${RUN_CODE_NAME}\` is callable directly — call \`write\` from inside a \`${RUN_CODE_NAME}\` program instead`, + ) }) it('routes a pre-aborted collapsed call through ABORTED_BEFORE_DISPATCH', async () => { From 5ca7be5dcb310aad1ce83e673d2b4326a7329ac9 Mon Sep 17 00:00:00 2001 From: imccyu <276526105+imccyu@users.noreply.github.com> Date: Tue, 11 Aug 2026 22:39:48 +0800 Subject: [PATCH 14/17] release(dsh): 0.0.1-rc.2 --- apps/cli/package.json | 2 +- apps/web/package.json | 2 +- package.json | 2 +- packages/acp/acp/package.json | 2 +- packages/api/gateway/package.json | 2 +- packages/api/remotes/package.json | 2 +- .../attachment/attachment-local/package.json | 2 +- packages/attachment/attachment/package.json | 2 +- packages/bash/bash-env/package.json | 2 +- packages/bash/bash-local/package.json | 2 +- packages/bash/bash-sandbox/package.json | 2 +- packages/bash/bash/package.json | 2 +- packages/bash/pwsh-local/package.json | 2 +- packages/bash/pwsh-sandbox/package.json | 2 +- packages/bash/tool-bash/package.json | 2 +- packages/bash/tool-pwsh/package.json | 2 +- packages/boot/app-boot/package.json | 2 +- packages/boot/cmdline/package.json | 2 +- packages/bundle/base/package.json | 2 +- packages/bundle/headless/package.json | 2 +- packages/bundle/web-app/package.json | 2 +- packages/client/connection/package.json | 2 +- packages/client/hmr/package.json | 2 +- packages/client/locale/package.json | 2 +- packages/client/modules/package.json | 2 +- packages/client/runtime/package.json | 2 +- packages/client/schema-form/package.json | 2 +- packages/client/test-runtime/package.json | 2 +- packages/client/ui-agent-preset/package.json | 2 +- packages/client/ui-attachment/package.json | 2 +- packages/client/ui-command/package.json | 2 +- packages/client/ui-conversation/package.json | 2 +- packages/client/ui-deliverables/package.json | 2 +- packages/client/ui-goal/package.json | 2 +- packages/client/ui-layout/package.json | 2 +- packages/client/ui-model/package.json | 2 +- packages/client/ui-models/package.json | 2 +- packages/client/ui-permission/package.json | 2 +- packages/client/ui-plan/package.json | 2 +- packages/client/ui-plugin-config/package.json | 2 +- packages/client/ui-primitives/package.json | 2 +- packages/client/ui-question/package.json | 2 +- .../client/ui-settings-general/package.json | 2 +- packages/client/ui-settings/package.json | 2 +- packages/client/ui-sidebar/package.json | 2 +- packages/client/ui-skill/package.json | 2 +- packages/client/ui-slash/package.json | 2 +- packages/client/ui-slots/package.json | 2 +- packages/client/ui-subagent/package.json | 2 +- packages/client/ui-task/package.json | 2 +- packages/client/ui-theme/package.json | 2 +- packages/client/ui-tool/package.json | 2 +- packages/client/ui-trajectory/package.json | 2 +- packages/client/ui-workflow-run/package.json | 2 +- packages/client/ui-workspace/package.json | 2 +- packages/client/web-react/package.json | 2 +- packages/client/web/package.json | 2 +- .../code-runtime-worker/package.json | 2 +- .../code-runtime/code-runtime/package.json | 2 +- packages/compact/command-compact/package.json | 2 +- packages/compact/compact-basic/package.json | 2 +- .../compact-tool-result-prune/package.json | 2 +- packages/compact/compact/package.json | 2 +- .../context/session-reference/package.json | 2 +- packages/context/time-context/package.json | 2 +- packages/context/tmux-context/package.json | 2 +- .../context/workspace-context/package.json | 2 +- .../core/agent-default-model/package.json | 2 +- packages/core/agent-loop/package.json | 2 +- packages/core/agent-tool-mode/package.json | 2 +- packages/core/agent/package.json | 2 +- packages/core/scope/package.json | 2 +- packages/core/session/package.json | 2 +- packages/core/system-prompt/package.json | 2 +- packages/core/tools/package.json | 2 +- .../credentials-local/package.json | 2 +- packages/credentials/credentials/package.json | 2 +- packages/e2b/e2b/package.json | 2 +- packages/e2b/fs-e2b/package.json | 2 +- packages/e2b/subprocess-e2b/package.json | 2 +- packages/examples/acp-demo/package.json | 2 +- .../examples/agent-spine-demo/package.json | 2 +- packages/examples/jsonrpc-demo/package.json | 2 +- .../feedback/command-feedback/package.json | 2 +- .../feedback/message-feedback/package.json | 2 +- packages/fs/fs-local/package.json | 2 +- packages/fs/fs-policy/package.json | 2 +- packages/fs/fs-sandbox/package.json | 2 +- packages/fs/fs/package.json | 2 +- packages/fs/tool-fs-search/package.json | 2 +- packages/fs/tool-fs/package.json | 2 +- .../fs/tool-str-replace-editor/package.json | 2 +- packages/goal/command-goal/package.json | 2 +- packages/goal/goal-session/package.json | 2 +- packages/goal/goal/package.json | 2 +- packages/goal/tool-goal/package.json | 2 +- packages/guard/repeat-tool-guard/package.json | 2 +- packages/guard/timeout-policy/package.json | 2 +- packages/hooks/hook-protocol/package.json | 2 +- packages/hooks/hooks-claude/package.json | 2 +- packages/hooks/hooks-codex/package.json | 2 +- packages/host/apiproxy/package.json | 2 +- .../host/directory-picker-auto/package.json | 2 +- .../host/directory-picker-browse/package.json | 2 +- .../host/directory-picker-native/package.json | 2 +- packages/host/directory-picker/package.json | 2 +- packages/host/frontend-static/package.json | 2 +- packages/host/webserver/package.json | 2 +- packages/interaction/commands/package.json | 2 +- packages/interaction/permission/package.json | 2 +- .../interaction/tool-ask-user/package.json | 2 +- .../interaction/user-approval/package.json | 2 +- .../interaction/user-interaction/package.json | 2 +- packages/llm/llm-deepseek/package.json | 2 +- packages/llm/llm-pi-ai/package.json | 2 +- packages/llm/llm-retry/package.json | 2 +- packages/llm/llm/package.json | 2 +- packages/llm/token-meter/package.json | 2 +- packages/lsp/lsp-local/package.json | 2 +- packages/lsp/lsp/package.json | 2 +- packages/lsp/tool-lsp/package.json | 2 +- packages/mcp/mcp-client/package.json | 2 +- packages/plan/plan-mode/package.json | 2 +- packages/preset/agent-presets/package.json | 2 +- packages/preset/persona/package.json | 2 +- packages/pty/pty-local/package.json | 2 +- packages/pty/pty/package.json | 2 +- .../pty/tool-bash-persistent/package.json | 2 +- packages/pty/tool-pty/package.json | 2 +- packages/sandbox/sandbox-local/package.json | 2 +- packages/sandbox/sandbox-policy/package.json | 2 +- .../sandbox/sandbox-windows-acl/package.json | 2 +- packages/sandbox/sandbox/package.json | 2 +- packages/schedule/tool-schedule/package.json | 2 +- packages/sdk/client/package.json | 2 +- packages/sdk/protocol/package.json | 2 +- packages/sdk/server/package.json | 2 +- .../tool-cordis/package.json | 2 +- .../session-query-sqlite/package.json | 2 +- .../session-query/session-query/package.json | 2 +- .../tool-session-query/package.json | 2 +- .../session-checkpoint-policy/package.json | 2 +- .../session-persistence-jsonl/package.json | 2 +- .../session-persistence-sqlite/package.json | 2 +- .../session/session-persistence/package.json | 2 +- .../session-projection-cache/package.json | 2 +- .../session/session-projection/package.json | 2 +- .../session-telemetry-otel/package.json | 2 +- .../session/session-telemetry/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../session/session-title-llm/package.json | 2 +- packages/session/session-title/package.json | 2 +- packages/session/user-id/package.json | 2 +- packages/settings/settings-local/package.json | 2 +- packages/settings/settings/package.json | 2 +- packages/skill/skill-badge/package.json | 2 +- packages/skill/skill-local/package.json | 2 +- packages/skill/skill/package.json | 2 +- packages/skill/tool-skill/package.json | 2 +- packages/spill/spill-local/package.json | 2 +- packages/spill/spill-policy/package.json | 2 +- packages/spill/spill/package.json | 2 +- packages/storage/storage-domain/package.json | 2 +- packages/storage/storage-json/package.json | 2 +- packages/storage/storage-sqlite/package.json | 2 +- packages/storage/storage/package.json | 2 +- packages/subagent/subagent-acp/package.json | 2 +- .../subagent-claude-code/package.json | 2 +- packages/subagent/subagent-codex/package.json | 2 +- .../subagent/subagent-dsh-sdk/package.json | 2 +- packages/subagent/subagent-fork/package.json | 2 +- .../subagent/subagent-inprocess/package.json | 2 +- packages/subagent/subagent-spawn/package.json | 2 +- packages/subagent/subagent/package.json | 2 +- .../tool-subagent-control/package.json | 2 +- .../tool-subagent-report/package.json | 2 +- packages/subagent/tool-subagent/package.json | 2 +- .../subprocess/subprocess-local/package.json | 2 +- packages/subprocess/subprocess/package.json | 2 +- packages/support/acp-snapshot/package.json | 2 +- .../support/agent-loop-testkit/package.json | 2 +- packages/support/invariants/package.json | 2 +- packages/support/llm-mock-server/package.json | 2 +- packages/support/llm-replay/package.json | 2 +- packages/support/loader-smoke/package.json | 2 +- packages/tasks/tasks-local/package.json | 2 +- packages/tasks/tasks/package.json | 2 +- packages/tasks/tool-tasks/package.json | 2 +- packages/todo/tool-todo/package.json | 2 +- packages/typert/generator/package.json | 2 +- packages/typert/loader/package.json | 2 +- packages/typert/registry/package.json | 2 +- packages/typert/type-meta/package.json | 2 +- packages/util/atomic-write/package.json | 2 +- packages/util/brand/package.json | 2 +- packages/util/environment/package.json | 2 +- packages/util/native-command/package.json | 2 +- packages/util/paths/package.json | 2 +- packages/util/retention/package.json | 2 +- packages/util/timeout/package.json | 2 +- packages/web/tool-web/package.json | 2 +- packages/web/web-fetch-local/package.json | 2 +- packages/web/web-search-deepseek/package.json | 2 +- packages/web/web-search-exa/package.json | 2 +- .../web/web-search-perplexity/package.json | 2 +- packages/web/web/package.json | 2 +- packages/workflow/tool-ralph/package.json | 2 +- packages/workflow/tool-workflow/package.json | 2 +- .../workflow-workerthread/package.json | 2 +- packages/workflow/workflow/package.json | 2 +- packages/workspace/workspace/package.json | 2 +- pnpm-lock.yaml | 90 +++++++++---------- 213 files changed, 257 insertions(+), 257 deletions(-) diff --git a/apps/cli/package.json b/apps/cli/package.json index 178f2690f2..cc9b448b2f 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh", "description": "dsh CLI: profile boot, plugin management, and the browser UI alias", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/apps/web/package.json b/apps/web/package.json index aed4488355..32edacefec 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-frontend", "description": "Web application entry: vite build over the @deepseek-ai/dsh-client-web shell library; dist/ served by apps/cli's dsh web", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/package.json b/package.json index e1e64e5c46..5760b0497b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@deepseek-ai/dsh-root", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "private": true, "type": "module", "packageManager": "pnpm@11.7.0", diff --git a/packages/acp/acp/package.json b/packages/acp/acp/package.json index b244c0367d..ff5a52bc63 100644 --- a/packages/acp/acp/package.json +++ b/packages/acp/acp/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-acp", "description": "Automation-only Agent Client Protocol server for driving DeepSeek Harness agents over JSON-RPC stdio", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/api/gateway/package.json b/packages/api/gateway/package.json index 48615dc55f..bd1dc63adc 100644 --- a/packages/api/gateway/package.json +++ b/packages/api/gateway/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-api-gateway", "description": "TypeRT Remote Host dispatcher and Client API endpoint", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/api/remotes/package.json b/packages/api/remotes/package.json index 56ade19443..30ebcb3195 100644 --- a/packages/api/remotes/package.json +++ b/packages/api/remotes/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-api-remotes", "description": "Remote BFF assembly and Host Agent/Session lookup policy", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/attachment/attachment-local/package.json b/packages/attachment/attachment-local/package.json index 3bbf361032..47244229ec 100644 --- a/packages/attachment/attachment-local/package.json +++ b/packages/attachment/attachment-local/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-attachment-local", "description": "Private content-addressed DSH_HOME attachment storage", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/attachment/attachment/package.json b/packages/attachment/attachment/package.json index 1fa800d2bf..1d608778c0 100644 --- a/packages/attachment/attachment/package.json +++ b/packages/attachment/attachment/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-attachment", "description": "Durable immutable attachment storage seam for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/bash/bash-env/package.json b/packages/bash/bash-env/package.json index acde7f422f..c1aea0a05f 100644 --- a/packages/bash/bash-env/package.json +++ b/packages/bash/bash-env/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-bash-env", "description": "Tool-independent managed DSH_* shell environment registry", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/bash/bash-local/package.json b/packages/bash/bash-local/package.json index 4b1b831c55..6afe6c72f9 100644 --- a/packages/bash/bash-local/package.json +++ b/packages/bash/bash-local/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-bash-local", "description": "Local-subprocess implementation of the DeepSeek Harness bash executor seam", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/bash/bash-sandbox/package.json b/packages/bash/bash-sandbox/package.json index 293748a67e..8814ac0819 100644 --- a/packages/bash/bash-sandbox/package.json +++ b/packages/bash/bash-sandbox/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-bash-sandbox", "description": "Sandbox-consuming implementation of the DeepSeek Harness bash executor seam (confines every command via ctx.sandbox, reports denial/enforcement result facts)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/bash/bash/package.json b/packages/bash/bash/package.json index f97d4b1f74..c3915573aa 100644 --- a/packages/bash/bash/package.json +++ b/packages/bash/bash/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-bash", "description": "Abstract bash executor seam (ctx.bash) for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/bash/pwsh-local/package.json b/packages/bash/pwsh-local/package.json index aac75796a7..f62ff9b2ce 100644 --- a/packages/bash/pwsh-local/package.json +++ b/packages/bash/pwsh-local/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-pwsh-local", "description": "Local PowerShell implementation of the DeepSeek Harness bash executor seam", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/bash/pwsh-sandbox/package.json b/packages/bash/pwsh-sandbox/package.json index 53e418f401..ba88837a61 100644 --- a/packages/bash/pwsh-sandbox/package.json +++ b/packages/bash/pwsh-sandbox/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-pwsh-sandbox", "description": "Sandbox-consuming implementation of the DeepSeek Harness PowerShell executor seam (confines every command via ctx.sandbox, reports denial/enforcement result facts)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/bash/tool-bash/package.json b/packages/bash/tool-bash/package.json index 9da6eb65ca..877a1e4926 100644 --- a/packages/bash/tool-bash/package.json +++ b/packages/bash/tool-bash/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-bash", "description": "Model-facing bash tool with optional generic background-task and sandbox-escalation support", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/bash/tool-pwsh/package.json b/packages/bash/tool-pwsh/package.json index 0b93e820c2..620d5c2523 100644 --- a/packages/bash/tool-pwsh/package.json +++ b/packages/bash/tool-pwsh/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-pwsh", "description": "Model-facing pwsh tool over the bash executor seam", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/boot/app-boot/package.json b/packages/boot/app-boot/package.json index f6d4cfc07d..c1f1031511 100644 --- a/packages/boot/app-boot/package.json +++ b/packages/boot/app-boot/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-app-boot", "description": "Shared boot glue for the app bins: .env loading, fail-loud Loader guards, snapshot-aware config resolution, and the Loader boot sequence", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/boot/cmdline/package.json b/packages/boot/cmdline/package.json index 9b30a9f7c5..ba9622b20b 100644 --- a/packages/boot/cmdline/package.json +++ b/packages/boot/cmdline/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-cmdline", "description": "Immutable command-line handoff from a dsh launcher to any app plugin that injects cmdlineArgs", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/bundle/base/package.json b/packages/bundle/base/package.json index 655de66ec0..50e57017d4 100644 --- a/packages/bundle/base/package.json +++ b/packages/bundle/base/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-base", "description": "The shared dsh core as a profile bundle: every profile's first patch layer, inserting the base plugin rows over the empty profile root", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/bundle/headless/package.json b/packages/bundle/headless/package.json index af0935d2a4..01886ac3b0 100644 --- a/packages/bundle/headless/package.json +++ b/packages/bundle/headless/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-headless", "description": "The dsh one-shot bundle: a direct core Agent/Session runner over dsh-base with no Host, HTTP, or browser layer", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/bundle/web-app/package.json b/packages/bundle/web-app/package.json index 51de2e02fd..4219449a14 100644 --- a/packages/bundle/web-app/package.json +++ b/packages/bundle/web-app/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-web-app", "description": "The dsh browser-surface bundle: the web patch layer over dsh-base plus the runtime glue plugin (frontend dist serving, web-surface prompt, bash runtime variables, URL line)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/connection/package.json b/packages/client/connection/package.json index 025b5ffb90..40ff58ffac 100644 --- a/packages/client/connection/package.json +++ b/packages/client/connection/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-connection", "description": "Wire consumer layer: HTTP-up/WebSocket-down client, ConnectionController dual streams with reconnect, and fixture api", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/hmr/package.json b/packages/client/hmr/package.json index 6e7614bc27..3264315e15 100644 --- a/packages/client/hmr/package.json +++ b/packages/client/hmr/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-hmr", "description": "Dev-only hot-reload driver for script-loaded client entries: SSE rebuilt frames → invalidate/prefetch → fiber swap through the vendored Loader entry", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/locale/package.json b/packages/client/locale/package.json index cc527dee85..d7d7b54ca7 100644 --- a/packages/client/locale/package.json +++ b/packages/client/locale/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-locale", "description": "Locale plugin: Host-backed zh/en preference, browser-derived fallback, locale snapshots, and typed namespace dictionaries", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/modules/package.json b/packages/client/modules/package.json index 3d97f98fa6..f7d541bdc0 100644 --- a/packages/client/modules/package.json +++ b/packages/client/modules/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-modules", "description": "Client module system, dual-face: node half composes the __DSH_BOOT__ entry graph (incremental dsh.client scan, bundle route, index tap, webPlugins service); browser half is the lazy-CJS module table the vendored cordis Loader consumes as its internal seam", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/runtime/package.json b/packages/client/runtime/package.json index f57f9e4952..be2bfa4172 100644 --- a/packages/client/runtime/package.json +++ b/packages/client/runtime/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-runtime", "description": "Client core services: SlotsService, SessionsService (scope tree + object layer)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/schema-form/package.json b/packages/client/schema-form/package.json index 90f59b329a..becc40b0fb 100644 --- a/packages/client/schema-form/package.json +++ b/packages/client/schema-form/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-schema-form", "description": "Schema/draft model layer for settings editors: rehydrates a serialized schemastery schema, validates drafts, and edits them immutably by path", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/test-runtime/package.json b/packages/client/test-runtime/package.json index 96f3add186..54d3e8e8c1 100644 --- a/packages/client/test-runtime/package.json +++ b/packages/client/test-runtime/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-test-runtime", "description": "jsdom slot test runtime: real Cordis Context + SlotsService + web-react renderer with test-owned session/workspace doubles for feature specs", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-agent-preset/package.json b/packages/client/ui-agent-preset/package.json index aab0727a7f..c8dfe83c54 100644 --- a/packages/client/ui-agent-preset/package.json +++ b/packages/client/ui-agent-preset/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-agent-preset", "description": "Agent-preset surfaces: the default for later sessions, this session's seat, and the composition editor", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-attachment/package.json b/packages/client/ui-attachment/package.json index e894a42196..a9c5124414 100644 --- a/packages/client/ui-attachment/package.json +++ b/packages/client/ui-attachment/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-attachment", "description": "Pure React attachment atoms for the dsh web UI: draft-image rail, message image gallery, and original-image lightbox (zero cordis)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-command/package.json b/packages/client/ui-command/package.json index 7a13ed5bd5..6a58ff6603 100644 --- a/packages/client/ui-command/package.json +++ b/packages/client/ui-command/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-command", "description": "Client command surface: global directory cache, '/' source, three command UI kinds, popupSelect registry", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-conversation/package.json b/packages/client/ui-conversation/package.json index 2f4258639b..a9996ce09a 100644 --- a/packages/client/ui-conversation/package.json +++ b/packages/client/ui-conversation/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-conversation", "description": "Conversation domain: skeleton, ordered chat flow, composer with the Host-backed busy-Enter preference, and details host", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-deliverables/package.json b/packages/client/ui-deliverables/package.json index 2a69585645..4d7ea0d314 100644 --- a/packages/client/ui-deliverables/package.json +++ b/packages/client/ui-deliverables/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-deliverables", "description": "Produced-files turn tail: the deliverables row a finished turn ends with", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-goal/package.json b/packages/client/ui-goal/package.json index 28dfd38d56..fde636b09e 100644 --- a/packages/client/ui-goal/package.json +++ b/packages/client/ui-goal/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-goal", "description": "Session goal surface: GoalBar docked above the composer, read from the goal session projection", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-layout/package.json b/packages/client/ui-layout/package.json index 232c4606ab..e6115e60ab 100644 --- a/packages/client/ui-layout/package.json +++ b/packages/client/ui-layout/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-layout", "description": "Shell plugin: three-column AppFrame with drag handles, ctx.layout viewing-state service (navigation + panels)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-model/package.json b/packages/client/ui-model/package.json index 1e4e70e356..09e4b5eb85 100644 --- a/packages/client/ui-model/package.json +++ b/packages/client/ui-model/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-model", "description": "Model selection: the /model popupSelect over session.models / session.selectModel", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-models/package.json b/packages/client/ui-models/package.json index bb4dd16fb8..0098cfd1d3 100644 --- a/packages/client/ui-models/package.json +++ b/packages/client/ui-models/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-models", "description": "Models settings and official-DeepSeek first-run routing over one live provider/settings/credential join", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-permission/package.json b/packages/client/ui-permission/package.json index 5e5c390cc2..f5e372a0f9 100644 --- a/packages/client/ui-permission/package.json +++ b/packages/client/ui-permission/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-permission", "description": "Permission surfaces: a new-session default in General settings and a current-session /permission popup over the permissions projection", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-plan/package.json b/packages/client/ui-plan/package.json index 3ee6860ce5..0a8f1512bf 100644 --- a/packages/client/ui-plan/package.json +++ b/packages/client/ui-plan/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-plan", "description": "Plan-mode composer control: the conversation.input.plan seat over the plan projection and the /plan command channel", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-plugin-config/package.json b/packages/client/ui-plugin-config/package.json index a1460e64f0..dd4d808789 100644 --- a/packages/client/ui-plugin-config/package.json +++ b/packages/client/ui-plugin-config/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-plugin-config", "description": "Plugin configuration section: host-plane plugin settings as expandable cards", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-primitives/package.json b/packages/client/ui-primitives/package.json index 05dbe8f822..a2ce6a4d39 100644 --- a/packages/client/ui-primitives/package.json +++ b/packages/client/ui-primitives/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-primitives", "description": "Pure React atoms for the dsh web UI: controls, icons, markdown, and JSON inspectors (zero cordis)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-question/package.json b/packages/client/ui-question/package.json index aafb3bf534..cb74154ff0 100644 --- a/packages/client/ui-question/package.json +++ b/packages/client/ui-question/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-question", "description": "Web ask_user_question feature: host tool mount plus composer-takeover question UI", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-settings-general/package.json b/packages/client/ui-settings-general/package.json index 89e5fcfa0d..29391c3f00 100644 --- a/packages/client/ui-settings-general/package.json +++ b/packages/client/ui-settings-general/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-settings-general", "description": "Settings ownerless-copy and product onboarding plugin: the General section, shell trigger/header chrome content, settings dictionaries, and the versioned welcome notice", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-settings/package.json b/packages/client/ui-settings/package.json index 56009fca92..d1da7f46a2 100644 --- a/packages/client/ui-settings/package.json +++ b/packages/client/ui-settings/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-settings", "description": "Settings domain base plugin: the settings-namespace scope service and the canonical settings slot-type contract", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-sidebar/package.json b/packages/client/ui-sidebar/package.json index 73ce0817d7..3f1d00963f 100644 --- a/packages/client/ui-sidebar/package.json +++ b/packages/client/ui-sidebar/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-sidebar", "description": "Sidebar plugin: session multi-level tree, search, grouping, state dots", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-skill/package.json b/packages/client/ui-skill/package.json index cc6dd4bb60..82f80bccca 100644 --- a/packages/client/ui-skill/package.json +++ b/packages/client/ui-skill/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-skill", "description": "Web skill references and the dedicated skill tool row", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-slash/package.json b/packages/client/ui-slash/package.json index 485052ae5f..c0a1fcd48a 100644 --- a/packages/client/ui-slash/package.json +++ b/packages/client/ui-slash/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-slash", "description": "Input trigger pipeline: '/' and '@' detection, candidate menu, pick routing to registered sources", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-slots/package.json b/packages/client/ui-slots/package.json index 85a8886519..2d045c3d60 100644 --- a/packages/client/ui-slots/package.json +++ b/packages/client/ui-slots/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-slots", "description": "Slot registry pure core: SlotMap declaration merging, single register composition API, four-share props types, store-seat types, renderer install seam", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-subagent/package.json b/packages/client/ui-subagent/package.json index 75e5b53af7..208023446a 100644 --- a/packages/client/ui-subagent/package.json +++ b/packages/client/ui-subagent/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-subagent", "description": "Subagent conversation catalog, continuation routing UI, and '@' reference source", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-task/package.json b/packages/client/ui-task/package.json index c8354f8f6c..4fb6a48f6e 100644 --- a/packages/client/ui-task/package.json +++ b/packages/client/ui-task/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-task", "description": "Session-header background-task list: live registry state mirrored from session/tasks frames", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "type": "module", "main": "lib/index.js", "types": "lib/types/index.d.ts", diff --git a/packages/client/ui-theme/package.json b/packages/client/ui-theme/package.json index f2b8a683be..34d627a2ad 100644 --- a/packages/client/ui-theme/package.json +++ b/packages/client/ui-theme/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-theme", "description": "Theme plugin: Host bootstrap for the pre-plugin palette; DOM-free ThemeService for light/dark/system state; --dsw-* token styles and Appearance settings row", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-tool/package.json b/packages/client/ui-tool/package.json index 6644d1d506..398831749b 100644 --- a/packages/client/ui-tool/package.json +++ b/packages/client/ui-tool/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-tool", "description": "Client Tool call-tree renderer and keyed per-tool presentation slot", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-trajectory/package.json b/packages/client/ui-trajectory/package.json index 725dc11d5f..54aa132b09 100644 --- a/packages/client/ui-trajectory/package.json +++ b/packages/client/ui-trajectory/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-trajectory", "description": "Trajectory event ledger with an interactive timing overview: pure-consumer plugin registering into the conversation ViewMap (no service)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-workflow-run/package.json b/packages/client/ui-workflow-run/package.json index 001d2ae058..764363578b 100644 --- a/packages/client/ui-workflow-run/package.json +++ b/packages/client/ui-workflow-run/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-workflow-run", "description": "Durable workflow-run Conversation Node and nested member disclosure for dsh web", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/ui-workspace/package.json b/packages/client/ui-workspace/package.json index f19c44ea57..77b5ffded2 100644 --- a/packages/client/ui-workspace/package.json +++ b/packages/client/ui-workspace/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-ui-workspace", "description": "Workspace picker plugin: one WorkspacePicker registered into the sidebar and empty-state workspace slots", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/web-react/package.json b/packages/client/web-react/package.json index 16bab468df..0f64920755 100644 --- a/packages/client/web-react/package.json +++ b/packages/client/web-react/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-web-react", "description": "Shell-side React glue: createSlotRenderer, SessionProvider, bindSnapshotSelector (uSES bridge), useInvoke", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/client/web/package.json b/packages/client/web/package.json index d23c343b3c..d448b71d0d 100644 --- a/packages/client/web/package.json +++ b/packages/client/web/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-client-web", "description": "Web shell kernel: bootWebShell (module system holding + seed table + two-stage boot + AppRoot gate + app-shell assembly entry), consumed by the apps/web vite entry", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/code-runtime/code-runtime-worker/package.json b/packages/code-runtime/code-runtime-worker/package.json index 2614be990a..30648ea699 100644 --- a/packages/code-runtime/code-runtime-worker/package.json +++ b/packages/code-runtime/code-runtime-worker/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-code-runtime-worker", "description": "Worker-thread implementation of the DeepSeek Harness code-execution seam", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/code-runtime/code-runtime/package.json b/packages/code-runtime/code-runtime/package.json index 8d4e77136b..c3ede79ac5 100644 --- a/packages/code-runtime/code-runtime/package.json +++ b/packages/code-runtime/code-runtime/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-code-runtime", "description": "Abstract code-execution seam (ctx.codeRuntime) for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/compact/command-compact/package.json b/packages/compact/command-compact/package.json index 83df4eae98..716d033855 100644 --- a/packages/compact/command-compact/package.json +++ b/packages/compact/command-compact/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-command-compact", "description": "Human-facing slash command for explicit session compaction", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/compact/compact-basic/package.json b/packages/compact/compact-basic/package.json index 75e0dcd959..17ac1fb46b 100644 --- a/packages/compact/compact-basic/package.json +++ b/packages/compact/compact-basic/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-compact-basic", "description": "Token-meter-driven compaction policy and LLM summarization backend for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/compact/compact-tool-result-prune/package.json b/packages/compact/compact-tool-result-prune/package.json index 26f216a4dd..09c96af730 100644 --- a/packages/compact/compact-tool-result-prune/package.json +++ b/packages/compact/compact-tool-result-prune/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-compact-tool-result-prune", "description": "Replay-safe model-free head/middle/tail pruning for tool-result surface nodes", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/compact/compact/package.json b/packages/compact/compact/package.json index 6f484bf8f6..0876a1d596 100644 --- a/packages/compact/compact/package.json +++ b/packages/compact/compact/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-compact", "description": "Abstract compaction service seam (ctx.compact) for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/context/session-reference/package.json b/packages/context/session-reference/package.json index c9dcb6af03..2d8b0289f8 100644 --- a/packages/context/session-reference/package.json +++ b/packages/context/session-reference/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-session-reference", "description": "Cross-session snapshot references and durable untrusted model context (ctx.sessionReferences)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/context/time-context/package.json b/packages/context/time-context/package.json index c1c222bd6f..f267433217 100644 --- a/packages/context/time-context/package.json +++ b/packages/context/time-context/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-time-context", "description": "Opt-in durable per-step context with the current time and elapsed time", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/context/tmux-context/package.json b/packages/context/tmux-context/package.json index 6a4d7b81d8..f12773ffab 100644 --- a/packages/context/tmux-context/package.json +++ b/packages/context/tmux-context/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tmux-context", "description": "Opt-in durable per-step context with this agent's tmux pane and window location", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/context/workspace-context/package.json b/packages/context/workspace-context/package.json index 9181b2aded..3016fdd849 100644 --- a/packages/context/workspace-context/package.json +++ b/packages/context/workspace-context/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-workspace-context", "description": "Workspace context loader for AGENTS.md/CLAUDE.md instruction files", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/core/agent-default-model/package.json b/packages/core/agent-default-model/package.json index 6e3f6c0413..89eaf0e617 100644 --- a/packages/core/agent-default-model/package.json +++ b/packages/core/agent-default-model/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-agent-default-model", "description": "Default model selection shared by Agent entry points", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/core/agent-loop/package.json b/packages/core/agent-loop/package.json index 8bfbe38cfe..c268434dc4 100644 --- a/packages/core/agent-loop/package.json +++ b/packages/core/agent-loop/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-agent-loop", "description": "The concrete agent loop plugin for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/core/agent-tool-mode/package.json b/packages/core/agent-tool-mode/package.json index e0d35abf0f..3f392f2024 100644 --- a/packages/core/agent-tool-mode/package.json +++ b/packages/core/agent-tool-mode/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-agent-tool-mode", "description": "Agent-plane presentation selector: composes one agent's tools as Code Mode, native, or both", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/core/agent/package.json b/packages/core/agent/package.json index 6c85552224..b739469d16 100644 --- a/packages/core/agent/package.json +++ b/packages/core/agent/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-agent", "description": "Agent interface, registry, initiator scope, and event vocabulary for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/core/scope/package.json b/packages/core/scope/package.json index d0a67e8841..a8f386e480 100644 --- a/packages/core/scope/package.json +++ b/packages/core/scope/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-scope", "description": "Scoped-context registration primitive (scope tags, scope-filtered event dispatch) for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/core/session/package.json b/packages/core/session/package.json index 3528334b3c..02df5d6db3 100644 --- a/packages/core/session/package.json +++ b/packages/core/session/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-session", "description": "Event-sourced session store for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/core/system-prompt/package.json b/packages/core/system-prompt/package.json index 1f411b554f..769f9df9cf 100644 --- a/packages/core/system-prompt/package.json +++ b/packages/core/system-prompt/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-system-prompt", "description": "System prompt assembly registry for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/core/tools/package.json b/packages/core/tools/package.json index 6634098f99..c3ef8f8ea7 100644 --- a/packages/core/tools/package.json +++ b/packages/core/tools/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tools", "description": "Tool registry and execution pipeline for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/credentials/credentials-local/package.json b/packages/credentials/credentials-local/package.json index 977c51013c..6f3276a81b 100644 --- a/packages/credentials/credentials-local/package.json +++ b/packages/credentials/credentials-local/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-credentials-local", "description": "File-backed credentials provider ($DSH_HOME/.env under the live process environment) for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/credentials/credentials/package.json b/packages/credentials/credentials/package.json index 8fbcf111bf..0909354c56 100644 --- a/packages/credentials/credentials/package.json +++ b/packages/credentials/credentials/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-credentials", "description": "Abstract credential seam (ctx.credentials): settings carry references to secrets, providers own the values", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/e2b/e2b/package.json b/packages/e2b/e2b/package.json index dafbb57b00..ebe99f6cf8 100644 --- a/packages/e2b/e2b/package.json +++ b/packages/e2b/e2b/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-e2b", "description": "Shared E2B sandbox lifecycle for DeepSeek Harness provider adapters", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/e2b/fs-e2b/package.json b/packages/e2b/fs-e2b/package.json index 1f6e085e5f..3b87b3ca46 100644 --- a/packages/e2b/fs-e2b/package.json +++ b/packages/e2b/fs-e2b/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-fs-e2b", "description": "E2B filesystem implementation for DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/e2b/subprocess-e2b/package.json b/packages/e2b/subprocess-e2b/package.json index dfbdf73da5..ece30dfd8c 100644 --- a/packages/e2b/subprocess-e2b/package.json +++ b/packages/e2b/subprocess-e2b/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-subprocess-e2b", "description": "E2B subprocess implementation for DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/examples/acp-demo/package.json b/packages/examples/acp-demo/package.json index 1d35f2b23f..c63f5808ff 100644 --- a/packages/examples/acp-demo/package.json +++ b/packages/examples/acp-demo/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-acp-demo", "description": "ACP automation server app: agent spine + JSONL persistence + ACP transport, with a JSON-RPC stdio bin", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/examples/agent-spine-demo/package.json b/packages/examples/agent-spine-demo/package.json index 2092965d75..661136d17f 100644 --- a/packages/examples/agent-spine-demo/package.json +++ b/packages/examples/agent-spine-demo/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-agent-spine-demo", "description": "The default executor-less/UI-less agent spine with fallback session titles, provider-routed retry, and optional persisted goals", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/examples/jsonrpc-demo/package.json b/packages/examples/jsonrpc-demo/package.json index 2524d75378..1224b63c7a 100644 --- a/packages/examples/jsonrpc-demo/package.json +++ b/packages/examples/jsonrpc-demo/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-jsonrpc-demo", "description": "Bin that boots an external Cordis config for the stdio JSON-RPC SDK runtime", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/feedback/command-feedback/package.json b/packages/feedback/command-feedback/package.json index f45d504814..0a805e1537 100644 --- a/packages/feedback/command-feedback/package.json +++ b/packages/feedback/command-feedback/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-command-feedback", "description": "Log-only session feedback producer and human-facing slash command", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/feedback/message-feedback/package.json b/packages/feedback/message-feedback/package.json index fe0caa18fb..53f85868c2 100644 --- a/packages/feedback/message-feedback/package.json +++ b/packages/feedback/message-feedback/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-message-feedback", "description": "Lifecycle-bound per-message rating and note sidecar for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/fs/fs-local/package.json b/packages/fs/fs-local/package.json index 77ed82d979..437e9ff7ec 100644 --- a/packages/fs/fs-local/package.json +++ b/packages/fs/fs-local/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-fs-local", "description": "Local-filesystem implementation of the DeepSeek Harness filesystem seam (ctx.fs)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/fs/fs-policy/package.json b/packages/fs/fs-policy/package.json index 4f731e6559..efa65e6813 100644 --- a/packages/fs/fs-policy/package.json +++ b/packages/fs/fs-policy/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-fs-policy", "description": "File-context policy plugin for the DeepSeek Harness — observed-state, read-before-edit, and version-guarded write/edit added over the ctx.fs provider seam through the fs/* event gate (no service API)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/fs/fs-sandbox/package.json b/packages/fs/fs-sandbox/package.json index cc6daed922..4d0969121f 100644 --- a/packages/fs/fs-sandbox/package.json +++ b/packages/fs/fs-sandbox/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-fs-sandbox", "description": "Sandbox-enforcing implementation of the DeepSeek Harness filesystem seam: fences write/edit by the per-call sandbox mode (read-only denies mutation, workspace-write contains it to the workspace + temp roots) while reads pass through", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/fs/fs/package.json b/packages/fs/fs/package.json index e9779e9d96..5af7eb2600 100644 --- a/packages/fs/fs/package.json +++ b/packages/fs/fs/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-fs", "description": "Abstract filesystem capability seam (ctx.fs) for the DeepSeek Harness — vocabulary types, the FileSystem service (text IO + optional version-guarded atomic mutations), and the fs/* policy event vocabulary", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/fs/tool-fs-search/package.json b/packages/fs/tool-fs-search/package.json index ca56b0198a..9df7901979 100644 --- a/packages/fs/tool-fs-search/package.json +++ b/packages/fs/tool-fs-search/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-fs-search", "description": "Model-facing filesystem discovery tools (glob, grep) backed by the packaged ripgrep binary (@vscode/ripgrep)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/fs/tool-fs/package.json b/packages/fs/tool-fs/package.json index 65db543d26..ed4524c227 100644 --- a/packages/fs/tool-fs/package.json +++ b/packages/fs/tool-fs/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-fs", "description": "Model-facing filesystem tools (read, write, edit) over the DeepSeek Harness filesystem seam (ctx.fs)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/fs/tool-str-replace-editor/package.json b/packages/fs/tool-str-replace-editor/package.json index 5b20d4afc4..c3acc317ac 100644 --- a/packages/fs/tool-str-replace-editor/package.json +++ b/packages/fs/tool-str-replace-editor/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-str-replace-editor", "description": "Model-facing view, create, literal replace, and line insert tool over the Harness filesystem service", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/goal/command-goal/package.json b/packages/goal/command-goal/package.json index b87f385599..edb52363c0 100644 --- a/packages/goal/command-goal/package.json +++ b/packages/goal/command-goal/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-command-goal", "description": "Human-facing slash command for persisted same-session goals", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/goal/goal-session/package.json b/packages/goal/goal-session/package.json index fa42ef63d3..37c42bf3c4 100644 --- a/packages/goal/goal-session/package.json +++ b/packages/goal/goal-session/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-goal-session", "description": "Race-fenced same-session goal-round driver", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/goal/goal/package.json b/packages/goal/goal/package.json index a2f90fced3..8a13ec7ceb 100644 --- a/packages/goal/goal/package.json +++ b/packages/goal/goal/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-goal", "description": "Event-sourced same-session goal state and lifecycle service for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/goal/tool-goal/package.json b/packages/goal/tool-goal/package.json index e83648ab97..e875dd8a4e 100644 --- a/packages/goal/tool-goal/package.json +++ b/packages/goal/tool-goal/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-goal", "description": "Model-facing same-session goal tools with execution-time authority checks", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/guard/repeat-tool-guard/package.json b/packages/guard/repeat-tool-guard/package.json index 27e7cc916e..f59ab2be2e 100644 --- a/packages/guard/repeat-tool-guard/package.json +++ b/packages/guard/repeat-tool-guard/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-repeat-tool-guard", "description": "Repeat-tool-call guard plugin: advisory reminders when an agent loops on identical tool calls", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/guard/timeout-policy/package.json b/packages/guard/timeout-policy/package.json index 4800c0f472..608f836a98 100644 --- a/packages/guard/timeout-policy/package.json +++ b/packages/guard/timeout-policy/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-timeout-policy", "description": "Tool-call timeout policy: a tools/execute wrapper that arms a per-tool deadline on exec.signal and returns TOOL_TIMEOUT when it wins", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/hooks/hook-protocol/package.json b/packages/hooks/hook-protocol/package.json index ad92d9dd78..a1f8519e71 100644 --- a/packages/hooks/hook-protocol/package.json +++ b/packages/hooks/hook-protocol/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-hook-protocol", "description": "Shared Claude Code / Codex hook wire protocol: matcher engine, stdin/exit-code/stdout codec, multi-hook merge, and hook/* session events", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/hooks/hooks-claude/package.json b/packages/hooks/hooks-claude/package.json index 9ed1ed7ceb..e5b218f4c2 100644 --- a/packages/hooks/hooks-claude/package.json +++ b/packages/hooks/hooks-claude/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-hooks-claude", "description": "Bridge plugin: run a Claude Code hooks.json / settings hook config on the DeepSeek Harness interception seams", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/hooks/hooks-codex/package.json b/packages/hooks/hooks-codex/package.json index a2bd73fba1..9471713885 100644 --- a/packages/hooks/hooks-codex/package.json +++ b/packages/hooks/hooks-codex/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-hooks-codex", "description": "Bridge plugin: run a Codex hooks.json hook config on the DeepSeek Harness interception seams", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/host/apiproxy/package.json b/packages/host/apiproxy/package.json index 1145ee492b..ca23793fe7 100644 --- a/packages/host/apiproxy/package.json +++ b/packages/host/apiproxy/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-host-apiproxy", "description": "API gateway: the ApiProxy contract (api/), the fetch carrier pair (fetch/), and the host-side gateway plugin providing ctx.apiProxy", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/host/directory-picker-auto/package.json b/packages/host/directory-picker-auto/package.json index 4ad110d48f..572c1045c8 100644 --- a/packages/host/directory-picker-auto/package.json +++ b/packages/host/directory-picker-auto/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-host-directory-picker-auto", "description": "Adaptive chooser of the directory-picker seam: resolves the host situation at boot and mounts the native or browse backend for the DeepSeek Harness web GUI host", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/host/directory-picker-browse/package.json b/packages/host/directory-picker-browse/package.json index 3b42032e16..f134a00dbf 100644 --- a/packages/host/directory-picker-browse/package.json +++ b/packages/host/directory-picker-browse/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-host-directory-picker-browse", "description": "In-app browsing backend of the directory-picker seam (listing/creation primitives over the host filesystem)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/host/directory-picker-native/package.json b/packages/host/directory-picker-native/package.json index 01817a238e..4465553e07 100644 --- a/packages/host/directory-picker-native/package.json +++ b/packages/host/directory-picker-native/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-host-directory-picker-native", "description": "Native-OS-chooser backend of the directory-picker seam for the DeepSeek Harness web GUI host", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/host/directory-picker/package.json b/packages/host/directory-picker/package.json index 0540414965..8b752bab20 100644 --- a/packages/host/directory-picker/package.json +++ b/packages/host/directory-picker/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-host-directory-picker", "description": "Abstract workspace-directory picking seam (ctx.directoryPicker) for the DeepSeek Harness web GUI host", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/host/frontend-static/package.json b/packages/host/frontend-static/package.json index 61c144abe9..0065234841 100644 --- a/packages/host/frontend-static/package.json +++ b/packages/host/frontend-static/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-frontend-static", "description": "SPA dist server for the Web shell: owns the webserver fallback seat, serving the built frontend with index-tap injection, traversal rejection, and SPA index fallback", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/host/webserver/package.json b/packages/host/webserver/package.json index 016ae8f253..1f3aba254e 100644 --- a/packages/host/webserver/package.json +++ b/packages/host/webserver/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-host-webserver", "description": "Web route-registration plugin: HTTP and upgrade routes, index transform taps, and static dist fallback; knows no harness concepts", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/interaction/commands/package.json b/packages/interaction/commands/package.json index 1db5c770d6..3865fbd2ae 100644 --- a/packages/interaction/commands/package.json +++ b/packages/interaction/commands/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-commands", "description": "Plugin-owned human command registry for DeepSeek Harness UIs", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/interaction/permission/package.json b/packages/interaction/permission/package.json index 054773f691..6d0a0773d7 100644 --- a/packages/interaction/permission/package.json +++ b/packages/interaction/permission/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-permission", "description": "User-facing permission presets (ctx.permission) for the DeepSeek Harness: one product-level Permissions select bundling the sandbox-mode and approval-policy knobs, written through to their own session events", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/interaction/tool-ask-user/package.json b/packages/interaction/tool-ask-user/package.json index dc025017e0..889f07c19b 100644 --- a/packages/interaction/tool-ask-user/package.json +++ b/packages/interaction/tool-ask-user/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-ask-user", "description": "Model-facing ask_user_question tool over the ctx.userInteraction seam", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/interaction/user-approval/package.json b/packages/interaction/user-approval/package.json index 37b29c4697..d4a9dfd8cf 100644 --- a/packages/interaction/user-approval/package.json +++ b/packages/interaction/user-approval/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-user-approval", "description": "User-approval seam (ctx.approval) for the DeepSeek Harness: one-shot permission decisions dispatched to composed answerers over the approval/request waterfall, fail-closed by default", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/interaction/user-interaction/package.json b/packages/interaction/user-interaction/package.json index fe90d7534c..fe65552533 100644 --- a/packages/interaction/user-interaction/package.json +++ b/packages/interaction/user-interaction/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-user-interaction", "description": "Abstract user-interaction seam (ctx.userInteraction) for asking the human during agent runs", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/llm/llm-deepseek/package.json b/packages/llm/llm-deepseek/package.json index 52b50283a8..2e2338d10d 100644 --- a/packages/llm/llm-deepseek/package.json +++ b/packages/llm/llm-deepseek/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-llm-deepseek", "description": "DeepSeek chat-completions adapter for the DeepSeek Harness LLM seam", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/llm/llm-pi-ai/package.json b/packages/llm/llm-pi-ai/package.json index 3d36802a3e..cbef9b89df 100644 --- a/packages/llm/llm-pi-ai/package.json +++ b/packages/llm/llm-pi-ai/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-llm-pi-ai", "description": "pi-ai-backed DeepSeek adapter for the DeepSeek Harness LLM seam (design-verification twin of dsh-llm-deepseek)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/llm/llm-retry/package.json b/packages/llm/llm-retry/package.json index da8358c620..b00ffdb2e6 100644 --- a/packages/llm/llm-retry/package.json +++ b/packages/llm/llm-retry/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-llm-retry", "description": "Provider-routed LLM request retry policy for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/llm/llm/package.json b/packages/llm/llm/package.json index 523ab16cb3..28f68802a5 100644 --- a/packages/llm/llm/package.json +++ b/packages/llm/llm/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-llm", "description": "Provider-neutral LLM service interface for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/llm/token-meter/package.json b/packages/llm/token-meter/package.json index ef08734fe2..f1158c0300 100644 --- a/packages/llm/token-meter/package.json +++ b/packages/llm/token-meter/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-token-meter", "description": "Replay-aware token measurement service (ctx.tokenMeter) for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/lsp/lsp-local/package.json b/packages/lsp/lsp-local/package.json index f31e48080f..33ada9d841 100644 --- a/packages/lsp/lsp-local/package.json +++ b/packages/lsp/lsp-local/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-lsp-local", "description": "Generic stdio language-server provider for the DeepSeek Harness LSP capability seam (ctx.lsp) — spawns configured servers, translates JSON-RPC, and serves transient-open goToDefinition/findReferences/goToImplementation/hover queries in the host filesystem namespace", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/lsp/lsp/package.json b/packages/lsp/lsp/package.json index 6395749c68..57e5d0f876 100644 --- a/packages/lsp/lsp/package.json +++ b/packages/lsp/lsp/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-lsp", "description": "Abstract LSP capability seam (ctx.lsp) for the DeepSeek Harness — language-server provider registry keyed by branded id and extension mapping, order-independent per-query selection, normalized definition/references/implementation/hover requests and results, and the LspError taxonomy", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/lsp/tool-lsp/package.json b/packages/lsp/tool-lsp/package.json index d4003a61e5..df9cb7a2ad 100644 --- a/packages/lsp/tool-lsp/package.json +++ b/packages/lsp/tool-lsp/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-lsp", "description": "Model-facing lsp tool over the DeepSeek Harness LSP capability seam (ctx.lsp) — one read-only tool with goToDefinition/findReferences/goToImplementation/hover operations, one-based UTF-16 cursor coordinates, bounded location rendering, and hover normalization", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/mcp/mcp-client/package.json b/packages/mcp/mcp-client/package.json index 1cd533c3db..cc68494a17 100644 --- a/packages/mcp/mcp-client/package.json +++ b/packages/mcp/mcp-client/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-mcp-client", "description": "MCP client bridge: connects to MCP servers and registers their tools on ctx.tools", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/plan/plan-mode/package.json b/packages/plan/plan-mode/package.json index 33b536d3ee..386cd76b96 100644 --- a/packages/plan/plan-mode/package.json +++ b/packages/plan/plan-mode/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-plan-mode", "description": "Logged per-agent plan mode with deployment guidance, a direct slash command, and a user-reviewed exit", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/preset/agent-presets/package.json b/packages/preset/agent-presets/package.json index 2a7dd7da63..08af1af854 100644 --- a/packages/preset/agent-presets/package.json +++ b/packages/preset/agent-presets/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-agent-presets", "description": "Per-session agent composition from preset cordis.yml files for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/preset/persona/package.json b/packages/preset/persona/package.json index 7a9c4cd746..b6c343f9a4 100644 --- a/packages/preset/persona/package.json +++ b/packages/preset/persona/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-persona", "description": "Composition-authored deployment persona section for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/pty/pty-local/package.json b/packages/pty/pty-local/package.json index 3db9e83889..47a24fdf0a 100644 --- a/packages/pty/pty-local/package.json +++ b/packages/pty/pty-local/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-pty-local", "description": "Persistent shell PTY backend over the DeepSeek Harness subprocess terminal primitive", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/pty/pty/package.json b/packages/pty/pty/package.json index 37837181fb..6bd31798d8 100644 --- a/packages/pty/pty/package.json +++ b/packages/pty/pty/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-pty", "description": "Persistent PTY session seam for the DeepSeek Harness — owner-scoped ids, backend registry, interactive sends, reads, signals, and awaited cleanup", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/pty/tool-bash-persistent/package.json b/packages/pty/tool-bash-persistent/package.json index 0074f050b1..63cec95d11 100644 --- a/packages/pty/tool-bash-persistent/package.json +++ b/packages/pty/tool-bash-persistent/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-bash-persistent", "description": "Model-facing owner-scoped persistent Bash tool backed by the Harness PTY service", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/pty/tool-pty/package.json b/packages/pty/tool-pty/package.json index 804f6fb1a4..f8dcca8eee 100644 --- a/packages/pty/tool-pty/package.json +++ b/packages/pty/tool-pty/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-pty", "description": "Six model-facing persistent PTY tools with owner isolation and generic background-task integration", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/sandbox/sandbox-local/package.json b/packages/sandbox/sandbox-local/package.json index 64fdcb8991..1bedb912e2 100644 --- a/packages/sandbox/sandbox-local/package.json +++ b/packages/sandbox/sandbox-local/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-sandbox-local", "description": "Local process-sandbox backends for the DeepSeek Harness sandbox seam: bwrap, the npm-distributed landlock-run launcher, macOS Seatbelt, or the Windows ACL restricted-token runner — functionally probed, fail-closed", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/sandbox/sandbox-policy/package.json b/packages/sandbox/sandbox-policy/package.json index e5736878e3..1f9ddae514 100644 --- a/packages/sandbox/sandbox-policy/package.json +++ b/packages/sandbox/sandbox-policy/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-sandbox-policy", "description": "Per-call sandbox policy resolver and current model context: deployment fallbacks plus each session's mode and workspace root, shared by every enforcing capability family", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/sandbox/sandbox-windows-acl/package.json b/packages/sandbox/sandbox-windows-acl/package.json index b2f0a2b089..012e162cbb 100644 --- a/packages/sandbox/sandbox-windows-acl/package.json +++ b/packages/sandbox/sandbox-windows-acl/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-sandbox-windows-acl", "description": "Windows ACL write-restriction sandbox backend (restricted-token spawn with capability-SID write allowlist) for the DeepSeek Harness sandbox seam", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/sandbox/sandbox/package.json b/packages/sandbox/sandbox/package.json index b25c8b74a0..459fb187da 100644 --- a/packages/sandbox/sandbox/package.json +++ b/packages/sandbox/sandbox/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-sandbox", "description": "Abstract process-sandbox seam (ctx.sandbox) for the DeepSeek Harness: same-world confinement vocabulary and the SandboxProvider contract", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/schedule/tool-schedule/package.json b/packages/schedule/tool-schedule/package.json index 45ad7e6614..6137239495 100644 --- a/packages/schedule/tool-schedule/package.json +++ b/packages/schedule/tool-schedule/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-schedule", "description": "Agent-scoped durable after, at, and fixed-rate reminders over the session event log", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/sdk/client/package.json b/packages/sdk/client/package.json index f767cb1da9..7a84b2dee2 100644 --- a/packages/sdk/client/package.json +++ b/packages/sdk/client/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-sdk-client", "description": "TypeScript client SDK for driving a DeepSeek Harness runtime subprocess over stdio JSON-RPC: the DeepSeekHarness high-level turns API and the lower-level HarnessClient", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/sdk/protocol/package.json b/packages/sdk/protocol/package.json index b08eb9709e..0a634fcc43 100644 --- a/packages/sdk/protocol/package.json +++ b/packages/sdk/protocol/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-sdk-protocol", "description": "Shared wire protocol for the DeepSeek Harness SDK runtime: the newline-delimited JSON-RPC stdio transport and the named request, result, and notification types spoken between the runtime server and SDK clients", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/sdk/server/package.json b/packages/sdk/server/package.json index 72a09f0333..0e22917d1c 100644 --- a/packages/sdk/server/package.json +++ b/packages/sdk/server/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-jsonrpc", "description": "Stdio JSON-RPC server plugin for out-of-process DeepSeek Harness SDK clients", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/self-modification/tool-cordis/package.json b/packages/self-modification/tool-cordis/package.json index 66fc24d91a..38e3b6e816 100644 --- a/packages/self-modification/tool-cordis/package.json +++ b/packages/self-modification/tool-cordis/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-cordis", "description": "Self-referential cordis toolset: inspect the live runtime, mount and dispose model-written plugins", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/session-query/session-query-sqlite/package.json b/packages/session-query/session-query-sqlite/package.json index 156643a8bd..1e503fb7e4 100644 --- a/packages/session-query/session-query-sqlite/package.json +++ b/packages/session-query/session-query-sqlite/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-session-query-sqlite", "description": "Concrete ctx.sessionQuery backend with SQLite FTS5 search", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/session-query/session-query/package.json b/packages/session-query/session-query/package.json index 4d0e4c29de..7acb2fb2fe 100644 --- a/packages/session-query/session-query/package.json +++ b/packages/session-query/session-query/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-session-query", "description": "Combined session query service contract with concrete reads, traces, and filters", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/session-query/tool-session-query/package.json b/packages/session-query/tool-session-query/package.json index 6d8ef7696a..4f604788a8 100644 --- a/packages/session-query/tool-session-query/package.json +++ b/packages/session-query/tool-session-query/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-session-query", "description": "Workspace-authorized model-facing session history search, trace, and event read tools", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/session/session-checkpoint-policy/package.json b/packages/session/session-checkpoint-policy/package.json index 751b95d56a..2d9ca797ba 100644 --- a/packages/session/session-checkpoint-policy/package.json +++ b/packages/session/session-checkpoint-policy/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-session-checkpoint-policy", "description": "Semantic session durability checkpoints before model requests and tool side effects", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/session/session-persistence-jsonl/package.json b/packages/session/session-persistence-jsonl/package.json index aec127fa21..816ab6c087 100644 --- a/packages/session/session-persistence-jsonl/package.json +++ b/packages/session/session-persistence-jsonl/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-session-persistence-jsonl", "description": "JSONL durable session persistence backend for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/session/session-persistence-sqlite/package.json b/packages/session/session-persistence-sqlite/package.json index 60858d5aa8..9a3a2fec3b 100644 --- a/packages/session/session-persistence-sqlite/package.json +++ b/packages/session/session-persistence-sqlite/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-session-persistence-sqlite", "description": "SQLite durable session persistence backend for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/session/session-persistence/package.json b/packages/session/session-persistence/package.json index 33c900a3d8..4ada35f30b 100644 --- a/packages/session/session-persistence/package.json +++ b/packages/session/session-persistence/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-session-persistence", "description": "Abstract durable session persistence seam (ctx.sessionPersistence) for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/session/session-projection-cache/package.json b/packages/session/session-projection-cache/package.json index 59c3cd2a57..1c96d52f48 100644 --- a/packages/session/session-projection-cache/package.json +++ b/packages/session/session-projection-cache/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-session-projection-cache", "description": "Persisted projection cache (ctx.sessionProjectionCache): durable per-session projection checkpoints over the domain data form, throttled write-behind, and the cold-read ladder (cache row + persistence tail replay)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/session/session-projection/package.json b/packages/session/session-projection/package.json index fee23d3970..ee2c2e6b1b 100644 --- a/packages/session/session-projection/package.json +++ b/packages/session/session-projection/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-session-projection", "description": "Session-projection seam: the merge-extensible projection type table, the provider contract, and the ctx.sessionProjections registry serving whole current values of log-derived per-session state", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/session/session-telemetry-otel/package.json b/packages/session/session-telemetry-otel/package.json index d5229618a8..5294d3eab7 100644 --- a/packages/session/session-telemetry-otel/package.json +++ b/packages/session/session-telemetry-otel/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-session-telemetry-otel", "description": "OpenTelemetry backend for the DeepSeek Harness telemetry seam: hands captured session records to the OTel JS SDK's log pipeline", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/session/session-telemetry/package.json b/packages/session/session-telemetry/package.json index 8dc9a7fb67..5dad6b0d44 100644 --- a/packages/session/session-telemetry/package.json +++ b/packages/session/session-telemetry/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-session-telemetry", "description": "Telemetry seam for the DeepSeek Harness: session-event capture, projection, redaction, and handoff to a reporting backend", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/session/session-title-all-messages-llm/package.json b/packages/session/session-title-all-messages-llm/package.json index d333b5d5ca..772efcea95 100644 --- a/packages/session/session-title-all-messages-llm/package.json +++ b/packages/session/session-title-all-messages-llm/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-session-title-all-messages-llm", "description": "All-user-messages LLM provider plugin for DeepSeek Harness session titles", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/session/session-title-first-message-llm/package.json b/packages/session/session-title-first-message-llm/package.json index f259b41435..0214c1d96c 100644 --- a/packages/session/session-title-first-message-llm/package.json +++ b/packages/session/session-title-first-message-llm/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-session-title-first-message-llm", "description": "First-message LLM provider plugin for DeepSeek Harness session titles", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/session/session-title-llm/package.json b/packages/session/session-title-llm/package.json index dff4c3fde3..13b42af03d 100644 --- a/packages/session/session-title-llm/package.json +++ b/packages/session/session-title-llm/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-session-title-llm", "description": "Shared LLM generation policy for DeepSeek Harness session-title providers", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/session/session-title/package.json b/packages/session/session-title/package.json index 5ae395c008..577a9c1bc0 100644 --- a/packages/session/session-title/package.json +++ b/packages/session/session-title/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-session-title", "description": "Log-backed session title service and provider registry for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/session/user-id/package.json b/packages/session/user-id/package.json index 5ea2e7a5a9..193893975b 100644 --- a/packages/session/user-id/package.json +++ b/packages/session/user-id/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-user-id", "description": "Shared anonymous user identity for DeepSeek Harness telemetry and feedback correlation", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/settings/settings-local/package.json b/packages/settings/settings-local/package.json index 2ea49671fc..61d61b2591 100644 --- a/packages/settings/settings-local/package.json +++ b/packages/settings/settings-local/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-settings-local", "description": "File-backed settings provider (settings.yaml) for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/settings/settings/package.json b/packages/settings/settings/package.json index 08424a08d8..50e6f49518 100644 --- a/packages/settings/settings/package.json +++ b/packages/settings/settings/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-settings", "description": "Abstract user-settings seam (ctx.settings) for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/skill/skill-badge/package.json b/packages/skill/skill-badge/package.json index c3c79538c2..43d7828c67 100644 --- a/packages/skill/skill-badge/package.json +++ b/packages/skill/skill-badge/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-skill-badge", "description": "Bundled dsh badge skill provider for DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/skill/skill-local/package.json b/packages/skill/skill-local/package.json index c9f3ba8f27..64bdb9d24a 100644 --- a/packages/skill/skill-local/package.json +++ b/packages/skill/skill-local/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-skill-local", "description": "Local filesystem skill provider for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/skill/skill/package.json b/packages/skill/skill/package.json index dbb4429d9d..7afb0059bc 100644 --- a/packages/skill/skill/package.json +++ b/packages/skill/skill/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-skill", "description": "Agent skill provider registry for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/skill/tool-skill/package.json b/packages/skill/tool-skill/package.json index 7712261549..2d3ce92bf4 100644 --- a/packages/skill/tool-skill/package.json +++ b/packages/skill/tool-skill/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-skill", "description": "Model-facing skill loading tool for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/spill/spill-local/package.json b/packages/spill/spill-local/package.json index 1bab4c650f..9dd973f9ac 100644 --- a/packages/spill/spill-local/package.json +++ b/packages/spill/spill-local/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-spill-local", "description": "Local-filesystem implementation of the DeepSeek Harness spill storage seam (private session-scoped files)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/spill/spill-policy/package.json b/packages/spill/spill-policy/package.json index a18df1647c..0f24085fc7 100644 --- a/packages/spill/spill-policy/package.json +++ b/packages/spill/spill-policy/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-spill-policy", "description": "Tool-result spill policy for the DeepSeek Harness — replaces oversized plain-text tool results with a retained preview plus a spill-file path (no service API)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/spill/spill/package.json b/packages/spill/spill/package.json index c3379e6f72..f8227a504e 100644 --- a/packages/spill/spill/package.json +++ b/packages/spill/spill/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-spill", "description": "Abstract spill storage seam (ctx.spillStore) for the DeepSeek Harness — save oversized tool text and return a retrieval locator", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/storage/storage-domain/package.json b/packages/storage/storage-domain/package.json index 064ec4aa8a..dd89801f84 100644 --- a/packages/storage/storage-domain/package.json +++ b/packages/storage/storage-domain/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-storage-domain", "description": "Domain data form (ctx.storage.domain): schema-validated, event-emitting KV domains over storage backends for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/storage/storage-json/package.json b/packages/storage/storage-json/package.json index 78e1d9231a..c62421885a 100644 --- a/packages/storage/storage-json/package.json +++ b/packages/storage/storage-json/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-storage-json", "description": "JSON file KV storage backend for the DeepSeek Harness storage hub", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/storage/storage-sqlite/package.json b/packages/storage/storage-sqlite/package.json index 2fef41cebd..ea357a4a0b 100644 --- a/packages/storage/storage-sqlite/package.json +++ b/packages/storage/storage-sqlite/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-storage-sqlite", "description": "SQLite storage backend (kv facet) for the DeepSeek Harness storage hub", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/storage/storage/package.json b/packages/storage/storage/package.json index 39c8f0bed3..e5bfa0f6e0 100644 --- a/packages/storage/storage/package.json +++ b/packages/storage/storage/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-storage", "description": "Storage hub (ctx.storage): named backend registry plus mounted data-form facilities for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/subagent/subagent-acp/package.json b/packages/subagent/subagent-acp/package.json index 5efd65bcd5..1c8901130d 100644 --- a/packages/subagent/subagent-acp/package.json +++ b/packages/subagent/subagent-acp/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-subagent-acp", "description": "Out-of-process ACP subagent backend: drives a child agent in a spawned subprocess over the Agent Client Protocol", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/subagent/subagent-claude-code/package.json b/packages/subagent/subagent-claude-code/package.json index 4767d1ccb8..7966835ccd 100644 --- a/packages/subagent/subagent-claude-code/package.json +++ b/packages/subagent/subagent-claude-code/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-subagent-claude-code", "description": "One-shot Claude Code subagent provider over the official Agent SDK", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/subagent/subagent-codex/package.json b/packages/subagent/subagent-codex/package.json index 17e13287ef..6901a6d20b 100644 --- a/packages/subagent/subagent-codex/package.json +++ b/packages/subagent/subagent-codex/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-subagent-codex", "description": "One-shot Codex subagent provider over the official app-server protocol", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/subagent/subagent-dsh-sdk/package.json b/packages/subagent/subagent-dsh-sdk/package.json index 5d15e3da45..846c00c629 100644 --- a/packages/subagent/subagent-dsh-sdk/package.json +++ b/packages/subagent/subagent-dsh-sdk/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-subagent-dsh-sdk", "description": "Out-of-process SDK subagent backend: drives a child DeepSeek Harness runtime subprocess over stdio JSON-RPC through the TypeScript SDK client", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/subagent/subagent-fork/package.json b/packages/subagent/subagent-fork/package.json index 85ef8c6d88..734e6c4db1 100644 --- a/packages/subagent/subagent-fork/package.json +++ b/packages/subagent/subagent-fork/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-subagent-fork", "description": "In-process fork subagent backend: runs a child agent seeded with a prefix of the parent's log", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/subagent/subagent-inprocess/package.json b/packages/subagent/subagent-inprocess/package.json index 457bd16d36..f42010ae91 100644 --- a/packages/subagent/subagent-inprocess/package.json +++ b/packages/subagent/subagent-inprocess/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-subagent-inprocess", "description": "Shared in-process subagent run driver: drives a child agent on ctx.agents (used by the spawn and fork backends)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/subagent/subagent-spawn/package.json b/packages/subagent/subagent-spawn/package.json index 094470807b..41f7dbf0c1 100644 --- a/packages/subagent/subagent-spawn/package.json +++ b/packages/subagent/subagent-spawn/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-subagent-spawn", "description": "In-process spawn subagent backend: runs a fresh child agent on ctx.agents", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/subagent/subagent/package.json b/packages/subagent/subagent/package.json index 8a1bbef19f..6224922e16 100644 --- a/packages/subagent/subagent/package.json +++ b/packages/subagent/subagent/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-subagent", "description": "Abstract subagent seam (ctx.subagents): named-provider registry for delegating to child agents", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/subagent/tool-subagent-control/package.json b/packages/subagent/tool-subagent-control/package.json index 1a4a1ad4ad..8404f437d4 100644 --- a/packages/subagent/tool-subagent-control/package.json +++ b/packages/subagent/tool-subagent-control/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-subagent-control", "description": "Globally named send_message, interrupt_agent, and list_agents tools over ctx.subagents continuations", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/subagent/tool-subagent-report/package.json b/packages/subagent/tool-subagent-report/package.json index 8c2eb5d999..e22ed44505 100644 --- a/packages/subagent/tool-subagent-report/package.json +++ b/packages/subagent/tool-subagent-report/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-subagent-report", "description": "Child-scoped report tool over ctx.subagents continuations", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/subagent/tool-subagent/package.json b/packages/subagent/tool-subagent/package.json index 68488c604f..48d5879ef4 100644 --- a/packages/subagent/tool-subagent/package.json +++ b/packages/subagent/tool-subagent/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-subagent", "description": "Model-facing subagent delegation tool over the ctx.subagents seam", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/subprocess/subprocess-local/package.json b/packages/subprocess/subprocess-local/package.json index 12f47c0400..bc67b9369c 100644 --- a/packages/subprocess/subprocess-local/package.json +++ b/packages/subprocess/subprocess-local/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-subprocess-local", "description": "Local-subprocess implementation of the DeepSeek Harness subprocess seam", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/subprocess/subprocess/package.json b/packages/subprocess/subprocess/package.json index 55558024f4..0769654faf 100644 --- a/packages/subprocess/subprocess/package.json +++ b/packages/subprocess/subprocess/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-subprocess", "description": "Subprocess seam (ctx.subprocess) for the DeepSeek Harness — managed process groups, bounded spill-backed output, and escalated kills behind one abstract service", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/support/acp-snapshot/package.json b/packages/support/acp-snapshot/package.json index e06a890806..c701ebd247 100644 --- a/packages/support/acp-snapshot/package.json +++ b/packages/support/acp-snapshot/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-acp-snapshot", "description": "ACP test kit: shared subprocess launcher, snapshot scenario harness, expected-output normalizers, and suite factory", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/support/agent-loop-testkit/package.json b/packages/support/agent-loop-testkit/package.json index 43c49f3953..138d4da298 100644 --- a/packages/support/agent-loop-testkit/package.json +++ b/packages/support/agent-loop-testkit/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-agent-loop-testkit", "description": "Shared prerequisite mounting for tests that exercise the concrete agent loop", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/support/invariants/package.json b/packages/support/invariants/package.json index 1d01c18bd0..5001e61ac6 100644 --- a/packages/support/invariants/package.json +++ b/packages/support/invariants/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-invariants", "description": "Registry service for package-owned DeepSeek Harness runtime invariants", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/support/llm-mock-server/package.json b/packages/support/llm-mock-server/package.json index 203b092987..73ac097b1a 100644 --- a/packages/support/llm-mock-server/package.json +++ b/packages/support/llm-mock-server/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-llm-mock-server", "description": "Scriptable OpenAI-compatible HTTP/SSE fault server for LLM recovery tests", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/support/llm-replay/package.json b/packages/support/llm-replay/package.json index 3c05e7fbf6..8d16d418fe 100644 --- a/packages/support/llm-replay/package.json +++ b/packages/support/llm-replay/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-llm-replay", "description": "Replay LLM plugin: short-circuits llm/stream with model chunks reconstructed from a recorded session JSONL (keyless snapshot tests)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/support/loader-smoke/package.json b/packages/support/loader-smoke/package.json index 9f43ca3a01..4f402f40e6 100644 --- a/packages/support/loader-smoke/package.json +++ b/packages/support/loader-smoke/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-loader-smoke", "description": "Shared subprocess and direct-agent harness for keyless real-Loader example smoke tests", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/tasks/tasks-local/package.json b/packages/tasks/tasks-local/package.json index cd40629948..67c851607e 100644 --- a/packages/tasks/tasks-local/package.json +++ b/packages/tasks/tasks-local/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tasks-local", "description": "Process-local implementation of the DeepSeek Harness background task registry seam", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/tasks/tasks/package.json b/packages/tasks/tasks/package.json index 8c968b743b..97dd504c98 100644 --- a/packages/tasks/tasks/package.json +++ b/packages/tasks/tasks/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tasks", "description": "Background task registry (ctx.tasks) for the DeepSeek Harness — shared ids, owner isolation, polling, cancellation, and completion listeners for long-running tool work", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/tasks/tool-tasks/package.json b/packages/tasks/tool-tasks/package.json index c1ab0be9c4..92c25c45dd 100644 --- a/packages/tasks/tool-tasks/package.json +++ b/packages/tasks/tool-tasks/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-tasks", "description": "Model-facing background task control tools (task_output, task_list, task_kill) over the ctx.tasks registry", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/todo/tool-todo/package.json b/packages/todo/tool-todo/package.json index 0f080c5d33..a9d2659150 100644 --- a/packages/todo/tool-todo/package.json +++ b/packages/todo/tool-todo/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-todo", "description": "Model-facing todo_write tool over the DeepSeek Harness event-sourced session log", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/typert/generator/package.json b/packages/typert/generator/package.json index 53e711b3a7..a3180f190f 100644 --- a/packages/typert/generator/package.json +++ b/packages/typert/generator/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-typert-generator", "description": "TypeScript project analyzer and model-driven Typert artifact generator", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/typert/loader/package.json b/packages/typert/loader/package.json index ec66e2165b..46cd186a1e 100644 --- a/packages/typert/loader/package.json +++ b/packages/typert/loader/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-typert-loader", "description": "Loader integration for generated Typert package contributions", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/typert/registry/package.json b/packages/typert/registry/package.json index 0a75703929..45fba63e5e 100644 --- a/packages/typert/registry/package.json +++ b/packages/typert/registry/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-typert-registry", "description": "Runtime registry for generated package reflection and Zod schemas", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/typert/type-meta/package.json b/packages/typert/type-meta/package.json index 3195392acb..6f848885c9 100644 --- a/packages/typert/type-meta/package.json +++ b/packages/typert/type-meta/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-type-meta", "description": "Compiler-independent Remote metadata and TypeRT provider protocols", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/util/atomic-write/package.json b/packages/util/atomic-write/package.json index a26a5e62d3..ad63c689dc 100644 --- a/packages/util/atomic-write/package.json +++ b/packages/util/atomic-write/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-atomic-write", "description": "Zero-dependency atomic file replacement: exclusive-create random-suffix temp + rename carrying the caller-stated permissions (writeFileAtomic)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/util/brand/package.json b/packages/util/brand/package.json index 1496dfdb3a..c771e1fee3 100644 --- a/packages/util/brand/package.json +++ b/packages/util/brand/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-brand", "description": "Type-only Branded nominal-typing primitive for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/util/environment/package.json b/packages/util/environment/package.json index 6fa44ab20c..bdb01c8f43 100644 --- a/packages/util/environment/package.json +++ b/packages/util/environment/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-environment", "description": "Immutable DeepSeek Harness launch environment that records which layer supplied each value", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/util/native-command/package.json b/packages/util/native-command/package.json index af0891fb82..d4a2044f82 100644 --- a/packages/util/native-command/package.json +++ b/packages/util/native-command/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-native-command", "description": "Zero-dependency no-shell execFile runner for host-native OS integrations: utf8 stdio capture, abort propagation, Windows hide", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/util/paths/package.json b/packages/util/paths/package.json index e3c492ea34..07683e298b 100644 --- a/packages/util/paths/package.json +++ b/packages/util/paths/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-paths", "description": "Shared filesystem path helpers for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/util/retention/package.json b/packages/util/retention/package.json index eea04fee3e..1d563f34b8 100644 --- a/packages/util/retention/package.json +++ b/packages/util/retention/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-retention", "description": "Zero-dependency bounded-retention primitive: ItemRetainer/TextRetainer + neutral notice helpers (what did we keep, what did we omit)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/util/timeout/package.json b/packages/util/timeout/package.json index 72daaa2c6b..aeaac1eb9b 100644 --- a/packages/util/timeout/package.json +++ b/packages/util/timeout/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-timeout", "description": "Zero-dependency timeout/deadline primitive: clampTimeout, deadline, timeoutOf, TimeoutReason (timing + classification only, no termination)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/web/tool-web/package.json b/packages/web/tool-web/package.json index 0135e83403..0f72197514 100644 --- a/packages/web/tool-web/package.json +++ b/packages/web/tool-web/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-web", "description": "Model-facing web tools (web_search, web_fetch) over the DeepSeek Harness web capability seam (ctx.web)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/web/web-fetch-local/package.json b/packages/web/web-fetch-local/package.json index 562f8be8f6..9a79f66a83 100644 --- a/packages/web/web-fetch-local/package.json +++ b/packages/web/web-fetch-local/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-web-fetch-local", "description": "Anonymous public HTTP(S) fetch provider for the DeepSeek Harness web capability seam (ctx.web)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/web/web-search-deepseek/package.json b/packages/web/web-search-deepseek/package.json index 532b9d14bd..f51ec01a60 100644 --- a/packages/web/web-search-deepseek/package.json +++ b/packages/web/web-search-deepseek/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-web-search-deepseek", "description": "DeepSeek-backed search provider (native web_search via the Anthropic-compatible API) for the DeepSeek Harness web capability seam (ctx.web)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/web/web-search-exa/package.json b/packages/web/web-search-exa/package.json index 55b18bec50..e8d12fed01 100644 --- a/packages/web/web-search-exa/package.json +++ b/packages/web/web-search-exa/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-web-search-exa", "description": "Exa-backed search provider for the DeepSeek Harness web capability seam (ctx.web)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/web/web-search-perplexity/package.json b/packages/web/web-search-perplexity/package.json index 09c3b823ae..a1bac036f6 100644 --- a/packages/web/web-search-perplexity/package.json +++ b/packages/web/web-search-perplexity/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-web-search-perplexity", "description": "Perplexity-backed search provider for the DeepSeek Harness web capability seam (ctx.web)", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/web/web/package.json b/packages/web/web/package.json index 21e9811c1e..151a2133cc 100644 --- a/packages/web/web/package.json +++ b/packages/web/web/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-web", "description": "Abstract web access capability seam (ctx.web) for the DeepSeek Harness — search/fetch provider registry, registration-order-independent selection, request/result vocabulary, and the WebError taxonomy", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/workflow/tool-ralph/package.json b/packages/workflow/tool-ralph/package.json index f92eb944c4..d45a9ba985 100644 --- a/packages/workflow/tool-ralph/package.json +++ b/packages/workflow/tool-ralph/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-ralph", "description": "Model-facing fresh-agent Ralph loop over the workflow and subagent seams", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/workflow/tool-workflow/package.json b/packages/workflow/tool-workflow/package.json index 0b650b150c..effd74b6e2 100644 --- a/packages/workflow/tool-workflow/package.json +++ b/packages/workflow/tool-workflow/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-tool-workflow", "description": "Model-facing workflow tool: run a JavaScript orchestration script over ctx.workflows", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/workflow/workflow-workerthread/package.json b/packages/workflow/workflow-workerthread/package.json index af20d74fb2..08a8739242 100644 --- a/packages/workflow/workflow-workerthread/package.json +++ b/packages/workflow/workflow-workerthread/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-workflow-workerthread", "description": "worker-thread workflow engine: executes model-written orchestration scripts off the host event loop, bridging agent() calls back to ctx.subagents", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/workflow/workflow/package.json b/packages/workflow/workflow/package.json index c1391b7f24..6f7ddc13fd 100644 --- a/packages/workflow/workflow/package.json +++ b/packages/workflow/workflow/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-workflow", "description": "Workflow capability seam: ctx.workflows service, run vocabulary, and workflow/* events", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/packages/workspace/workspace/package.json b/packages/workspace/workspace/package.json index 4ab1aeecbe..67b6921d4a 100644 --- a/packages/workspace/workspace/package.json +++ b/packages/workspace/workspace/package.json @@ -1,7 +1,7 @@ { "name": "@deepseek-ai/dsh-workspace", "description": "Workspace entity registry (ctx.workspace): durable workspace records with validated session attachment over the domain data form for the DeepSeek Harness", - "version": "0.0.1-rc.1", + "version": "0.0.1-rc.2", "publishConfig": { "access": "restricted" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 18a0fcd55c..d63ee5fa71 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -210,9 +210,6 @@ importers: '@deepseek-ai/dsh-session-reference': specifier: workspace:^ version: link:../../packages/context/session-reference - '@deepseek-ai/dsh-time-context': - specifier: workspace:^ - version: link:../../packages/context/time-context '@deepseek-ai/dsh-skill': specifier: workspace:^ version: link:../../packages/skill/skill @@ -222,6 +219,9 @@ importers: '@deepseek-ai/dsh-tasks-local': specifier: workspace:^ version: link:../../packages/tasks/tasks-local + '@deepseek-ai/dsh-time-context': + specifier: workspace:^ + version: link:../../packages/context/time-context '@deepseek-ai/dsh-tmux-context': specifier: workspace:^ version: link:../../packages/context/tmux-context @@ -5725,6 +5725,48 @@ importers: specifier: workspace:^ version: link:../sandbox-local + packages/schedule/tool-schedule: + devDependencies: + '@deepseek-ai/cordis': + specifier: workspace:^ + version: link:../../../vendor/cordis + '@deepseek-ai/cordis-plugin-loader': + specifier: workspace:^ + version: link:../../../vendor/loader + '@deepseek-ai/dsh-agent': + specifier: workspace:^ + version: link:../../core/agent + '@deepseek-ai/dsh-agent-loop': + specifier: workspace:^ + version: link:../../core/agent-loop + '@deepseek-ai/dsh-agent-loop-testkit': + specifier: workspace:^ + version: link:../../support/agent-loop-testkit + '@deepseek-ai/dsh-brand': + specifier: workspace:^ + version: link:../../util/brand + '@deepseek-ai/dsh-invariants': + specifier: workspace:^ + version: link:../../support/invariants + '@deepseek-ai/dsh-llm': + specifier: workspace:^ + version: link:../../llm/llm + '@deepseek-ai/dsh-session': + specifier: workspace:^ + version: link:../../core/session + '@deepseek-ai/dsh-session-persistence': + specifier: workspace:^ + version: link:../../session/session-persistence + '@deepseek-ai/dsh-session-persistence-jsonl': + specifier: workspace:^ + version: link:../../session/session-persistence-jsonl + '@deepseek-ai/dsh-system-prompt': + specifier: workspace:^ + version: link:../../core/system-prompt + '@deepseek-ai/dsh-tools': + specifier: workspace:^ + version: link:../../core/tools + packages/sdk/client: devDependencies: '@deepseek-ai/cordis': @@ -5804,48 +5846,6 @@ importers: specifier: workspace:^ version: link:../../subagent/subagent - packages/schedule/tool-schedule: - devDependencies: - '@deepseek-ai/cordis': - specifier: workspace:^ - version: link:../../../vendor/cordis - '@deepseek-ai/cordis-plugin-loader': - specifier: workspace:^ - version: link:../../../vendor/loader - '@deepseek-ai/dsh-agent': - specifier: workspace:^ - version: link:../../core/agent - '@deepseek-ai/dsh-agent-loop': - specifier: workspace:^ - version: link:../../core/agent-loop - '@deepseek-ai/dsh-agent-loop-testkit': - specifier: workspace:^ - version: link:../../support/agent-loop-testkit - '@deepseek-ai/dsh-brand': - specifier: workspace:^ - version: link:../../util/brand - '@deepseek-ai/dsh-invariants': - specifier: workspace:^ - version: link:../../support/invariants - '@deepseek-ai/dsh-llm': - specifier: workspace:^ - version: link:../../llm/llm - '@deepseek-ai/dsh-session': - specifier: workspace:^ - version: link:../../core/session - '@deepseek-ai/dsh-session-persistence': - specifier: workspace:^ - version: link:../../session/session-persistence - '@deepseek-ai/dsh-session-persistence-jsonl': - specifier: workspace:^ - version: link:../../session/session-persistence-jsonl - '@deepseek-ai/dsh-system-prompt': - specifier: workspace:^ - version: link:../../core/system-prompt - '@deepseek-ai/dsh-tools': - specifier: workspace:^ - version: link:../../core/tools - packages/self-modification/tool-cordis: dependencies: '@deepseek-ai/schemastery': From e258cf7a2ddee25aae08b968877690d39e1b9239 Mon Sep 17 00:00:00 2001 From: Yichen Jiang Date: Tue, 11 Aug 2026 22:53:17 +0800 Subject: [PATCH 15/17] fix(tools): resolve the collapse through the scope, not the deployment default `collapses()` read `defaultMode`, so the collapse only applied when the DEPLOYMENT was `code`. An agent handed `code` by an agent preset under a native default announced `[run_code]` on the wire and still executed a model-direct native call -- the bypass this collapse exists to close, reopened for exactly the composition `dsh-agent-tool-mode` produces. `modeFor(scope)` is the same resolution `wireSchemas` and the SDK section already use, so presentation and execution cannot disagree, and a mode inherited from a standing preset scope collapses like a declared one. The per-agent and preset tests asserted only the wire, which is why the regression passed them. They now assert through the executor: the body never runs, the call resolves UNKNOWN_TOOL, and the native sibling beside it still executes. --- docs/config-catalog.i18n.yaml | 4 +- docs/config-catalog.md | 2 +- docs/config-catalog.zh.md | 2 +- packages/core/tools/src/index.ts | 15 +++++-- packages/core/tools/tests/code-mode.spec.ts | 45 ++++++++++++++++++++- 5 files changed, 58 insertions(+), 10 deletions(-) diff --git a/docs/config-catalog.i18n.yaml b/docs/config-catalog.i18n.yaml index ec81187785..db0acfe414 100644 --- a/docs/config-catalog.i18n.yaml +++ b/docs/config-catalog.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/config-catalog.md -config-catalog.md: 6362022dd1b80e17997684574d9dc7f14372e23a -config-catalog.zh.md: 3fd335ee2b1ec6d1526f75ed9667f1d9286faafe +config-catalog.md: 39433b697588ede7b36f878490f4e0b095e8d67a +config-catalog.zh.md: d76b289f8a7ffbc434b2adeefd5f16142fdffc99 diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 6362022dd1..39433b6975 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -2505,7 +2505,7 @@ export interface Config { export type ToolPresentationMode = 'native' | 'code' | 'both' ``` -Source: [`packages/core/tools/src/index.ts:629`](../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:654`](../packages/core/tools/src/index.ts) ## `@deepseek-ai/dsh-typert-loader` diff --git a/docs/config-catalog.zh.md b/docs/config-catalog.zh.md index 3fd335ee2b..d76b289f8a 100644 --- a/docs/config-catalog.zh.md +++ b/docs/config-catalog.zh.md @@ -2506,7 +2506,7 @@ export interface Config { export type ToolPresentationMode = 'native' | 'code' | 'both' ``` -来源:[`packages/core/tools/src/index.ts:617`](../packages/core/tools/src/index.ts) +来源:[`packages/core/tools/src/index.ts:654`](../packages/core/tools/src/index.ts) ## `@deepseek-ai/dsh-typert-loader` diff --git a/packages/core/tools/src/index.ts b/packages/core/tools/src/index.ts index 492112405b..b6be912c17 100644 --- a/packages/core/tools/src/index.ts +++ b/packages/core/tools/src/index.ts @@ -1221,7 +1221,7 @@ export class ToolRegistry extends Service { private resolveExecution(name: string, scope: ScopeKey | undefined, nested: boolean): ToolDefinition | undefined { const tool = this.get(name, scope) if (tool === undefined) return undefined - if (this.collapses(name, nested)) return undefined + if (this.collapses(name, scope, nested)) return undefined return tool } @@ -1311,11 +1311,18 @@ export class ToolRegistry extends Service { * `parent` token set) bypass the collapse. One home for the * security-relevant predicate, shared by {@link resolveExecution} and * {@link createExecution} so the two can never drift apart. + * + * Resolved through {@link modeFor}, NOT `defaultMode`: an agent given `code` + * by an agent preset under a native deployment is the composition + * `dsh-agent-tool-mode` exists for, and reading the deployment default would + * leave exactly that agent uncollapsed — announcing one surface while + * executing another, which is the bypass this collapse closes. * @param name - the tool name as registered. + * @param scope - the viewing scope whose effective presentation mode applies. * @param nested - whether the call is a transport sub-dispatch, not a model-direct call. */ - private collapses(name: string, nested: boolean): boolean { - return !nested && this.defaultMode === 'code' && name !== RUN_CODE_NAME + private collapses(name: string, scope: ScopeKey | undefined, nested: boolean): boolean { + return !nested && this.modeFor(scope) === 'code' && name !== RUN_CODE_NAME } /** @@ -1371,7 +1378,7 @@ export class ToolRegistry extends Service { // keeps the historical dispatch-stage `UNKNOWN_TOOL` path so policy // listeners still see every name that reaches the registry. const visible = this.get(name, agent) - const collapsed = visible !== undefined && this.collapses(name, parent !== undefined) + const collapsed = visible !== undefined && this.collapses(name, agent, parent !== undefined) const concludingExecutions = this.concludingExecutions const base = { token, diff --git a/packages/core/tools/tests/code-mode.spec.ts b/packages/core/tools/tests/code-mode.spec.ts index eb6d1b22e0..4379f7e0b2 100644 --- a/packages/core/tools/tests/code-mode.spec.ts +++ b/packages/core/tools/tests/code-mode.spec.ts @@ -1635,7 +1635,7 @@ describe('the run_code dispatch bridge', () => { describe('per-agent presentation', () => { it('gives one agent Code Mode while the deployment stays native', async () => { const { ctx, systemPrompt } = await setup({ mode: 'native' }) - registerEcho(ctx) + const calls = registerEcho(ctx) const { scope, agent } = await mintAgentScope(ctx) scope.ctx.tools.presentAs('code') @@ -1644,6 +1644,17 @@ describe('per-agent presentation', () => { expect(coded.tools.map(tool => tool.name)).toEqual([RUN_CODE_NAME]) expect(coded.sections.find(section => section.name === 'tools:sdk')?.text) .toContain('echo') + // Announced surface and callable surface must agree for THIS agent, whose + // mode is its own rather than the deployment's. + const denied = await ctx.tools.execute({ + signal: testToolSignal, + callId: CallId('coded-direct'), + name: 'echo', + arguments: { value: 'coded' }, + agent, + }) + expect(denied.error?.info).toEqual({ name: 'ToolNotFoundError', code: 'UNKNOWN_TOOL' }) + expect(calls).toEqual([]) // The deployment default is untouched: an agent that declared nothing — // and the global view behind it — still sees the native catalog. const native = await systemPrompt.assemble() @@ -1654,7 +1665,7 @@ describe('per-agent presentation', () => { it('inherits a STANDING preset scope\'s mode down the chain, agents beside it unaffected', async () => { const { bindScopeParent } = await import('@deepseek-ai/dsh-scope') const { ctx, systemPrompt } = await setup({ mode: 'native' }) - registerEcho(ctx) + const calls = registerEcho(ctx) // The preset's standing scope declares once; the agent only PARENTS to it // (the per-preset standing mount configuration has no per-agent declaration). const standing = await mintAgentScope(ctx, 'preset:code-like') @@ -1666,10 +1677,40 @@ describe('per-agent presentation', () => { expect(ctx.tools.get(RUN_CODE_NAME, joined.agent)).toBeDefined() const coded = await systemPrompt.assemble({ scope: joined.agent }) expect(coded.tools.map(tool => tool.name)).toEqual([RUN_CODE_NAME]) + // Through the EXECUTOR, not just the wire: the deployment default is + // `native` here, so a collapse predicate reading it instead of this + // scope's effective mode would announce [run_code] and still execute the + // native call — the bypass, reopened for exactly the preset composition + // `dsh-agent-tool-mode` produces. + expect(ctx.tools.executionMode({ + signal: testToolSignal, + callId: CallId('preset-coded-schedule'), + name: 'echo', + arguments: { value: 'joined' }, + agent: joined.agent, + })).toEqual({ kind: 'exclusive' }) + const denied = await ctx.tools.execute({ + signal: testToolSignal, + callId: CallId('preset-coded-direct'), + name: 'echo', + arguments: { value: 'joined' }, + agent: joined.agent, + }) + expect(denied.error?.info).toEqual({ name: 'ToolNotFoundError', code: 'UNKNOWN_TOOL' }) + expect(calls).toEqual([]) // A sibling that never parented stays native, as does the global view. expect(ctx.tools.get(RUN_CODE_NAME, loner.agent)).toBeUndefined() const native = await systemPrompt.assemble({ scope: loner.agent }) expect(native.tools.map(tool => tool.name)).toEqual(['echo']) + const allowed = await ctx.tools.execute({ + signal: testToolSignal, + callId: CallId('native-sibling-direct'), + name: 'echo', + arguments: { value: 'loner' }, + agent: loner.agent, + }) + expect(allowed).toMatchObject({ isError: false, value: 'echo:loner' }) + expect(calls).toEqual([{ value: 'loner' }]) }) it('keeps run_code out of a native agent\'s dispatch table', async () => { From 261349c95ebab042c61f5982210419536e950a9d Mon Sep 17 00:00:00 2001 From: Yichen Jiang Date: Tue, 11 Aug 2026 22:55:53 +0800 Subject: [PATCH 16/17] test(acp): refresh both-mode expected prompt onto the merged base --- .../snapshots/both-mode-turn/system-prompt.expected.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md b/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md index 94e7ee4afb..3771a70950 100644 --- a/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md +++ b/examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md @@ -21,6 +21,8 @@ Use the workflow tool ONLY when the user explicitly asks for a workflow or for l Use the ralph tool ONLY when the direct human explicitly asks for a Ralph loop or fresh-agent iterative execution. Each Ralph round starts a fresh child with no conversation seed and uses the shared workspace as durable memory. Completion and blockers are worker reports, not independent evaluation. Use same-session goal tools for ordinary long-running objectives, and plain subagents or workflows for bounded delegation and fan-out. +Use subagent in the background by default. Start independent delegations together in one assistant message and continue useful work while they run. Set `run_in_background: false` only when your next action depends on that subagent's result. When a background run settles, the runtime sends you a notice containing its outcome and any final assistant message. + ## Writing code for run_code Pass `run_code` the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program: @@ -115,16 +117,16 @@ interface ToolArgsMap { /** The exact skill name from the available skills list. */ name: string; } & Record; - /** Delegate a self-contained task to a subagent (a separate agent that works in its own context) and return its final result. Use this to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent runs to completion and you receive only its final answer, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. Set `run_in_background: true` to start a background subagent that keeps its conversation: this call returns only its subagent id, and the subagent works on its own from there. You are told when it finishes, so never poll or wait on it; `send_message` sends it more work. */ + /** Delegate a self-contained task to a subagent (a separate agent that works in its own context) to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent returns its result, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. This tool runs in the background by default, immediately returns a durable subagent id, and keeps the child conversation available for later turns. When that run settles, the runtime sends the parent a notice containing its outcome and any final assistant message; `send_message` starts a later turn in the same child conversation. Set `run_in_background: false` only when your next action depends on receiving the result. */ subagent: { /** A short (3-5 word) description of the delegated task, for display. */ description: string; /** The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs. */ prompt: string; - /** Run as a background subagent that keeps its conversation and return only its subagent id. This call does not wait for it; you are told when it finishes. Send it more work with send_message. */ + /** Whether to run in the background and return a durable subagent id immediately. Defaults to true. Set false to wait for the result when your next action depends on it. */ run_in_background?: boolean; } & Record; - /** Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn), returning only its final result. Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive only its final answer, not its intermediate steps. */ + /** Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn). Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive its result, not its intermediate steps. This call waits for the subagent and returns its result. */ subagent_fork: { /** A short (3-5 word) description of the delegated task, for display. */ description: string; From db4e3e39a54223e9315d2e49275e01e09d745176 Mon Sep 17 00:00:00 2001 From: Yichen Jiang Date: Tue, 11 Aug 2026 23:11:12 +0800 Subject: [PATCH 17/17] docs: refresh generated source references after the collapse-section constants Adding COLLAPSE_SECTION_ORDER and CODE_ONLY_INSTRUCTION shifted every later line in packages/core/tools/src/index.ts by 14, and three generated artifacts cite those lines: the subsystems cordis-surface region, the event producer/consumer matrix, and the Agent Note pair record left inconsistent by the cherry-pick resolution. --- ...026-08-07-code-mode-executor-collapse.i18n.yaml | 4 ++-- docs/event-producer-consumer.i18n.yaml | 4 ++-- docs/event-producer-consumer.md | 12 ++++++------ docs/event-producer-consumer.zh.md | 12 ++++++------ docs/subsystems/tools.i18n.yaml | 4 ++-- docs/subsystems/tools.md | 14 +++++++------- docs/subsystems/tools.zh.md | 14 +++++++------- 7 files changed, 32 insertions(+), 32 deletions(-) diff --git a/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.i18n.yaml b/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.i18n.yaml index b81b0fe922..2b04b5b240 100644 --- a/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.i18n.yaml +++ b/.agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-07-code-mode-executor-collapse.md -2026-08-07-code-mode-executor-collapse.md: 817da95678edbceb807c45b3ef858b800eaaa6c2 -2026-08-07-code-mode-executor-collapse.zh.md: 7b4a1b8adc01f6611c50cc4325c02d4b60313898 +2026-08-07-code-mode-executor-collapse.md: 3b64675f90f830628dcde427d4388153ec7accf1 +2026-08-07-code-mode-executor-collapse.zh.md: 51b35ad44b9758805784834d1d036ba374140dd9 diff --git a/docs/event-producer-consumer.i18n.yaml b/docs/event-producer-consumer.i18n.yaml index 12daef3078..8494ab9aa3 100644 --- a/docs/event-producer-consumer.i18n.yaml +++ b/docs/event-producer-consumer.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/event-producer-consumer.md -event-producer-consumer.md: c272087b03c6d27599b76ad6d6f197b023a36579 -event-producer-consumer.zh.md: b5634785e58134df453f0022a3b46ea926f3a526 +event-producer-consumer.md: 788d40e8dc110ffb5200889d9fdf17a5b17e8241 +event-producer-consumer.zh.md: 666f1f4108a3034af81d45b17c62537a4be30af6 diff --git a/docs/event-producer-consumer.md b/docs/event-producer-consumer.md index c272087b03..788d40e8dc 100644 --- a/docs/event-producer-consumer.md +++ b/docs/event-producer-consumer.md @@ -45,12 +45,12 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `system-prompt/assemble` | `waterfall` | [`packages/core/system-prompt/src/index.ts:31`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`waterfall`) | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`system-prompt`](../packages/core/system-prompt) | | `system-prompt/change` | `emit` | [`packages/core/system-prompt/src/index.ts:37`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`emit`) | - | | `telemetry/record` | `waterfall` | [`packages/session/session-telemetry/src/index.ts:43`](../packages/session/session-telemetry/src/index.ts) | [`session-telemetry`](../packages/session/session-telemetry) (`waterfall`) | - | -| `tools/change` | `emit` | [`packages/core/tools/src/index.ts:193`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`emit`) | - | -| `tools/code-dispatch-log` | `waterfall` | [`packages/core/tools/src/index.ts:175`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`spill-policy`](../packages/spill/spill-policy) | -| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:149`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), [`timeout-policy`](../packages/guard/timeout-policy) | -| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:161`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`tool-fs-search`](../packages/fs/tool-fs-search) | -| `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:138`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`tool-tasks`](../packages/tasks/tool-tasks) | -| `tools/result` | `emit` | [`packages/core/tools/src/index.ts:183`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`workspace-context`](../packages/context/workspace-context) | +| `tools/change` | `emit` | [`packages/core/tools/src/index.ts:207`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`emit`) | - | +| `tools/code-dispatch-log` | `waterfall` | [`packages/core/tools/src/index.ts:189`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`spill-policy`](../packages/spill/spill-policy) | +| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:163`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), [`timeout-policy`](../packages/guard/timeout-policy) | +| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:175`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`tool-fs-search`](../packages/fs/tool-fs-search) | +| `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:152`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`tool-tasks`](../packages/tasks/tool-tasks) | +| `tools/result` | `emit` | [`packages/core/tools/src/index.ts:197`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`workspace-context`](../packages/context/workspace-context) | | `workflow/agent-end` | `emit` | [`packages/workflow/workflow/src/index.ts:79`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) | | `workflow/agent-start` | `emit` | [`packages/workflow/workflow/src/index.ts:68`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) | | `workflow/end` | `emit` | [`packages/workflow/workflow/src/index.ts:89`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`workflow`](../packages/workflow/workflow) | diff --git a/docs/event-producer-consumer.zh.md b/docs/event-producer-consumer.zh.md index b5634785e5..666f1f4108 100644 --- a/docs/event-producer-consumer.zh.md +++ b/docs/event-producer-consumer.zh.md @@ -47,12 +47,12 @@ | `system-prompt/assemble` | `waterfall` | [`packages/core/system-prompt/src/index.ts:31`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`waterfall`) | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`system-prompt`](../packages/core/system-prompt) | | `system-prompt/change` | `emit` | [`packages/core/system-prompt/src/index.ts:37`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`emit`) | - | | `telemetry/record` | `waterfall` | [`packages/session/session-telemetry/src/index.ts:43`](../packages/session/session-telemetry/src/index.ts) | [`session-telemetry`](../packages/session/session-telemetry) (`waterfall`) | - | -| `tools/change` | `emit` | [`packages/core/tools/src/index.ts:193`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`emit`) | - | -| `tools/code-dispatch-log` | `waterfall` | [`packages/core/tools/src/index.ts:175`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`spill-policy`](../packages/spill/spill-policy) | -| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:149`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), [`timeout-policy`](../packages/guard/timeout-policy) | -| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:161`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`tool-fs-search`](../packages/fs/tool-fs-search) | -| `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:138`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`tool-tasks`](../packages/tasks/tool-tasks) | -| `tools/result` | `emit` | [`packages/core/tools/src/index.ts:183`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`workspace-context`](../packages/context/workspace-context) | +| `tools/change` | `emit` | [`packages/core/tools/src/index.ts:207`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`emit`) | - | +| `tools/code-dispatch-log` | `waterfall` | [`packages/core/tools/src/index.ts:189`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`spill-policy`](../packages/spill/spill-policy) | +| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:163`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), [`timeout-policy`](../packages/guard/timeout-policy) | +| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:175`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`tool-fs-search`](../packages/fs/tool-fs-search) | +| `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:152`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`tool-tasks`](../packages/tasks/tool-tasks) | +| `tools/result` | `emit` | [`packages/core/tools/src/index.ts:197`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`workspace-context`](../packages/context/workspace-context) | | `workflow/agent-end` | `emit` | [`packages/workflow/workflow/src/index.ts:79`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) | | `workflow/agent-start` | `emit` | [`packages/workflow/workflow/src/index.ts:68`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) | | `workflow/end` | `emit` | [`packages/workflow/workflow/src/index.ts:89`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`workflow`](../packages/workflow/workflow) | diff --git a/docs/subsystems/tools.i18n.yaml b/docs/subsystems/tools.i18n.yaml index 3974e0217f..a4cefc4ef5 100644 --- a/docs/subsystems/tools.i18n.yaml +++ b/docs/subsystems/tools.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/tools.md -tools.md: fff43d587428ca4747cfd19ac5fccca08b4e048e -tools.zh.md: 4705edf81e56c81b237a69caa1c012ba12d67716 +tools.md: 60f982e1934a37f80236382141ebc54fdef5d7b4 +tools.zh.md: 07e5e5729bfb8329b2696c64c25b852cb8a91350 diff --git a/docs/subsystems/tools.md b/docs/subsystems/tools.md index fff43d5874..60f982e193 100644 --- a/docs/subsystems/tools.md +++ b/docs/subsystems/tools.md @@ -571,7 +571,7 @@ async execute(exec: ToolExecutionInput): Promise Types: [ScopeKey](scope.md) -Source: [`packages/core/tools/src/index.ts:762`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:787`](../../packages/core/tools/src/index.ts) @@ -596,7 +596,7 @@ A tool was registered or unregistered, or a scoped restriction changed (the avai 'tools/change'(): void ``` -Source: [`packages/core/tools/src/index.ts:193`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:207`](../../packages/core/tools/src/index.ts) @@ -623,7 +623,7 @@ Allow a listener to replace content in the DURABLE LOG COPY of one `run_code` su Types: [ContentBlock](llm-streaming.md) · [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:175`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:189`](../../packages/core/tools/src/index.ts) @@ -647,7 +647,7 @@ Around-dispatch waterfall for timeout, retry, or metrics. `next()` returns a nor Types: [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:149`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:163`](../../packages/core/tools/src/index.ts) @@ -672,7 +672,7 @@ Accept, replace, enrich, or block a normalized dispatch result. `next()` accepts Types: [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:161`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:175`](../../packages/core/tools/src/index.ts) @@ -695,7 +695,7 @@ Allow, deny, or ask before dispatch. `next()` delegates to allow; missing approv Types: [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:138`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:152`](../../packages/core/tools/src/index.ts) @@ -716,5 +716,5 @@ Observe the frozen, lossless-JSON final outcome. Listener failures are contained Types: [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:183`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:197`](../../packages/core/tools/src/index.ts) diff --git a/docs/subsystems/tools.zh.md b/docs/subsystems/tools.zh.md index 4705edf81e..07e5e5729b 100644 --- a/docs/subsystems/tools.zh.md +++ b/docs/subsystems/tools.zh.md @@ -571,7 +571,7 @@ async execute(exec: ToolExecutionInput): Promise Types: [ScopeKey](scope.md) -Source: [`packages/core/tools/src/index.ts:762`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:787`](../../packages/core/tools/src/index.ts) @@ -596,7 +596,7 @@ A tool was registered or unregistered, or a scoped restriction changed (the avai 'tools/change'(): void ``` -Source: [`packages/core/tools/src/index.ts:193`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:207`](../../packages/core/tools/src/index.ts) @@ -623,7 +623,7 @@ Allow a listener to replace content in the DURABLE LOG COPY of one `run_code` su Types: [ContentBlock](llm-streaming.md) · [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:175`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:189`](../../packages/core/tools/src/index.ts) @@ -647,7 +647,7 @@ Around-dispatch waterfall for timeout, retry, or metrics. `next()` returns a nor Types: [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:149`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:163`](../../packages/core/tools/src/index.ts) @@ -672,7 +672,7 @@ Accept, replace, enrich, or block a normalized dispatch result. `next()` accepts Types: [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:161`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:175`](../../packages/core/tools/src/index.ts) @@ -695,7 +695,7 @@ Allow, deny, or ask before dispatch. `next()` delegates to allow; missing approv Types: [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:138`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:152`](../../packages/core/tools/src/index.ts) @@ -716,5 +716,5 @@ Observe the frozen, lossless-JSON final outcome. Listener failures are contained Types: [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:183`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts:197`](../../packages/core/tools/src/index.ts)