diff --git a/apps/cli/tests/profiles/sdk/keyless-smoke.e2e.ts b/apps/cli/tests/profiles/sdk/keyless-smoke.e2e.ts
index 4d3bb617b8..5c51bd36ae 100644
--- a/apps/cli/tests/profiles/sdk/keyless-smoke.e2e.ts
+++ b/apps/cli/tests/profiles/sdk/keyless-smoke.e2e.ts
@@ -399,7 +399,7 @@ describe('Python SDK dsh profile keyless smoke', () => {
const patch = join(root, 'failure.yml')
await mkdir(home)
if (blocked) await writeFile(join(home, 'logs'), 'blocked')
- await writeFile(patch, '- id: tool-executor-native\n config:\n maxParallelToolCalls: 0\n')
+ await writeFile(patch, '- id: agent-loop\n config:\n maxParallelToolCalls: 0\n')
const child = execa(launch.command, [
...launch.args, '--profile', 'sdk', '--patch', patch,
], {
diff --git a/apps/cli/tests/web-agent-presets.e2e.ts b/apps/cli/tests/web-agent-presets.e2e.ts
index 5944476fb2..43620ba878 100644
--- a/apps/cli/tests/web-agent-presets.e2e.ts
+++ b/apps/cli/tests/web-agent-presets.e2e.ts
@@ -816,7 +816,7 @@ describe('a user preset declared from the shipped cordis rows', () => {
expect(queriedText).toContain(`"name": "${toolName}"`)
}
- // The `Config` provider reads the booted profile tree: the executor selector declares a Config,
+ // The `Config` provider reads the booted profile tree: the Agent loop declares a Config,
// and the bootstrap include row is a carrier. The name filter keeps each page small.
type ConfigRow = { id: string; patchId: string; name: string; status: string }
type ConfigPage = { data: { entries: ConfigRow[]; total: number; nextOffset: number | null } }
@@ -831,9 +831,9 @@ describe('a user preset declared from the shipped cordis rows', () => {
expect(page.isError, resultText(page)).toBe(false)
return (JSON.parse(resultText(page)) as ConfigPage).data
}
- const toolsRows = await listConfigs({ name: '@deepseek-ai/dsh-tool-executor-native' }, 'copied-preset-inspect-configs')
+ const toolsRows = await listConfigs({ name: '@deepseek-ai/dsh-agent-loop' }, 'copied-preset-inspect-configs')
const toolsRow = toolsRows.entries[0]
- expect(toolsRow).toMatchObject({ patchId: 'tool-executor-native', status: 'schema' })
+ expect(toolsRow).toMatchObject({ patchId: 'agent-loop', status: 'schema' })
expect(toolsRows).toMatchObject({ total: 1, nextOffset: null })
const includes = await listConfigs({ name: 'cordis:include' }, 'copied-preset-inspect-includes')
expect(includes.entries.find(entry => entry.patchId === 'include')).toMatchObject({ status: 'tree' })
diff --git a/apps/web/tests/shipped-composition.e2e.ts b/apps/web/tests/shipped-composition.e2e.ts
index 669a48faf1..9868bc8968 100644
--- a/apps/web/tests/shipped-composition.e2e.ts
+++ b/apps/web/tests/shipped-composition.e2e.ts
@@ -1,4 +1,4 @@
-import { executeToolFixture } from '@deepseek-ai/dsh-tool-testkit'
+import { executeToolFixture, executeModelToolFixture } from '@deepseek-ai/dsh-tool-testkit'
// Boots the shipped Web composition over the built dist this lane already uses
// and asserts its catalog, defaults, Loader lifecycle, and one complete Auto
// producer-to-tool path. Browser scenarios in this lane own visual behavior.
@@ -680,7 +680,7 @@ it('lets a preset producer reach the background-job registry', async () => {
// `tool-bash` is a preset row and `tasks` is a host registry; the producer
// resolves it with `ctx.get`, so a registry hidden behind a preset realm
// fails here — with every task control still listed in the catalog above.
- const started = await executeToolFixture(ctx, {
+ const started = await executeModelToolFixture(ctx, {
signal,
callId: ToolCallId('shipped-bash-background'),
name: 'bash',
diff --git a/docs/config-catalog.md b/docs/config-catalog.md
index ee53ca268d..33ab75b9e4 100644
--- a/docs/config-catalog.md
+++ b/docs/config-catalog.md
@@ -162,7 +162,7 @@ export interface Config {
## `@deepseek-ai/dsh-agent-tool-presentation`
- `inject`: `tools`
-- `source`: [`packages/core/agent-tool-presentation/src/index.ts:26`](../packages/core/agent-tool-presentation/src/index.ts)
+- `source`: [`packages/core/agent-tool-presentation/src/index.ts:25`](../packages/core/agent-tool-presentation/src/index.ts)
```ts config-catalog
/**
@@ -3822,40 +3822,19 @@ export interface Config {
```
-
-
-
-## `@deepseek-ai/dsh-tool-executor-native`
-
-- `inject`: `tools`
-- `refs`: `Volatile` (`@deepseek-ai/cosmokit`)
-- `source`: [`packages/core/tool-executor-native/src/index.ts:14`](../packages/core/tool-executor-native/src/index.ts)
-
-```ts config-catalog
-/** Native batch concurrency configuration. */
-export interface Config {
- /** Maximum overlapping concurrency-safe calls in one batch. */
- maxParallelToolCalls: Volatile
-}
-```
-
-
## `@deepseek-ai/dsh-tool-executor-ptc`
-- `inject`: `tools` · `systemPrompt` · `ptcRuntime`
-- `refs`: `Volatile` (`@deepseek-ai/cosmokit`)
-- `source`: [`packages/core/tool-executor-ptc/src/index.ts:19`](../packages/core/tool-executor-ptc/src/index.ts)
+- `inject`: `tools` · `systemPrompt`
+- `source`: [`packages/core/tool-executor-ptc/src/config.ts:5`](../packages/core/tool-executor-ptc/src/config.ts)
```ts config-catalog
/** Program execution limits. */
export interface Config {
- /** Maximum overlapping concurrency-safe calls in one model batch. */
- maxParallelToolCalls: Volatile
/** Maximum overlapping concurrency-safe program subcalls. */
- maxParallelSubCalls?: number
+ maxParallelSubCalls: number
}
```
@@ -4769,6 +4748,7 @@ These load from a `cordis.yml` entry with no `config:` block; they declare no co
| `@deepseek-ai/dsh-terminal` | — | [`packages/terminal/terminal/src/index.ts`](../packages/terminal/terminal/src/index.ts) |
| `@deepseek-ai/dsh-tool-call-timeout-policy` | `tools` | [`packages/guard/timeout-policy/src/index.ts`](../packages/guard/timeout-policy/src/index.ts) |
| `@deepseek-ai/dsh-tool-cordis` | `tools` · `cordisInspect` | [`packages/extensions/tool-cordis/src/index.ts`](../packages/extensions/tool-cordis/src/index.ts) |
+| `@deepseek-ai/dsh-tool-executor-native` | `tools` | [`packages/core/tool-executor-native/src/index.ts`](../packages/core/tool-executor-native/src/index.ts) |
| `@deepseek-ai/dsh-tool-schedule` | `tools` | [`packages/schedule/tool-schedule/src/index.ts`](../packages/schedule/tool-schedule/src/index.ts) |
| `@deepseek-ai/dsh-tool-subagent-control` | `tools` · `subagents` · `agents` | [`packages/subagent/tool-subagent-control/src/index.ts`](../packages/subagent/tool-subagent-control/src/index.ts) |
| `@deepseek-ai/dsh-tool-working-directory` | `tools` · `workingDirectory` | [`packages/session/tool-working-directory/src/index.ts`](../packages/session/tool-working-directory/src/index.ts) |
diff --git a/docs/config-catalog.zh.md b/docs/config-catalog.zh.md
index 7da2fed7a5..1e2e6f7a05 100644
--- a/docs/config-catalog.zh.md
+++ b/docs/config-catalog.zh.md
@@ -164,7 +164,7 @@ export interface Config {
## `@deepseek-ai/dsh-agent-tool-presentation`
- `inject`: `tools`
-- `source`: [`packages/core/agent-tool-presentation/src/index.ts:26`](../packages/core/agent-tool-presentation/src/index.ts)
+- `source`: [`packages/core/agent-tool-presentation/src/index.ts:25`](../packages/core/agent-tool-presentation/src/index.ts)
```ts config-catalog
/**
@@ -3824,40 +3824,19 @@ export interface Config {
```
-
-
-
-## `@deepseek-ai/dsh-tool-executor-native`
-
-- `inject`: `tools`
-- `refs`: `Volatile` (`@deepseek-ai/cosmokit`)
-- `source`: [`packages/core/tool-executor-native/src/index.ts:14`](../packages/core/tool-executor-native/src/index.ts)
-
-```ts config-catalog
-/** Native batch concurrency configuration. */
-export interface Config {
- /** Maximum overlapping concurrency-safe calls in one batch. */
- maxParallelToolCalls: Volatile
-}
-```
-
-
## `@deepseek-ai/dsh-tool-executor-ptc`
-- `inject`: `tools` · `systemPrompt` · `ptcRuntime`
-- `refs`: `Volatile` (`@deepseek-ai/cosmokit`)
-- `source`: [`packages/core/tool-executor-ptc/src/index.ts:19`](../packages/core/tool-executor-ptc/src/index.ts)
+- `inject`: `tools` · `systemPrompt`
+- `source`: [`packages/core/tool-executor-ptc/src/config.ts:5`](../packages/core/tool-executor-ptc/src/config.ts)
```ts config-catalog
/** Program execution limits. */
export interface Config {
- /** Maximum overlapping concurrency-safe calls in one model batch. */
- maxParallelToolCalls: Volatile
/** Maximum overlapping concurrency-safe program subcalls. */
- maxParallelSubCalls?: number
+ maxParallelSubCalls: number
}
```
@@ -4771,6 +4750,7 @@ export interface Config {
| `@deepseek-ai/dsh-terminal` | — | [`packages/terminal/terminal/src/index.ts`](../packages/terminal/terminal/src/index.ts) |
| `@deepseek-ai/dsh-tool-call-timeout-policy` | `tools` | [`packages/guard/timeout-policy/src/index.ts`](../packages/guard/timeout-policy/src/index.ts) |
| `@deepseek-ai/dsh-tool-cordis` | `tools` · `cordisInspect` | [`packages/extensions/tool-cordis/src/index.ts`](../packages/extensions/tool-cordis/src/index.ts) |
+| `@deepseek-ai/dsh-tool-executor-native` | `tools` | [`packages/core/tool-executor-native/src/index.ts`](../packages/core/tool-executor-native/src/index.ts) |
| `@deepseek-ai/dsh-tool-schedule` | `tools` | [`packages/schedule/tool-schedule/src/index.ts`](../packages/schedule/tool-schedule/src/index.ts) |
| `@deepseek-ai/dsh-tool-subagent-control` | `tools` · `subagents` · `agents` | [`packages/subagent/tool-subagent-control/src/index.ts`](../packages/subagent/tool-subagent-control/src/index.ts) |
| `@deepseek-ai/dsh-tool-working-directory` | `tools` · `workingDirectory` | [`packages/session/tool-working-directory/src/index.ts`](../packages/session/tool-working-directory/src/index.ts) |
diff --git a/docs/module-graph.md b/docs/module-graph.md
index c5ba1734a8..233e731000 100644
--- a/docs/module-graph.md
+++ b/docs/module-graph.md
@@ -1194,7 +1194,6 @@ flowchart TD
pkg_spill_policy --> pkg_session
pkg_spill_policy --> pkg_spill
pkg_spill_policy --> pkg_token_meter
- pkg_spill_policy --> pkg_tool_executor_ptc
pkg_spill_policy --> pkg_tools
pkg_session_query_sqlite --> pkg_session
pkg_session_query_sqlite --> pkg_session_persistence
@@ -1769,7 +1768,7 @@ flowchart TD
| [`subprocess-ssh`](../packages/ssh/subprocess-ssh) | `ssh` | [`ssh`](../packages/ssh/ssh), [`subprocess`](../packages/subprocess/subprocess), [`subprocess-local`](../packages/subprocess/subprocess-local) |
| [`agent-loop-testkit`](../packages/test-support/agent-loop-testkit) | `test-support` | [`agent`](../packages/core/agent), [`agent-loop`](../packages/core/agent-loop), [`fs-local`](../packages/fs/fs-local), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`working-directory`](../packages/session/working-directory) |
| [`subagent`](../packages/subagent/subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-preset-registry`](../packages/preset/agent-preset-registry), [`attachment`](../packages/attachment/attachment), [`llm`](../packages/llm/llm), [`permission-presets`](../packages/interaction/permission-presets), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval), [`util-time`](../packages/util/time), [`working-directory`](../packages/session/working-directory), [`workspace`](../packages/workspace/workspace) |
-| [`spill-policy`](../packages/spill/spill-policy) | `spill` | [`attachment`](../packages/attachment/attachment), [`fs`](../packages/fs/fs), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`spill`](../packages/spill/spill), [`token-meter`](../packages/llm/token-meter), [`tool-executor-ptc`](../packages/core/tool-executor-ptc), [`tools`](../packages/core/tools) |
+| [`spill-policy`](../packages/spill/spill-policy) | `spill` | [`attachment`](../packages/attachment/attachment), [`fs`](../packages/fs/fs), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`spill`](../packages/spill/spill), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools) |
| [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | `session-query` | [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query) |
| [`acp`](../packages/acp/acp) | `acp` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`llm`](../packages/llm/llm), [`mcp-client`](../packages/mcp/mcp-client), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`token-meter`](../packages/llm/token-meter), [`user-approval`](../packages/interaction/user-approval) |
| [`plugin-manager`](../packages/boot/plugin-manager) | `boot` | [`brand`](../packages/util/brand), [`hmr`](../packages/boot/hmr), [`host-plugin-inventory`](../packages/host/plugin-inventory), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`subprocess`](../packages/subprocess/subprocess), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval) |
diff --git a/docs/module-graph.zh.md b/docs/module-graph.zh.md
index 6a7f781d4a..ba174b22f4 100644
--- a/docs/module-graph.zh.md
+++ b/docs/module-graph.zh.md
@@ -1196,7 +1196,6 @@ flowchart TD
pkg_spill_policy --> pkg_session
pkg_spill_policy --> pkg_spill
pkg_spill_policy --> pkg_token_meter
- pkg_spill_policy --> pkg_tool_executor_ptc
pkg_spill_policy --> pkg_tools
pkg_session_query_sqlite --> pkg_session
pkg_session_query_sqlite --> pkg_session_persistence
@@ -1771,7 +1770,7 @@ flowchart TD
| [`subprocess-ssh`](../packages/ssh/subprocess-ssh) | `ssh` | [`ssh`](../packages/ssh/ssh), [`subprocess`](../packages/subprocess/subprocess), [`subprocess-local`](../packages/subprocess/subprocess-local) |
| [`agent-loop-testkit`](../packages/test-support/agent-loop-testkit) | `test-support` | [`agent`](../packages/core/agent), [`agent-loop`](../packages/core/agent-loop), [`fs-local`](../packages/fs/fs-local), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`working-directory`](../packages/session/working-directory) |
| [`subagent`](../packages/subagent/subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-preset-registry`](../packages/preset/agent-preset-registry), [`attachment`](../packages/attachment/attachment), [`llm`](../packages/llm/llm), [`permission-presets`](../packages/interaction/permission-presets), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval), [`util-time`](../packages/util/time), [`working-directory`](../packages/session/working-directory), [`workspace`](../packages/workspace/workspace) |
-| [`spill-policy`](../packages/spill/spill-policy) | `spill` | [`attachment`](../packages/attachment/attachment), [`fs`](../packages/fs/fs), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`spill`](../packages/spill/spill), [`token-meter`](../packages/llm/token-meter), [`tool-executor-ptc`](../packages/core/tool-executor-ptc), [`tools`](../packages/core/tools) |
+| [`spill-policy`](../packages/spill/spill-policy) | `spill` | [`attachment`](../packages/attachment/attachment), [`fs`](../packages/fs/fs), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`spill`](../packages/spill/spill), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools) |
| [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | `session-query` | [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query) |
| [`acp`](../packages/acp/acp) | `acp` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`llm`](../packages/llm/llm), [`mcp-client`](../packages/mcp/mcp-client), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`token-meter`](../packages/llm/token-meter), [`user-approval`](../packages/interaction/user-approval) |
| [`plugin-manager`](../packages/boot/plugin-manager) | `boot` | [`brand`](../packages/util/brand), [`hmr`](../packages/boot/hmr), [`host-plugin-inventory`](../packages/host/plugin-inventory), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`subprocess`](../packages/subprocess/subprocess), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval) |
diff --git a/docs/persistence-catalog.i18n.yaml b/docs/persistence-catalog.i18n.yaml
index 634a3a5b47..8112d1933e 100644
--- a/docs/persistence-catalog.i18n.yaml
+++ b/docs/persistence-catalog.i18n.yaml
@@ -1830,8 +1830,8 @@
en: 08be4349548406a9
zh: 8e7cf9966198ef78
/session-persistence-event-catalog/resolved-persistence-types/kind-tool-registry:
- en: 4fde95c569339141
- zh: 6fa54e19c24ab7f3
+ en: c59d020828d8211f
+ zh: 154a30cb69e79489
/session-persistence-event-catalog/resolved-persistence-types/kind-user:
en: a58f339332877b15
zh: b7406af7d8197b64
diff --git a/docs/persistence-catalog.md b/docs/persistence-catalog.md
index ad03afd422..54674899b3 100644
--- a/docs/persistence-catalog.md
+++ b/docs/persistence-catalog.md
@@ -7542,7 +7542,7 @@ SHA-256: `c5228b7a55498d84f529591744a0ab26e0b93ade18a70a26db1377a1ecfa6b49`
SHA-256: `8fcb0b44a575e998665c053643d1ab04c82f39253ebd190ac0c975b78e40b543`
-Sources: [`packages/core/tools/src/index.ts:17`](../packages/core/tools/src/index.ts)
+Sources: [`packages/core/tools/src/index.ts:18`](../packages/core/tools/src/index.ts)
| Property | Presence | Type |
|---|---|---|
diff --git a/docs/persistence-catalog.zh.md b/docs/persistence-catalog.zh.md
index ac37597541..f4833af8b8 100644
--- a/docs/persistence-catalog.zh.md
+++ b/docs/persistence-catalog.zh.md
@@ -7544,7 +7544,7 @@ SHA-256: `c5228b7a55498d84f529591744a0ab26e0b93ade18a70a26db1377a1ecfa6b49`
SHA-256: `8fcb0b44a575e998665c053643d1ab04c82f39253ebd190ac0c975b78e40b543`
-来源:[`packages/core/tools/src/index.ts:17`](../packages/core/tools/src/index.ts)
+来源:[`packages/core/tools/src/index.ts:18`](../packages/core/tools/src/index.ts)
| 属性 | 存在性 | 类型 |
|---|---|---|
diff --git a/docs/persistence-schema.json b/docs/persistence-schema.json
index 935980f278..c1aed265be 100644
--- a/docs/persistence-schema.json
+++ b/docs/persistence-schema.json
@@ -24599,7 +24599,7 @@
"digest": "8fcb0b44a575e998665c053643d1ab04c82f39253ebd190ac0c975b78e40b543",
"names": [],
"sources": [
- "packages/core/tools/src/index.ts:17"
+ "packages/core/tools/src/index.ts:18"
]
},
{
diff --git a/docs/subsystems/tools.md b/docs/subsystems/tools.md
index a43e3f29e0..a92f41d6df 100644
--- a/docs/subsystems/tools.md
+++ b/docs/subsystems/tools.md
@@ -293,7 +293,7 @@ interface ToolExecutionInput {
* 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: 'ptc'`, only calls WITH a parent may
+ * model-direct call: with the PTC executor selected, 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.
*/
@@ -635,6 +635,7 @@ schemas(scope?: ScopeKey): ToolSchema[]
/**
* Provide the executor for the calling scope; an unscoped contribution is the deployment default.
+ * Rendering any executor-owned section requires the viewing scope's selection to remain available.
* @param executor - initialized provider owned by the contributing plugin.
* @returns the effect disposer. Unloading leaves the selection unavailable until it is replaced.
*/
diff --git a/docs/subsystems/tools.zh.md b/docs/subsystems/tools.zh.md
index a0fecf88cc..187d61c3f7 100644
--- a/docs/subsystems/tools.zh.md
+++ b/docs/subsystems/tools.zh.md
@@ -293,7 +293,7 @@ interface ToolExecutionInput {
* 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: 'ptc'`, only calls WITH a parent may
+ * model-direct call: with the PTC executor selected, 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.
*/
@@ -635,6 +635,7 @@ schemas(scope?: ScopeKey): ToolSchema[]
/**
* Provide the executor for the calling scope; an unscoped contribution is the deployment default.
+ * Rendering any executor-owned section requires the viewing scope's selection to remain available.
* @param executor - initialized provider owned by the contributing plugin.
* @returns the effect disposer. Unloading leaves the selection unavailable until it is replaced.
*/
diff --git a/docs/upgrade-guide/v0.2.1-rc.2/tool-executor-plugins/guide.i18n.yaml b/docs/upgrade-guide/v0.2.1-rc.2/tool-executor-plugins/guide.i18n.yaml
index bf3b31aa5b..60370bde67 100644
--- a/docs/upgrade-guide/v0.2.1-rc.2/tool-executor-plugins/guide.i18n.yaml
+++ b/docs/upgrade-guide/v0.2.1-rc.2/tool-executor-plugins/guide.i18n.yaml
@@ -9,8 +9,8 @@
en: 73002a2963b9ea27
zh: a67ea382d7c70c61
/mount-a-tool-executor/change:
- en: b47c04b407b204a9
- zh: f3f54c9b25eb1951
+ en: f732d85027bf0236
+ zh: d6597cde7ba31e47
/mount-a-tool-executor/migration:
en: 411860d06f1013ea
zh: 615e044545d89b55
diff --git a/docs/upgrade-guide/v0.2.1-rc.2/tool-executor-plugins/guide.md b/docs/upgrade-guide/v0.2.1-rc.2/tool-executor-plugins/guide.md
index 9c3fc0bc4a..9ea22ca563 100644
--- a/docs/upgrade-guide/v0.2.1-rc.2/tool-executor-plugins/guide.md
+++ b/docs/upgrade-guide/v0.2.1-rc.2/tool-executor-plugins/guide.md
@@ -9,7 +9,7 @@ English | [中文](guide.zh.md)
## Change
-`@deepseek-ai/dsh-tools` keeps tool registration and executor selection, but no longer accepts `mode` or `maxParallelSubCalls`. Native and PTC execution require `@deepseek-ai/dsh-tool-executor-native` or `@deepseek-ai/dsh-tool-executor-ptc`. Shipped profiles mount an executor; custom compositions must add one. The existing `dsh-agent-tool-presentation` selector remains supported but is deprecated. Enabled `tool-executor-native` and `tool-executor-ptc` rows are required at startup; invalid executor configuration now stops startup.
+`@deepseek-ai/dsh-tools` keeps tool registration and executor selection, but rejects the removed `mode` and `maxParallelSubCalls` configuration fields at load time. Native and PTC execution require `@deepseek-ai/dsh-tool-executor-native` or `@deepseek-ai/dsh-tool-executor-ptc`. Shipped profiles mount an executor; custom compositions must add one. The existing `dsh-agent-tool-presentation` selector remains supported but is deprecated. Enabled `tool-executor-native` and `tool-executor-ptc` rows are required at startup; invalid executor configuration now stops startup.
## Migration
diff --git a/docs/upgrade-guide/v0.2.1-rc.2/tool-executor-plugins/guide.zh.md b/docs/upgrade-guide/v0.2.1-rc.2/tool-executor-plugins/guide.zh.md
index 0d9e484c8e..6e0f4c9a24 100644
--- a/docs/upgrade-guide/v0.2.1-rc.2/tool-executor-plugins/guide.zh.md
+++ b/docs/upgrade-guide/v0.2.1-rc.2/tool-executor-plugins/guide.zh.md
@@ -9,7 +9,7 @@ description: "工具执行模式从 dsh-tools 配置移至显式执行器插件
## 变更
-`@deepseek-ai/dsh-tools` 保留工具注册和执行器选择,但不再接受 `mode` 或 `maxParallelSubCalls`。原生和 PTC 执行分别要求 `@deepseek-ai/dsh-tool-executor-native` 或 `@deepseek-ai/dsh-tool-executor-ptc`。内置 profile 已挂载执行器,自定义组合必须添加一个。现有 `dsh-agent-tool-presentation` 选择器仍受支持,但已弃用。 启用的 `tool-executor-native` 和 `tool-executor-ptc` 条目属于启动必需项;无效的执行器配置会终止启动。
+`@deepseek-ai/dsh-tools` 保留工具注册和执行器选择,但加载时会拒绝已移除的 `mode` 和 `maxParallelSubCalls` 配置字段。原生和 PTC 执行分别要求 `@deepseek-ai/dsh-tool-executor-native` 或 `@deepseek-ai/dsh-tool-executor-ptc`。内置 profile 已挂载执行器,自定义组合必须添加一个。现有 `dsh-agent-tool-presentation` 选择器仍受支持,但已弃用。启用的 `tool-executor-native` 和 `tool-executor-ptc` 条目属于启动必需项;无效的执行器配置会终止启动。
## 迁移
diff --git a/packages/context/session-reference/package.json b/packages/context/session-reference/package.json
index e7ffcca708..8cefe88f74 100644
--- a/packages/context/session-reference/package.json
+++ b/packages/context/session-reference/package.json
@@ -47,7 +47,6 @@
"license": "MIT",
"dependencies": {
"@deepseek-ai/dsh-brand": "workspace:*",
- "@deepseek-ai/dsh-tool-executor-native": "workspace:*",
"@deepseek-ai/dsh-util-values": "workspace:*",
"@deepseek-ai/schemastery": "workspace:~",
"zod": "4.4.3"
@@ -95,6 +94,7 @@
"@deepseek-ai/dsh-subagent": "workspace:*",
"@deepseek-ai/dsh-spill-local": "workspace:*",
"@deepseek-ai/dsh-system-prompt": "workspace:*",
+ "@deepseek-ai/dsh-tool-executor-native": "workspace:*",
"@deepseek-ai/dsh-tool-fs": "workspace:*",
"@deepseek-ai/dsh-tool-testkit": "workspace:*",
"@deepseek-ai/dsh-tools": "workspace:*",
diff --git a/packages/core/agent-loop/tests/tool-calls.spec.ts b/packages/core/agent-loop/tests/tool-calls.spec.ts
index a57106751d..d08e9f6bca 100644
--- a/packages/core/agent-loop/tests/tool-calls.spec.ts
+++ b/packages/core/agent-loop/tests/tool-calls.spec.ts
@@ -1,8 +1,8 @@
-import type { ToolExecutionPipeline } from '@deepseek-ai/dsh-tools/pipeline'
/**
* Exercises scheduler ordering and cancellation with deterministic gated tools.
* ACP expected outputs own transcript-facing coverage.
*/
+import type { ToolExecutionPipeline } from '@deepseek-ai/dsh-tools/pipeline'
import * as NativeToolExecutor from '@deepseek-ai/dsh-tool-executor-native'
import * as PtcToolExecutor from '@deepseek-ai/dsh-tool-executor-ptc'
@@ -37,13 +37,13 @@ async function harness(adapter: MockAdapter, maxParallelToolCalls?: number, exec
await ctx.plugin(ToolRuntime)
let toolPipeline!: ToolExecutionPipeline
await ctx.plugin({
- inject: ['tools'], Config: NativeToolExecutor.Config,
- apply(owner: Context, config: NativeToolExecutor.Config) {
- const executor = new NativeToolExecutor.NativeToolExecutor(owner, () => config.maxParallelToolCalls.get())
+ inject: ['tools'],
+ apply(owner: Context) {
+ const executor = new NativeToolExecutor.NativeToolExecutor(owner, () => executorLimit ?? 10)
toolPipeline = executor['pipeline']
owner.tools.setExecutor(executor)
},
- }, { ...executorLimit === undefined ? {} : { maxParallelToolCalls: executorLimit } })
+ })
await ctx.plugin(AgentRegistry)
await ctx.plugin(AgentLoop, {
agents: [],
diff --git a/packages/core/agent-tool-presentation/README.i18n.yaml b/packages/core/agent-tool-presentation/README.i18n.yaml
index 2a2ed58937..b39ccedaf7 100644
--- a/packages/core/agent-tool-presentation/README.i18n.yaml
+++ b/packages/core/agent-tool-presentation/README.i18n.yaml
@@ -21,8 +21,8 @@
en: 1550e3dcc5a3aa1e
zh: 47b2d1e0e3e3cbf2
/deepseek-ai-dsh-agent-tool-presentation/use-this-package/what-ptc-mode-requires:
- en: d5004b2caa31b245
- zh: 32619d7e03c7c2ac
+ en: 3ec33f18b3ac0859
+ zh: 92bf371bfbbc511d
/deepseek-ai-dsh-agent-tool-presentation/use-this-package/one-presentation-per-agent:
en: 46bf80f051175567
zh: 8f5e1623da5d1520
@@ -36,8 +36,8 @@
en: 89ecdb3d5d032e7f
zh: 64ae2feb4344c679
/deepseek-ai-dsh-agent-tool-presentation/understand-the-implementation/behavior-notes:
- en: 7996925328f0e771
- zh: 40146455aac119d2
+ en: 4a44ac4057732829
+ zh: 813d3ec7627146fd
/deepseek-ai-dsh-agent-tool-presentation/further-exploration:
en: 6a1d0096e4da25e4
zh: 9d5de770addb69d2
diff --git a/packages/core/agent-tool-presentation/README.md b/packages/core/agent-tool-presentation/README.md
index 569ee37d63..b3c22d9bfe 100644
--- a/packages/core/agent-tool-presentation/README.md
+++ b/packages/core/agent-tool-presentation/README.md
@@ -45,7 +45,7 @@ The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-a
### What PTC mode requires
-Selecting `ptc` needs a composed PTC runtime (`ctx.ptcRuntime`) whose language has a registered SDK renderer — the TypeScript runtime ships via [`dsh-ptc-runtime-node`](../../ptc-runtime/ptc-runtime-node/README.md), and both the TypeScript and Python SDK renderers are built into `dsh-tool-executor-ptc`. A preset that selects a PTC mode against a deployment composing no such runtime refuses to mount, naming this row, so the failure lands where the operator can act instead of at the session's first request.
+Selecting `ptc` needs a composed PTC runtime (`ctx.ptcRuntime`) whose language has a registered SDK renderer — the TypeScript runtime ships via [`dsh-ptc-runtime-node`](../../ptc-runtime/ptc-runtime-node/README.md), and both the TypeScript and Python SDK renderers are built into `dsh-tool-executor-ptc`. Selection takes effect even when the runtime is missing; prompt assembly or program execution then reports the missing runtime instead of inheriting native execution.
### One presentation per agent
@@ -73,7 +73,7 @@ The tool registry cannot move into a preset: its consumers are all host-plane
### Behavior notes
-`native` applies immediately. A PTC mode instead waits for `ctx.ptcRuntime`, a host-plane service: a preset selecting PTC mode against a deployment composing no runtime holds this row pending, and `dsh-agent-preset-registry` refuses the mount naming this id. `setExecutor` is itself the effect, so the declaration unwinds with this row without a second wrapper owning it.
+Both modes mount their executor immediately. PTC checks runtime availability when describing or executing a program. The mounted executor owns its scoped registration, which is withdrawn with this selector's plugin lifetime.
diff --git a/packages/core/agent-tool-presentation/README.zh.md b/packages/core/agent-tool-presentation/README.zh.md
index e30fc01cb5..f54c3799a6 100644
--- a/packages/core/agent-tool-presentation/README.zh.md
+++ b/packages/core/agent-tool-presentation/README.zh.md
@@ -45,7 +45,7 @@ kind: "package-reference"
### PTC 模式需要什么
-选择 `ptc` 需要已组合的 PTC 运行时(`ctx.ptcRuntime`),且其语言有已注册的 SDK 渲染器——TypeScript 运行时经 [`dsh-ptc-runtime-node`](../../ptc-runtime/ptc-runtime-node/README.zh.md) 交付,TypeScript 与 Python 的 SDK 渲染器都内置在 `dsh-tools` 中。针对未组装此类运行时的部署选择 PTC 模式的 preset 会拒绝挂载并点名这一行,使失败落在操作者可以行动的地方,而不是落在会话的第一次请求上。
+选择 `ptc` 需要已组合的 PTC 运行时(`ctx.ptcRuntime`),且其语言有已注册的 SDK 渲染器——TypeScript 运行时经 [`dsh-ptc-runtime-node`](../../ptc-runtime/ptc-runtime-node/README.zh.md) 交付,TypeScript 与 Python 的 SDK 渲染器都内置在 `dsh-tool-executor-ptc` 中。即使缺少运行时,选择也会生效;随后提示词组装或程序执行会报告缺少运行时,而不会继承原生执行方式。
### 每个 agent 只声明一次呈现方式
@@ -73,7 +73,7 @@ kind: "package-reference"
### 行为说明
-`native` 立即生效。PTC 模式则等待 `ctx.ptcRuntime`——这是一个宿主平面服务:针对未组装运行时的部署选择 PTC mode 的 preset 会让这一行停在 pending,`dsh-agent-preset-registry` 会指名此 id 拒绝挂载。`setExecutor` 本身就是 effect,因此该声明随这一行撤销,无需第二个包装层拥有它。
+两种模式都会立即挂载各自的执行器。PTC 在描述或执行程序时检查运行时是否可用。挂载的执行器拥有作用域注册,并随此选择器的插件生命周期一同撤销。
diff --git a/packages/core/agent-tool-presentation/src/index.ts b/packages/core/agent-tool-presentation/src/index.ts
index cc621472e3..ce986fce5f 100644
--- a/packages/core/agent-tool-presentation/src/index.ts
+++ b/packages/core/agent-tool-presentation/src/index.ts
@@ -13,9 +13,8 @@ import * as PtcToolExecutor from '@deepseek-ai/dsh-tool-executor-ptc'
export const name = 'tool-presentation'
/**
- * Required services. `ptcRuntime` is NOT listed: a `native` row must mount in
- * a deployment that composes no runtime, and the mode-dependent wait is
- * declared inside {@link apply} instead.
+ * Tool selection does not require a program runtime; the PTC executor
+ * reports a missing runtime when its description or execution is requested.
*/
export const inject = ['tools']
diff --git a/packages/core/agent-tool-presentation/tests/agent-tool-presentation.spec.ts b/packages/core/agent-tool-presentation/tests/agent-tool-presentation.spec.ts
index 3dcbbc747c..4481f31788 100644
--- a/packages/core/agent-tool-presentation/tests/agent-tool-presentation.spec.ts
+++ b/packages/core/agent-tool-presentation/tests/agent-tool-presentation.spec.ts
@@ -1,9 +1,8 @@
/**
* The row an agent preset carries to pick its tool presentation. What it owes
* its caller: the choice reaches THIS agent and no other, it unwinds with the
- * agent, and a code mode composed against a deployment with no PTC runtime
- * stops at mount — where a preset's activation audit can name it — rather
- * than at the first prompt assembly.
+ * agent, and a missing PTC runtime rejects the selected scope's prompt
+ * instead of inheriting the native executor.
*/
import * as NativeToolExecutor from '@deepseek-ai/dsh-tool-executor-native'
@@ -68,8 +67,7 @@ describe('the tool-presentation row', () => {
})
it('declares the services it uses without holding a PTC runtime hostage', () => {
- // A `native` row must mount where no runtime is composed, so the wait is
- // conditional inside apply rather than static metadata.
+ // Native execution does not require a program runtime.
expect(inject).toEqual(['tools'])
})
@@ -95,17 +93,13 @@ describe('the tool-presentation row', () => {
await expect(ctx.systemPrompt.assemble({ scope: agent })).rejects.toThrow('selected tool executor is unavailable')
})
- it('waits for a PTC runtime the deployment does not compose', async () => {
+ it('rejects PTC assembly when the deployment does not compose its runtime', async () => {
const ctx = await host({ runtime: false })
const { agent, row } = await mount(ctx, { mode: 'ptc' })
- // Pending, not applied: `dsh-agent-preset-registry` rejects a mount holding a row
- // that never reached a usable state, naming this id — so the preset fails
- // where the operator can act, instead of at the first request.
expect(row.ctx.get('ptcRuntime')).toBeUndefined()
- const assembly = await ctx.systemPrompt.assemble({ scope: agent })
- expect(assembly.tools.map(tool => tool.name)).toEqual(['echo'])
+ await expect(ctx.systemPrompt.assemble({ scope: agent })).rejects.toThrow('requires a PTC runtime')
})
it('applies once the runtime arrives', async () => {
diff --git a/packages/core/tool-executor-native/README.i18n.yaml b/packages/core/tool-executor-native/README.i18n.yaml
index 118a6d84fb..8d8ed7b889 100644
--- a/packages/core/tool-executor-native/README.i18n.yaml
+++ b/packages/core/tool-executor-native/README.i18n.yaml
@@ -15,11 +15,11 @@
en: d152484eb41ac6b4
zh: 09388d293f9be9cb
/deepseek-ai-dsh-tool-executor-native/use-this-package:
- en: 176f69450bacc28e
- zh: fc3c2d876195a4a4
+ en: 0e73b1a49308a0f6
+ zh: 968b3ee68284d849
/deepseek-ai-dsh-tool-executor-native/understand-the-implementation:
- en: d005036097c11788
- zh: 65fcaec551dc1697
+ en: 6a06c6b318f58436
+ zh: 4f572feca095e3a6
/deepseek-ai-dsh-tool-executor-native/further-exploration:
en: e8ae407b0ecdc5d3
zh: 022a8a714d24da4b
diff --git a/packages/core/tool-executor-native/README.md b/packages/core/tool-executor-native/README.md
index 5d6103c5fc..0841540ba6 100644
--- a/packages/core/tool-executor-native/README.md
+++ b/packages/core/tool-executor-native/README.md
@@ -29,13 +29,9 @@ Add this row to a composition with `dsh-tools` mounted. The nearest scoped execu
```yaml
- name: '@deepseek-ai/dsh-tool-executor-native'
- config:
- maxParallelToolCalls: 10
```
-For Agent steps, configure [agent-loop concurrency](../agent-loop/README.md); the loop always forwards its resolved limit to `execute()`. The executor's `maxParallelToolCalls` supplies the limit only when the caller omits it. This fallback is volatile, defaults to `10`, and is sampled for the next tool group. It must be a positive integer; `1` selects serial execution.
-
-[Configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-tool-executor-native)
+Configure [agent-loop concurrency](../agent-loop/README.md) for Agent steps; the loop reads the limit once per batch. This plugin has no configuration fields. Direct `NativeToolExecutor` callers may pass a constructor callback, defaulting to `10`, which is sampled for each tool group when the batch omits `maxParallelToolCalls`. Limits must be positive integers; `1` selects serial execution.
-----
@@ -47,7 +43,7 @@ For Agent steps, configure [agent-loop concurrency](../agent-loop/README.md); th
The executor receives the entire raw call batch and owns parsing, scheduling, cancellation, and optional model-step logging. It reuses the shared invocation pipeline for policy, tool bodies, and result notifications. After abort, it waits for started work and returns ordered error results for skipped calls.
-- [`src/index.ts`](src/index.ts) — Validated configuration and scoped registration; tool descriptions and batch execution.
+- [`src/index.ts`](src/index.ts) — Scoped executor registration; tool descriptions and batch execution.
diff --git a/packages/core/tool-executor-native/README.zh.md b/packages/core/tool-executor-native/README.zh.md
index 82f71691e6..4c9ea6ee19 100644
--- a/packages/core/tool-executor-native/README.zh.md
+++ b/packages/core/tool-executor-native/README.zh.md
@@ -29,13 +29,9 @@ kind: "package-reference"
```yaml
- name: '@deepseek-ai/dsh-tool-executor-native'
- config:
- maxParallelToolCalls: 10
```
-Agent 步骤使用 [agent-loop 并发配置](../agent-loop/README.zh.md),循环始终向 `execute()` 传入解析后的上限。只有调用方未传入上限时,才使用执行器的 `maxParallelToolCalls`。这个后备配置是 volatile 字段,默认值为 `10`,在下一个工具组开始时读取。值必须是正整数;`1` 表示串行执行。
-
-[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-tool-executor-native)
+Agent 步骤使用 [agent-loop 并发配置](../agent-loop/README.zh.md),循环在每个批次开始时读取一次上限。本插件没有配置字段。直接构造 `NativeToolExecutor` 的调用方可以传入回调,默认返回 `10`;批次未指定 `maxParallelToolCalls` 时,每个工具组读取该回调。上限必须是正整数;`1` 表示串行执行。
-----
@@ -47,7 +43,7 @@ Agent 步骤使用 [agent-loop 并发配置](../agent-loop/README.zh.md),循
执行器接收完整的原始调用批次,负责解析、调度、取消和可选的模型步骤日志。它复用共享调用流水线来执行策略、工具和结果通知。中止后,它等待已开始的工作完成,并为跳过的调用返回有序错误结果。
-- [`src/index.ts`](src/index.ts) — 配置校验和作用域注册;工具描述和批次执行。
+- [`src/index.ts`](src/index.ts) — 作用域执行器注册;工具描述和批次执行。
diff --git a/packages/core/tool-executor-native/package.json b/packages/core/tool-executor-native/package.json
index 3b733d5e63..e027d0e9bb 100644
--- a/packages/core/tool-executor-native/package.json
+++ b/packages/core/tool-executor-native/package.json
@@ -28,17 +28,12 @@
],
"peerDependencies": {
"@deepseek-ai/cordis": "workspace:~",
- "@deepseek-ai/cosmokit": "workspace:~",
"@deepseek-ai/dsh-llm": "workspace:*",
"@deepseek-ai/dsh-scope": "workspace:*",
"@deepseek-ai/dsh-tools": "workspace:*"
},
- "dependencies": {
- "@deepseek-ai/schemastery": "workspace:~"
- },
"devDependencies": {
"@deepseek-ai/cordis": "workspace:~",
- "@deepseek-ai/cosmokit": "workspace:~",
"@deepseek-ai/dsh-llm": "workspace:*",
"@deepseek-ai/dsh-scope": "workspace:*",
"@deepseek-ai/dsh-tools": "workspace:*"
diff --git a/packages/core/tool-executor-native/src/index.ts b/packages/core/tool-executor-native/src/index.ts
index 24685a696b..457749152c 100644
--- a/packages/core/tool-executor-native/src/index.ts
+++ b/packages/core/tool-executor-native/src/index.ts
@@ -3,15 +3,13 @@ import type { Context } from '@deepseek-ai/cordis'
import { projectToolSchema } from '@deepseek-ai/dsh-tools'
import type { ToolDefinition, ToolExecutor, ToolModelInput, ToolBatchInput, ToolBatchResult } from '@deepseek-ai/dsh-tools'
import { ToolExecutionPipeline, executeToolBatch } from '@deepseek-ai/dsh-tools/pipeline'
-import type { Volatile } from '@deepseek-ai/cosmokit'
-import z from '@deepseek-ai/schemastery'
/** Executes visible capabilities directly and owns their complete batch settlement. */
export class NativeToolExecutor implements ToolExecutor {
private readonly pipeline: ToolExecutionPipeline
constructor(ctx: Context, private readonly maxParallel: () => number = () => 10) {
- this.pipeline = new ToolExecutionPipeline(ctx, { get: (name, scope) => ctx.tools.get(name, scope) })
+ this.pipeline = new ToolExecutionPipeline(ctx)
}
describe(tools: readonly ToolDefinition[]): ToolModelInput {
@@ -28,22 +26,10 @@ export const name = 'native-tool-executor'
/** Tool registration and scoped dispatch. */
export const inject = ['tools']
-/** Native batch concurrency configuration. */
-export interface Config {
- /** Maximum overlapping concurrency-safe calls in one batch. */
- maxParallelToolCalls: Volatile
-}
-
-/** Validated live concurrency limit; one makes each batch serial. */
-export const Config: z<{ maxParallelToolCalls?: number }, Config> = z.object({
- maxParallelToolCalls: z.number().step(1).min(1).default(10).volatile(),
-})
-
/**
* Select native execution in the mounting scope.
* @param ctx - context owning this executor's selection and lifetime.
- * @param config - live batch concurrency configuration.
*/
-export function apply(ctx: Context, config: Config): void {
- ctx.tools.setExecutor(new NativeToolExecutor(ctx, () => config.maxParallelToolCalls.get()))
+export function apply(ctx: Context): void {
+ ctx.tools.setExecutor(new NativeToolExecutor(ctx))
}
diff --git a/packages/core/tool-executor-ptc/README.i18n.yaml b/packages/core/tool-executor-ptc/README.i18n.yaml
index 3a3836c1d0..e6d35ea2bc 100644
--- a/packages/core/tool-executor-ptc/README.i18n.yaml
+++ b/packages/core/tool-executor-ptc/README.i18n.yaml
@@ -9,17 +9,17 @@
en: e253ed9cec03a396
zh: 922fde282e2b0fd2
/deepseek-ai-dsh-tool-executor-ptc/summary:
- en: 60fb16b4d443d265
- zh: 6b0df6471c370c6b
+ en: 66e159c308afb6c1
+ zh: 29b1a646ae7f918a
/deepseek-ai-dsh-tool-executor-ptc/table-of-contents:
en: d152484eb41ac6b4
zh: 09388d293f9be9cb
/deepseek-ai-dsh-tool-executor-ptc/use-this-package:
- en: 5cfc28690358a419
- zh: d066d078ca649022
+ en: 488f394426b3aaa0
+ zh: a15185f91a1c342c
/deepseek-ai-dsh-tool-executor-ptc/understand-the-implementation:
- en: f054dc0faabb468f
- zh: 10f13508bfa9ef84
+ en: 9d4f61c351945d30
+ zh: 1c575526230b0e02
/deepseek-ai-dsh-tool-executor-ptc/understand-the-implementation/ptc-mode:
en: 11d32e05ba397f86
zh: 4e071ec4e6222d9d
diff --git a/packages/core/tool-executor-ptc/README.md b/packages/core/tool-executor-ptc/README.md
index b7b56146a5..7519301f2a 100644
--- a/packages/core/tool-executor-ptc/README.md
+++ b/packages/core/tool-executor-ptc/README.md
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
## Summary
-Use this executor when models should call tools through `run_code` programs. Mount a compatible PTC runtime and tool registry first. Scoped restrictions determine the generated SDK; only `run_code` is directly callable. Configure root-call and program-subcall concurrency independently.
+Use this executor when models should call tools through `run_code` programs. Mount a compatible PTC runtime and tool registry first. Scoped restrictions determine the generated SDK; only `run_code` is directly callable. Configure concurrency for parallel-safe program subcalls.
## Table of Contents
@@ -30,13 +30,12 @@ Add this row to a composition with `dsh-tools` mounted. The nearest scoped execu
```yaml
- name: '@deepseek-ai/dsh-tool-executor-ptc'
config:
- maxParallelToolCalls: 10
maxParallelSubCalls: 10
```
-For Agent steps, configure [agent-loop concurrency](../agent-loop/README.md); the loop always forwards its resolved limit to `execute()`. The executor's `maxParallelToolCalls` supplies the limit only when the caller omits it. This fallback is volatile, defaults to `10`, and is sampled for the next tool group. It must be a positive integer; `1` selects serial execution.
+Root `run_code` calls are exclusive and execute serially. `maxParallelSubCalls` limits parallel-safe nested calls within each program and defaults to `10`; it must be a positive integer, with `1` selecting serial execution. Exclusive calls form barriers.
-This package also requires `ctx.ptcRuntime` and `ctx.systemPrompt`; Agent-owned programs need `ctx.workingDirectory`. `maxParallelSubCalls` limits overlapping parallel-safe calls within each program and defaults to `10`.
+This package also requires `ctx.ptcRuntime` and `ctx.systemPrompt`; Agent-owned programs need `ctx.workingDirectory`. A missing runtime rejects prompt assembly or execution; the selected PTC executor never falls back to native execution.
Import durable event payloads from `@deepseek-ai/dsh-tool-executor-ptc/types`; this entry is safe for detached readers and client compilation. Host policy extensions import `PtcDispatchLog`, `tools/ptc-dispatch-log`, and the `ptc-mode` message-source declaration through a type-only import of the package entry, without mounting an executor.
@@ -50,7 +49,7 @@ Import durable event payloads from `@deepseek-ai/dsh-tool-executor-ptc/types`; t
Implementation internals — click to expand
-The executor receives the entire raw call batch and owns parsing, scheduling, cancellation, and optional model-step logging. It reuses the shared invocation pipeline for policy, tool bodies, and result notifications. After abort, it waits for started work and returns ordered error results for skipped calls.
+The executor receives the entire raw call batch and owns parsing, scheduling, cancellation, and optional model-step logging. It reuses the shared invocation pipeline for policy, tool bodies, and result notifications. After abort, it waits for started work and returns ordered error results for skipped calls. Unloading the executor aborts active sandboxed programs and waits for their nested calls to settle. Accepted batches still settle through that executor, potentially with cancellation errors.
### PTC mode
diff --git a/packages/core/tool-executor-ptc/README.zh.md b/packages/core/tool-executor-ptc/README.zh.md
index f4d60631ea..8625183568 100644
--- a/packages/core/tool-executor-ptc/README.zh.md
+++ b/packages/core/tool-executor-ptc/README.zh.md
@@ -9,7 +9,7 @@ kind: "package-reference"
## 概述
-当模型应通过 `run_code` 程序调用工具时,使用此执行器。先挂载兼容的 PTC 运行时和工具注册表。作用域限制决定生成的 SDK;只有 `run_code` 能被直接调用。根调用和程序子调用的并发限制分别配置。
+当模型应通过 `run_code` 程序调用工具时,使用此执行器。先挂载兼容的 PTC 运行时和工具注册表。作用域限制决定生成的 SDK;只有 `run_code` 能被直接调用。可配置并行安全的程序子调用并发上限。
## 目录
@@ -30,13 +30,12 @@ kind: "package-reference"
```yaml
- name: '@deepseek-ai/dsh-tool-executor-ptc'
config:
- maxParallelToolCalls: 10
maxParallelSubCalls: 10
```
-Agent 步骤使用 [agent-loop 并发配置](../agent-loop/README.zh.md),循环始终向 `execute()` 传入解析后的上限。只有调用方未传入上限时,才使用执行器的 `maxParallelToolCalls`。这个后备配置是 volatile 字段,默认值为 `10`,在下一个工具组开始时读取。值必须是正整数;`1` 表示串行执行。
+根 `run_code` 调用是独占调用,按串行执行。`maxParallelSubCalls` 限制每个程序中并行安全的嵌套调用数,默认值为 `10`;值必须是正整数,`1` 表示串行执行。独占调用构成屏障。
-本包还要求 `ctx.ptcRuntime` 和 `ctx.systemPrompt`;带 Agent 的程序要求 `ctx.workingDirectory`。`maxParallelSubCalls` 限制每个程序内重叠的并行安全调用,默认值为 `10`。
+本包还要求 `ctx.ptcRuntime` 和 `ctx.systemPrompt`;带 Agent 的程序要求 `ctx.workingDirectory`。缺少运行时时,提示词组装或执行会失败;选中的 PTC 执行器不会回退到原生执行。
持久化事件载荷从 `@deepseek-ai/dsh-tool-executor-ptc/types` 导入;该入口可用于独立读取者与 Client 编译。Host 策略扩展通过包主入口的仅类型导入获取 `PtcDispatchLog`、`tools/ptc-dispatch-log` 与 `ptc-mode` 消息来源声明,无需挂载执行器。
@@ -50,7 +49,7 @@ Agent 步骤使用 [agent-loop 并发配置](../agent-loop/README.zh.md),循
实现细节——点击展开
-执行器接收完整的原始调用批次,负责解析、调度、取消和可选的模型步骤日志。它复用共享调用流水线来执行策略、工具和结果通知。中止后,它等待已开始的工作完成,并为跳过的调用返回有序错误结果。
+执行器接收完整的原始调用批次,负责解析、调度、取消和可选的模型步骤日志。它复用共享调用流水线来执行策略、工具和结果通知。中止后,它等待已开始的工作完成,并为跳过的调用返回有序错误结果。卸载执行器会中止运行中的沙箱程序,并等待其嵌套调用结束。已接纳批次仍由该执行器结算,但可能返回取消错误。
### PTC mode
diff --git a/packages/core/tool-executor-ptc/package.json b/packages/core/tool-executor-ptc/package.json
index 89c8973e84..c2dc63b7e1 100644
--- a/packages/core/tool-executor-ptc/package.json
+++ b/packages/core/tool-executor-ptc/package.json
@@ -33,7 +33,6 @@
],
"peerDependencies": {
"@deepseek-ai/cordis": "workspace:~",
- "@deepseek-ai/cosmokit": "workspace:~",
"@deepseek-ai/dsh-agent": "workspace:*",
"@deepseek-ai/dsh-llm": "workspace:*",
"@deepseek-ai/dsh-ptc-runtime": "workspace:*",
@@ -52,7 +51,6 @@
},
"devDependencies": {
"@deepseek-ai/cordis": "workspace:~",
- "@deepseek-ai/cosmokit": "workspace:~",
"@deepseek-ai/dsh-agent": "workspace:*",
"@deepseek-ai/dsh-agent-loop-testkit": "workspace:*",
"@deepseek-ai/dsh-llm": "workspace:*",
diff --git a/packages/core/tool-executor-ptc/src/config.ts b/packages/core/tool-executor-ptc/src/config.ts
new file mode 100644
index 0000000000..b2710764e2
--- /dev/null
+++ b/packages/core/tool-executor-ptc/src/config.ts
@@ -0,0 +1,13 @@
+/** Configuration shared by plugin mounting and direct executor construction. @module */
+import z from '@deepseek-ai/schemastery'
+
+/** Program execution limits. */
+export interface Config {
+ /** Maximum overlapping concurrency-safe program subcalls. */
+ maxParallelSubCalls: number
+}
+
+/** Validated program subcall concurrency; one makes subcalls serial. */
+export const Config: z, Config> = z.object({
+ maxParallelSubCalls: z.natural().min(1).default(10),
+})
diff --git a/packages/core/tool-executor-ptc/src/index.ts b/packages/core/tool-executor-ptc/src/index.ts
index 74de8722b0..fa6c00086b 100644
--- a/packages/core/tool-executor-ptc/src/index.ts
+++ b/packages/core/tool-executor-ptc/src/index.ts
@@ -1,14 +1,12 @@
/** PTC execution plugin for the mounting Agent, preset, or deployment scope. @module */
import type { Context } from '@deepseek-ai/cordis'
-import type { ScopeKey } from '@deepseek-ai/dsh-scope'
import { RUN_CODE_NAME, ToolNotFoundError, projectToolSchema } from '@deepseek-ai/dsh-tools'
import type { ToolDefinition, ToolExecutor, ToolModelInput, ToolPromptSection, ToolBatchInput, ToolBatchResult } from '@deepseek-ai/dsh-tools'
import { ToolExecutionPipeline, executeToolBatch } from '@deepseek-ai/dsh-tools/pipeline'
import { createRunCodeTool, requirePtcRuntime, type PtcSdkLanguage } from './ptc.ts'
import { renderToolsSdk, type ToolSdkSchema } from './ts-types.ts'
import { renderToolsSdkPy } from './py-types.ts'
-import type { Volatile } from '@deepseek-ai/cosmokit'
-import z from '@deepseek-ai/schemastery'
+import { Config } from './config.ts'
const PTC_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.`
@@ -24,17 +22,15 @@ export class PtcExecutor implements ToolExecutor {
private readonly maxParallelSubCalls: number
private ptcTransport: ToolDefinition | undefined
- constructor(private readonly ctx: Context, config: Pick = {}, private readonly maxParallel: () => number = () => 10) {
+ constructor(private readonly ctx: Context, config: Partial = {}, private readonly maxParallel: () => number = () => 10) {
+ this.maxParallelSubCalls = Config(config).maxParallelSubCalls
+ const tools = ctx.tools
this.sections = [
{ name: 'tools:ptc-only', order: ctx.systemPrompt.getSectionOrder('PTC_ONLY'), text: PTC_ONLY_INSTRUCTION, interpolate: false },
{ name: 'tools:sdk', order: ctx.systemPrompt.getSectionOrder('TOOLS_SDK'), text: tools => this.renderSdk(tools), interpolate: false },
]
- this.maxParallelSubCalls = config.maxParallelSubCalls ?? 10
- if (!Number.isInteger(this.maxParallelSubCalls) || this.maxParallelSubCalls < 1) {
- throw new Error('maxParallelSubCalls must be a positive integer')
- }
this.pipeline = new ToolExecutionPipeline(ctx, {
- get: (name, scope) => this.get(name, scope),
+ get: (name, scope) => name === RUN_CODE_NAME ? this.requirePtcTransport() : tools.get(name, scope),
reject: (name, nested) => !nested && name !== RUN_CODE_NAME
? new ToolNotFoundError(name, `only \`${RUN_CODE_NAME}\` is callable directly — call \`${name}\` from inside a \`${RUN_CODE_NAME}\` program instead`)
: undefined,
@@ -54,10 +50,6 @@ export class PtcExecutor implements ToolExecutor {
})), runtime.programFormat)
}
- private get(name: string, scope?: ScopeKey): ToolDefinition | undefined {
- return name === RUN_CODE_NAME ? this.requirePtcTransport() : this.ctx.tools.get(name, scope)
- }
-
execute(input: ToolBatchInput): Promise {
return executeToolBatch(input, this.pipeline, this.maxParallel)
}
@@ -69,6 +61,7 @@ export class PtcExecutor implements ToolExecutor {
}
}
+export { Config } from './config.ts'
export { CodeRunFailedError } from './errors.ts'
export type { PtcDispatchLog } from './types.ts'
export type { PtcDispatchStartEventData, PtcDispatchEventData } from './session-types.ts'
@@ -77,22 +70,8 @@ export { jsonSchemaToPy, renderToolsSdkPy } from './py-types.ts'
/** Cordis plugin name. */
export const name = 'ptc-tool-executor'
-/** The program provider activates with its runtime. */
-export const inject = ['tools', 'systemPrompt', 'ptcRuntime']
-
-/** Program execution limits. */
-export interface Config {
- /** Maximum overlapping concurrency-safe calls in one model batch. */
- maxParallelToolCalls: Volatile
- /** Maximum overlapping concurrency-safe program subcalls. */
- maxParallelSubCalls?: number
-}
-
-/** Validated program execution configuration. */
-export const Config: z<{ maxParallelToolCalls?: number; maxParallelSubCalls?: number }, Config> = z.object({
- maxParallelToolCalls: z.number().step(1).min(1).default(10).volatile(),
- maxParallelSubCalls: z.natural().min(1).default(10),
-})
+/** Register the selected executor even when its runtime is unavailable. */
+export const inject = ['tools', 'systemPrompt']
/**
* Select PTC execution in the mounting scope.
@@ -100,5 +79,5 @@ export const Config: z<{ maxParallelToolCalls?: number; maxParallelSubCalls?: nu
* @param config - program subcall concurrency limits.
*/
export function apply(ctx: Context, config: Config): void {
- ctx.tools.setExecutor(new PtcExecutor(ctx, config, () => config.maxParallelToolCalls.get()))
+ ctx.tools.setExecutor(new PtcExecutor(ctx, config))
}
diff --git a/packages/core/tool-executor-ptc/src/ptc-calls.ts b/packages/core/tool-executor-ptc/src/ptc-calls.ts
index 16de96380c..c088ff92b4 100644
--- a/packages/core/tool-executor-ptc/src/ptc-calls.ts
+++ b/packages/core/tool-executor-ptc/src/ptc-calls.ts
@@ -15,8 +15,8 @@ export class PtcCalls {
private disposed = false
/**
- * Observe policy changes for the owning tool registry.
- * @param ctx - Registry lifecycle and Session events.
+ * Observe policy changes for the owning executor.
+ * @param ctx - Executor lifecycle and Session events.
*/
constructor(ctx: Context) {
ctx.on('session/event', (session, event) => {
@@ -28,7 +28,7 @@ export class PtcCalls {
ctx.effect(() => async () => {
this.disposed = true
const calls = [...this.calls.values()].flatMap(calls => [...calls])
- for (const call of calls) call.controller.abort(new Error('PTC tool registry disposed'))
+ for (const call of calls) call.controller.abort(new Error('PTC tool executor disposed'))
await Promise.all(calls.map(call => call.done))
}, 'PTC calls')
}
@@ -48,7 +48,7 @@ export class PtcCalls {
await Promise.all(pending.map(call => call.done))
}
signal.throwIfAborted()
- if (this.disposed) throw new Error('PTC tool registry disposed')
+ if (this.disposed) throw new Error('PTC tool executor disposed')
const controller = new AbortController()
const done = Promise.withResolvers()
const call = { mode: mode(), controller, done: done.promise }
diff --git a/packages/core/tool-executor-ptc/src/ptc.ts b/packages/core/tool-executor-ptc/src/ptc.ts
index be45a469f8..899b89dd71 100644
--- a/packages/core/tool-executor-ptc/src/ptc.ts
+++ b/packages/core/tool-executor-ptc/src/ptc.ts
@@ -19,7 +19,7 @@ import type {} from '@deepseek-ai/dsh-user-approval'
import type {} from '@deepseek-ai/dsh-working-directory'
import type {} from '@deepseek-ai/dsh-sandbox-policy'
import { deepFreeze, snapshotJsonValue, type JsonValue } from '@deepseek-ai/dsh-util-values'
-import { defineTool, parameterSchemaSpecToJsonSchema } from '@deepseek-ai/dsh-tools'
+import { defineTool, parameterSchemaSpecToJsonSchema, RUN_CODE_NAME } from '@deepseek-ai/dsh-tools'
import type { ToolExecutionPipeline } from '@deepseek-ai/dsh-tools/pipeline'
import { toolErrorMessage } from '@deepseek-ai/dsh-tools/pipeline'
import { scopeTarget } from '@deepseek-ai/dsh-scope'
@@ -29,8 +29,7 @@ import type { ToolDefinition, ToolExecutionResult, ToolRunContext } from '@deeps
import type {} from './session-types.ts'
/** The model-facing name of the PTC mode tool. */
-export { RUN_CODE_NAME } from '@deepseek-ai/dsh-tools'
-import { RUN_CODE_NAME } from '@deepseek-ai/dsh-tools'
+export { RUN_CODE_NAME }
/** Language-specific tool and code-parameter descriptions. */
interface RunCodeFlavor {
@@ -264,19 +263,6 @@ function resolveSandboxPolicy(ctx: Context, exec: ToolRunContext): SandboxExecut
return policy.resolve(exec.agent === undefined ? {} : { session: exec.agent.session })
}
-/** A failed log-content listener preserves the settled content and cannot fail the dispatch. */
-async function shapeDispatchLog(ctx: Context, dispatch: PtcDispatchLog): Promise {
- try {
- return await ctx.waterfall(
- scopeTarget(ctx.tools, dispatch.agent), 'tools/ptc-dispatch-log', dispatch,
- () => Promise.resolve(dispatch.content),
- )
- } catch (error: unknown) {
- ctx.logger.warn(`tools: ptc-dispatch-log listener failed for ${dispatch.name}: ${toolErrorMessage(error)}; logging the original settled content`)
- return dispatch.content
- }
-}
-
/**
* Build the reserved `run_code` transport outside registered capabilities.
* @param ctx - executor context owning policy listeners and active program cleanup.
@@ -289,6 +275,23 @@ export function createRunCodeTool(
executor: ToolExecutionPipeline,
maxParallel: number,
): ToolDefinition {
+ // Retain services for log settlement after the executor context becomes inactive.
+ const tools = ctx.tools
+ const logger = ctx.logger
+
+ /** A failed log-content listener preserves the settled content and cannot fail the dispatch. */
+ async function shapeDispatchLog(dispatch: PtcDispatchLog): Promise {
+ try {
+ return await ctx.waterfall(
+ scopeTarget(tools, dispatch.agent), 'tools/ptc-dispatch-log', dispatch,
+ () => Promise.resolve(dispatch.content),
+ )
+ } catch (error: unknown) {
+ logger.warn(`tools: ptc-dispatch-log listener failed for ${dispatch.name}: ${toolErrorMessage(error)}; logging the original settled content`)
+ return dispatch.content
+ }
+ }
+
const stateOwners = new WeakMap