dsh-plugin-dev-kb 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.en.md +14 -8
- package/README.md +14 -8
- package/docs/banner.svg +25 -0
- package/kb/INDEX.md +6 -2
- package/kb/README.md +4 -4
- package/kb/extra/AGENTS.md +2 -2
- package/kb/extra/cookbook/adding-a-session-format-version.md +109 -0
- package/kb/extra/cookbook/adding-a-session-format-version.zh.md +109 -0
- package/kb/extra/cookbook/adding-a-vendored-package.md +1 -1
- package/kb/extra/cookbook/adding-a-vendored-package.zh.md +1 -1
- package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.md +1 -1
- package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.zh.md +1 -1
- package/kb/extra/deepseek-llm-api-wire-extensions.md +2 -2
- package/kb/extra/deepseek-llm-api-wire-extensions.zh.md +2 -2
- package/kb/extra/development.md +13 -3
- package/kb/extra/development.zh.md +13 -3
- package/kb/extra/event-producer-consumer.md +33 -31
- package/kb/extra/event-producer-consumer.zh.md +34 -32
- package/kb/extra/i18n/README.md +2 -1
- package/kb/extra/i18n/README.zh.md +3 -2
- package/kb/extra/i18n/translation-prompt.md +1 -1
- package/kb/extra/module-graph.md +62 -24
- package/kb/extra/module-graph.zh.md +62 -24
- package/kb/extra/rescope.md +1 -1
- package/kb/extra/rescope.zh.md +1 -1
- package/kb/extra/session-format-status.md +47 -0
- package/kb/extra/session-format-status.zh.md +47 -0
- package/kb/extra/subsystems/agent-team.md +1 -1
- package/kb/extra/subsystems/agent-team.zh.md +1 -1
- package/kb/extra/subsystems/feedback.md +164 -30
- package/kb/extra/subsystems/feedback.zh.md +164 -30
- package/kb/extra/testing.md +4 -3
- package/kb/extra/testing.zh.md +4 -3
- package/kb/extra/web-styling.md +1 -0
- package/kb/extra/web-styling.zh.md +1 -0
- package/kb/meta/search-index.json +151 -103
- package/kb/meta/site-pages.txt +188 -184
- package/kb/meta/source.json +5 -5
- package/kb/meta/topics.md +2 -2
- package/kb/site/develop/basic/publish.md +1 -1
- package/kb/site/en/develop/basic/publish.md +1 -1
- package/kb/site/en/guide/providers.md +1 -1
- package/kb/site/en/guide/python-sdk.md +19 -3
- package/kb/site/en/reference/agent-lifecycle.md +12 -5
- package/kb/site/en/reference/capability-seams.md +10 -3
- package/kb/site/en/reference/config-catalog.md +173 -42
- package/kb/site/en/reference/cookbook/adding-a-tool.md +1 -1
- package/kb/site/en/reference/cookbook/extension-cookbook.md +1 -1
- package/kb/site/en/reference/index.md +18 -8
- package/kb/site/en/reference/persistence-catalog.md +121 -48
- package/kb/site/en/reference/subsystems/approval.md +1 -1
- package/kb/site/en/reference/subsystems/client-modules.md +9 -0
- package/kb/site/en/reference/subsystems/client-resources.md +94 -0
- package/kb/site/en/reference/subsystems/compaction.md +1 -1
- package/kb/site/en/reference/subsystems/core.md +79 -16
- package/kb/site/en/reference/subsystems/filesystem.md +15 -0
- package/kb/site/en/reference/subsystems/goal.md +37 -1
- package/kb/site/en/reference/subsystems/index.md +2 -0
- package/kb/site/en/reference/subsystems/invariants.md +1 -1
- package/kb/site/en/reference/subsystems/llm-streaming.md +20 -10
- package/kb/site/en/reference/subsystems/lsp.md +1 -1
- package/kb/site/en/reference/subsystems/persistence.md +36 -15
- package/kb/site/en/reference/subsystems/schedule.md +1 -1
- package/kb/site/en/reference/subsystems/scope.md +1 -1
- package/kb/site/en/reference/subsystems/session-reference.md +4 -0
- package/kb/site/en/reference/subsystems/session-telemetry.md +22 -6
- package/kb/site/en/reference/subsystems/session.md +64 -42
- package/kb/site/en/reference/subsystems/shell.md +9 -6
- package/kb/site/en/reference/subsystems/sidebar-right.md +151 -0
- package/kb/site/en/reference/subsystems/slots.md +41 -33
- package/kb/site/en/reference/subsystems/spill.md +13 -6
- package/kb/site/en/reference/subsystems/subagent.md +20 -13
- package/kb/site/en/reference/subsystems/subprocess.md +25 -26
- package/kb/site/en/reference/subsystems/system-prompt.md +3 -1
- package/kb/site/en/reference/subsystems/token-meter.md +2 -1
- package/kb/site/en/reference/subsystems/tools.md +5 -5
- package/kb/site/en/reference/subsystems/workspace.md +80 -1
- package/kb/site/en/reference/tool-catalog.md +46 -2
- package/kb/site/en/reference/tool-execution-pipeline.md +2 -2
- package/kb/site/guide/providers.md +1 -1
- package/kb/site/guide/python-sdk.md +19 -3
- package/kb/site/reference/agent-lifecycle.md +12 -5
- package/kb/site/reference/capability-seams.md +10 -3
- package/kb/site/reference/config-catalog.md +173 -42
- package/kb/site/reference/cookbook/adding-a-tool.md +1 -1
- package/kb/site/reference/cookbook/extension-cookbook.md +1 -1
- package/kb/site/reference/index.md +18 -8
- package/kb/site/reference/persistence-catalog.md +127 -54
- package/kb/site/reference/subsystems/approval.md +1 -1
- package/kb/site/reference/subsystems/client-modules.md +9 -0
- package/kb/site/reference/subsystems/client-resources.md +94 -0
- package/kb/site/reference/subsystems/compaction.md +1 -1
- package/kb/site/reference/subsystems/core.md +79 -16
- package/kb/site/reference/subsystems/filesystem.md +15 -0
- package/kb/site/reference/subsystems/goal.md +37 -1
- package/kb/site/reference/subsystems/index.md +14 -12
- package/kb/site/reference/subsystems/invariants.md +1 -1
- package/kb/site/reference/subsystems/llm-streaming.md +20 -10
- package/kb/site/reference/subsystems/lsp.md +1 -1
- package/kb/site/reference/subsystems/persistence.md +36 -15
- package/kb/site/reference/subsystems/schedule.md +1 -1
- package/kb/site/reference/subsystems/scope.md +1 -1
- package/kb/site/reference/subsystems/session-reference.md +4 -0
- package/kb/site/reference/subsystems/session-telemetry.md +22 -6
- package/kb/site/reference/subsystems/session.md +64 -42
- package/kb/site/reference/subsystems/shell.md +9 -6
- package/kb/site/reference/subsystems/sidebar-right.md +151 -0
- package/kb/site/reference/subsystems/slots.md +41 -33
- package/kb/site/reference/subsystems/spill.md +13 -6
- package/kb/site/reference/subsystems/subagent.md +20 -13
- package/kb/site/reference/subsystems/subprocess.md +25 -26
- package/kb/site/reference/subsystems/system-prompt.md +3 -1
- package/kb/site/reference/subsystems/token-meter.md +2 -1
- package/kb/site/reference/subsystems/tools.md +5 -5
- package/kb/site/reference/subsystems/workspace.md +80 -1
- package/kb/site/reference/tool-catalog.md +46 -2
- package/kb/site/reference/tool-execution-pipeline.md +2 -2
- package/lib/index.js +25 -44
- package/package.json +3 -2
- package/skills/dsh-plugin-dev-kb.md +3 -3
|
@@ -85,6 +85,7 @@ The shipped adapters add these standard props. They are available according to t
|
|
|
85
85
|
|---|---|---|
|
|
86
86
|
| every scope | `useSessions`, `useSessionPendingInteraction` | `ui-session` |
|
|
87
87
|
| every scope | `useWorkspaces` | `ui-workspace` |
|
|
88
|
+
| every scope | `usePanelInfo` | `ui-layout` |
|
|
88
89
|
| `session` | `sessionId`, `useSession`, `useProjection` | `ui-session` |
|
|
89
90
|
| `session-maybe` | optional `sessionId`, `useSession`, `useProjection` results | `ui-session` |
|
|
90
91
|
| `session` | `useConversation`, `useInput`, `inputActions` | `ui-conversation` |
|
|
@@ -115,6 +116,7 @@ root
|
|
|
115
116
|
├─ sidebar
|
|
116
117
|
│ ├─ sidebar.brand.mark
|
|
117
118
|
│ ├─ sidebar.brand.name
|
|
119
|
+
│ ├─ sidebar.panellist
|
|
118
120
|
│ ├─ sidebar.footer.action
|
|
119
121
|
│ ├─ sidebar.workspaces
|
|
120
122
|
│ │ └─ sidebar.workspaces.directoryFlow
|
|
@@ -130,39 +132,45 @@ root
|
|
|
130
132
|
│ ├─ settings.models.footer
|
|
131
133
|
│ └─ settings.plugins.tab
|
|
132
134
|
│ └─ settings.plugin.item
|
|
133
|
-
├─
|
|
134
|
-
│
|
|
135
|
-
│
|
|
136
|
-
│
|
|
137
|
-
│
|
|
138
|
-
│
|
|
139
|
-
│
|
|
140
|
-
│
|
|
141
|
-
│
|
|
142
|
-
│
|
|
143
|
-
│
|
|
144
|
-
│
|
|
145
|
-
│
|
|
146
|
-
│
|
|
147
|
-
│
|
|
148
|
-
│
|
|
149
|
-
│ ├─ conversation.
|
|
150
|
-
│
|
|
151
|
-
│
|
|
152
|
-
│
|
|
153
|
-
│
|
|
154
|
-
│
|
|
155
|
-
│ ├─ conversation.input.
|
|
156
|
-
│
|
|
157
|
-
│
|
|
158
|
-
│
|
|
159
|
-
│
|
|
160
|
-
│
|
|
161
|
-
│
|
|
162
|
-
│
|
|
163
|
-
│
|
|
164
|
-
|
|
165
|
-
│
|
|
135
|
+
├─ main
|
|
136
|
+
│ └─ main.conversation
|
|
137
|
+
│ ├─ conversation.session
|
|
138
|
+
│ │ └─ conversation.view
|
|
139
|
+
│ │ ├─ conversation.chat.node
|
|
140
|
+
│ │ │ ├─ conversation.chat.assistant-actions
|
|
141
|
+
│ │ │ ├─ conversation.chat.commandview
|
|
142
|
+
│ │ │ ├─ conversation.chat.turnTail
|
|
143
|
+
│ │ │ └─ tool.call.toolview
|
|
144
|
+
│ │ │ ├─ tool.call.images
|
|
145
|
+
│ │ │ └─ tool.view.cordis
|
|
146
|
+
│ │ ├─ conversation.message.images
|
|
147
|
+
│ │ └─ conversation.trajectory.images
|
|
148
|
+
│ ├─ conversation.session.header
|
|
149
|
+
│ │ ├─ conversation.session.header.lineage
|
|
150
|
+
│ │ ├─ conversation.session.header.actions
|
|
151
|
+
│ │ ├─ conversation.session.header.utilities
|
|
152
|
+
│ │ └─ conversation.session.header.corner
|
|
153
|
+
│ ├─ conversation.composer
|
|
154
|
+
│ │ └─ conversation.approval.detail
|
|
155
|
+
│ ├─ conversation.composer.bar
|
|
156
|
+
│ │ ├─ conversation.input.attachments
|
|
157
|
+
│ │ ├─ conversation.input.plan
|
|
158
|
+
│ │ └─ conversation.input.model
|
|
159
|
+
│ ├─ conversation.input.overlay
|
|
160
|
+
│ ├─ conversation.input.dock
|
|
161
|
+
│ ├─ conversation.composer.dock
|
|
162
|
+
│ ├─ conversation.input.left
|
|
163
|
+
│ ├─ conversation.input.right
|
|
164
|
+
│ ├─ conversation.hero.brand.mark
|
|
165
|
+
│ ├─ conversation.hero.workspace
|
|
166
|
+
│ │ └─ conversation.hero.workspace.directoryFlow
|
|
167
|
+
│ └─ conversation.hero.agentPreset
|
|
168
|
+
├─ rightbar
|
|
169
|
+
│ └─ rightbar.session
|
|
170
|
+
│ ├─ sidebar.right.pane.tab
|
|
171
|
+
│ │ └─ sidebar.right.tab.guide
|
|
172
|
+
│ ├─ sidebar.right.pane.tab.title
|
|
173
|
+
│ └─ sidebar.right.tab.menu.item
|
|
166
174
|
└─ shell.overlay
|
|
167
175
|
```
|
|
168
176
|
|
|
@@ -5,13 +5,13 @@ outline: [2,3]
|
|
|
5
5
|
|
|
6
6
|
# Spill Storage
|
|
7
7
|
|
|
8
|
-
The spill storage
|
|
8
|
+
The spill storage [capability seam](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md) persists caller-provided text and returns a model-facing locator with retrieval guidance. Its Service Definition is [dsh-spill](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/spill/spill) (`ctx.spillStore`), and its local Service Provider is [dsh-spill-local](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/spill/spill-local). Consumers include the [tool-result policy](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/spill/spill-policy) and [session references](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/context/session-reference/README.md). Spill is optional, not part of the [agent-loop spine](./core.md); consumers own preview and spill decisions, while storage saves the supplied text verbatim.
|
|
9
9
|
|
|
10
10
|
Source: [`packages/spill/spill/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/spill/spill/src/types.ts)
|
|
11
11
|
|
|
12
12
|
## The save request
|
|
13
13
|
|
|
14
|
-
`saveText` is the sole service operation: persist `content` verbatim, return an opaque locator, a backend-supplied retrieval hint, and the exact byte count. The request carries the save-time storage namespace (`owner`),
|
|
14
|
+
`saveText` is the sole service operation: persist `content` verbatim, return an opaque locator, a backend-supplied retrieval hint, and the exact byte count. The request carries the save-time storage namespace (`owner`), descriptive producer provenance (`source`, never access control), and a `suggestedName` the backend may use as a naming hint, not a path. Tool provenance identifies the actual tool call; session-reference provenance identifies the captured source session, while its owner is the target session receiving the context.
|
|
15
15
|
|
|
16
16
|
```ts type-equiv
|
|
17
17
|
/** One request to persist text to a spill artifact. */
|
|
@@ -45,17 +45,24 @@ A retention-period cleanup may expire old locators with other old session artifa
|
|
|
45
45
|
|
|
46
46
|
```ts type-equiv
|
|
47
47
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
48
|
+
* Producer of a spilled artifact. Tool results carry their model-issued call id;
|
|
49
|
+
* session references identify the captured source session instead. Descriptive
|
|
50
|
+
* provenance only, never access control.
|
|
51
51
|
*/
|
|
52
|
-
|
|
52
|
+
type SpillSource = {
|
|
53
|
+
kind: 'tool'
|
|
53
54
|
/** The tool whose result was spilled (e.g. `web_fetch`). */
|
|
54
55
|
toolName: string
|
|
55
56
|
/** The model-issued call id the result belongs to. */
|
|
56
57
|
callId: ToolCallId
|
|
57
58
|
/** A short human label for the artifact (e.g. `result`). */
|
|
58
59
|
label: string
|
|
60
|
+
} | {
|
|
61
|
+
kind: 'session-reference'
|
|
62
|
+
/** Session whose projected conversation was captured. */
|
|
63
|
+
sessionId: SessionId
|
|
64
|
+
/** Host-provided label for the referenced session. */
|
|
65
|
+
label: string
|
|
59
66
|
}
|
|
60
67
|
```
|
|
61
68
|
|
|
@@ -7,10 +7,12 @@ outline: [2,3]
|
|
|
7
7
|
|
|
8
8
|
The subagent seam lets an agent delegate work to a child agent. Like [bash](./shell.md), it is **one optional capability**, not part of the agent loop, so its types live here rather than in [core.md](./core.md). It differs from the other capability seams because **multiple provider implementations coexist** in one context, registered by name (`ctx.subagents`), while bash allows only one executor. Its registry follows the [LLM adapter registry](./llm-streaming.md), not the single-service bash executor.
|
|
9
9
|
|
|
10
|
-
Service Definition: [dsh-subagent](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/subagent/subagent) (`ctx.subagents` + the vocabulary below). Service Providers are sibling packages (`dsh-subagent-spawn-in-process`, `dsh-subagent-fork-in-process`, `dsh-subagent-acp`, `dsh-subagent-codex`, `dsh-subagent-claude-code`, `dsh-subagent-dsh-sdk`); the model-facing Consumers are [dsh-tool-subagent](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/subagent/tool-subagent) (per-provider delegation) and [dsh-tool-subagent-control](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/subagent/tool-subagent-control) (the optional global `send_message`, `interrupt_agent`, and `list_agents` controls). The same `ctx.subagents` service owns continuable-child orchestration through an internal activation manager and read-only child and descendant discovery straight from the session store and optional session persistence. Product-provider rationale lives in [the Codex and Claude Code Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.md); common-seam rationale lives in [the subagent Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md), [the continuable subagents Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-07-28-continuable-subagent-conversations.md), [the adjacent-Agent messaging Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.md)
|
|
10
|
+
Service Definition: [dsh-subagent](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/subagent/subagent) (`ctx.subagents` + the vocabulary below). Service Providers are sibling packages (`dsh-subagent-spawn-in-process`, `dsh-subagent-fork-in-process`, `dsh-subagent-acp`, `dsh-subagent-codex`, `dsh-subagent-claude-code`, `dsh-subagent-dsh-sdk`); the model-facing Consumers are [dsh-tool-subagent](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/subagent/tool-subagent) (per-provider delegation) and [dsh-tool-subagent-control](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/subagent/tool-subagent-control) (the optional global `send_message`, `interrupt_agent`, and `list_agents` controls). The same `ctx.subagents` service owns continuable-child orchestration through an internal activation manager and read-only child and descendant discovery straight from the session store and optional session persistence. Product-provider rationale lives in [the Codex and Claude Code Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.md); common-seam rationale lives in [the subagent Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md), [the continuable subagents Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-07-28-continuable-subagent-conversations.md), and [the adjacent-Agent messaging Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.md); [the archived list-identity-projection record](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/archived/architecture/2026-08-06-subagent-list-identity-projection.md) documents the original list-identity decision.
|
|
11
11
|
|
|
12
12
|
Sources: [`packages/subagent/subagent/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subagent/subagent/src/types.ts), [`packages/subagent/subagent/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subagent/subagent/src/index.ts), and [`packages/subagent/subagent/src/continuation.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subagent/subagent/src/continuation.ts)
|
|
13
13
|
|
|
14
|
+
The `subagentCatalog` projection exposes `SubagentCatalogEntry[]` in parent event order through Session observations and client snapshots. Each entry contains the child id, creation time, mode, and mode-dependent label; fork-inherited catalog facts are excluded. [The subagent package](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subagent/subagent/README.md) owns catalog creation and persistence semantics.
|
|
15
|
+
|
|
14
16
|
## Two kinds of capability, discovered two ways
|
|
15
17
|
|
|
16
18
|
A provider advertises its **start-time** features on a static descriptor the service checks BEFORE a one-shot run exists; a request that needs one the provider lacks is rejected loud (`SubagentError('UNSUPPORTED_CAPABILITY')`), never accepted-then-ignored. Those flags describe only the one-shot [`start()`](#the-provider-contract-subagentprovider) path, where the provider composes the child. **Continuable** children are composed by the continuation manager itself, so they are gated by one optional method whose presence IS the capability, with TS narrowing as the discovery mechanism: [`SubagentProvider.prepareContinuable`](#the-provider-contract-subagentprovider).
|
|
@@ -99,7 +101,7 @@ interface SubagentStartRequest {
|
|
|
99
101
|
/**
|
|
100
102
|
* Optional per-child persona. Requires {@link SubagentCapabilities.persona};
|
|
101
103
|
* rejected at start otherwise. In-process backends register it as a scoped
|
|
102
|
-
* `deployment:persona` section on the child, SHADOWING the deployment's
|
|
104
|
+
* `deployment:persona-prefix` section on the child, SHADOWING the deployment's
|
|
103
105
|
* persona for this child alone — same template semantics as the deployment
|
|
104
106
|
* persona (strict `{{…}}` interpolation against the registered variables).
|
|
105
107
|
*/
|
|
@@ -144,13 +146,15 @@ persisted Session
|
|
|
144
146
|
| `waiting` | wake and steer the same Activation |
|
|
145
147
|
| no Activation | cold-resume a new Activation, then steer it |
|
|
146
148
|
|
|
147
|
-
`running` means the Agent has an active
|
|
149
|
+
`running` means the Agent has an active driver or maintenance task; `waiting` means no Agent activity is active but its Inbox is nonempty or it owns at least one child Activation that has not completed disposal; `settled` means no Agent activity is active, the Inbox is empty, and every owned child is disposed, at which point the manager disposes the [`AgentHandle`](./core.md#creation-and-ownership) and removes the Activation. The manager derives these internal conditions from `Agent.whenIdle()`, `Agent.inbox.hasPending`, the owned-child set, and an Activation generation that invalidates stale observations, rather than maintaining a second execution state machine. After the final Session flush, the child-lock decision uses the synchronous task entry of `Agent.runMaintenance()` to claim the idle phase and close admission in the same JavaScript turn. This conservative rule does not distinguish delivery modes: context parked by `Agent.inject()` can keep an idle Activation and its live ancestors resident until a waking delivery claims it, a queue mutation removes it, or manager teardown discards it.
|
|
148
150
|
|
|
149
|
-
The Agent inbox is the only queue. Every Agent message uses `Agent.steer()`: an idle target starts a turn, while a running target claims it at the nearest step boundary. Successful delivery returns the accepted `MessageId`; the existing `agent/inbox/inserted`, `agent/inbox/claimed`, and `agent/inbox/discarded` events remain the message-lifecycle observations, and the continuation layer defines no
|
|
151
|
+
The Agent inbox is the only queue. Every Agent message uses `Agent.steer()`: an idle target starts a turn, while a running target claims it at the nearest step boundary. The browser `subagent.prompt` Remote separately carries `delivery: 'queue' | 'steer'` through the same internal admission path; Queue opens a later FIFO turn, while Steer retains the Agent loop's best-effort nearest-step behavior and the message's human source. Successful delivery returns the accepted `MessageId`; the existing `agent/inbox/inserted`, `agent/inbox/claimed`, and `agent/inbox/discarded` events remain the message-lifecycle observations, and the continuation layer defines no second queue.
|
|
150
152
|
|
|
151
153
|
Authority comes from the exact live sender. Parent-to-child delivery requires the target's `SessionHeader.parentSession` to name the sender; child-to-parent delivery requires the sender's resident Activation to name the target. Siblings, ancestors beyond one edge, self-targets, stale Agent objects, and one-shot children are rejected. Each accepted message is framed as `Agent <sender-id> sent a message:` and records `AgentMessageSource`; provenance records the sender but grants no authority.
|
|
152
154
|
|
|
153
|
-
For `startContinuable()
|
|
155
|
+
For `startContinuable()`, `sendMessage()`, and browser prompt delivery, the caller signal owns lookup, materialization, and admission only until inbox acceptance. Afterwards the manager owns the Activation independently: later caller cancellation neither cancels the accepted turn nor disposes the child. The public subagent service exposes no caller-selected Agent-message scheduling; browser human Queue and Steer remain internal adapter choices.
|
|
156
|
+
|
|
157
|
+
Live queue occurrence mutation remains in the Session domain. `session.updateQueue` admits ordinary Edit, Remove, and QueueDock Steer for a live subagent-owned Agent only when its current projected identity is continuable and its descriptor sequence is in that child's own non-seed suffix. The identity projection folds descriptors last-wins so a child descriptor supersedes descriptors retained from fork lineage; the own-suffix sequence check prevents a seed-only ancestor identity from authorizing mutation. One-shot, missing, unknown, corrupt, or cold children remain rejected, and queue mutation never cold-resumes a child. The target Session id is the human authority for these mutations, including pending `nextStep` steering or injected context. Steer requires a queued `MessageId` and an Agent that reports running when the command begins; cancellation after admission uses the Agent's accepted waking `nextTurn` fallback. Edit rewrites content under the same `MessageId`, and both Edit and Steer complete their Inbox work synchronously, so settlement observes only the final state. `agent/inbox/claimed` and `agent/inbox/discarded` wake the watcher to re-read whether any pending occurrence remains; this lets direct Agent delivery resume parked work and lets removing the last parked occurrence settle an idle child. The [human inbox-control Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-08-27-continuable-subagent-human-inbox-control.md) owns these semantics.
|
|
154
158
|
|
|
155
159
|
`SubagentRuntime.interrupt(targetSessionId, authority)` is the one public stop: it authorizes synchronously, issues `Agent.cancel(cause, { keepInbox: true })` on the live target, and returns without awaiting quiescence. The Activation, its unclaimed pending inbox work, and published descendants are untouched; work already claimed into the interrupted turn is not requeued. Once the interrupted driver is idle, a waking send resumes the parked FIFO queue. An absent target — unknown, one-shot, or already settled — and a manager-less composition are accepted no-ops. For a live target, a mismatched parent address or caller outside its live ancestry rejects with `UNAUTHORIZED`; stale ancestor objects and self-targeting ancestor requests reject before target lookup.
|
|
156
160
|
|
|
@@ -165,7 +169,7 @@ type SubagentInterruptAuthority =
|
|
|
165
169
|
| { readonly kind: 'ancestor'; readonly agent: Agent }
|
|
166
170
|
```
|
|
167
171
|
|
|
168
|
-
Every Activation owns its `AgentHandle` and an `ownedChildren: Set<SessionId>`; because one Session has at most one live Activation, the child Session id identifies the live child without another runtime-incarnation reference. Starting a child or submitting parent-originated work registers the child in a continuation-managed parent's set before the child can run, and that parent cannot settle while the set is non-empty. A top-level or other non-continuation Agent has no Activation and stays outside the waiting graph. Child release happens only after the child Agent is
|
|
172
|
+
Every Activation owns its `AgentHandle` and an `ownedChildren: Set<SessionId>`; because one Session has at most one live Activation, the child Session id identifies the live child without another runtime-incarnation reference. Starting a child or submitting parent-originated work registers the child in a continuation-managed parent's set before the child can run, and that parent cannot settle while the set is non-empty. A top-level or other non-continuation Agent has no Activation and stays outside the waiting graph. Child release happens only after the child has no active Agent work, its Inbox is empty, every child of that child is disposed, the best-effort final session flush settles, and the child's `AgentHandle` completes disposal.
|
|
169
173
|
|
|
170
174
|
Final settlement awaits `ctx.sessions.flush(session)` but ignores its participation boolean because an arbitrary listener cannot prove that a persistence backend stored the state. Rejection is logged without failing the Activation, and the manager still disposes the handle and releases ownership; the persisted child state may then be missing or stale on a later resume. Manager unload invokes an internal manager-wide drain that closes admission and disposes every live forest; `drainContinuableDescendants(parents)` closes admission only below exact live host-owned Agents and disposes their continuable descendants while unrelated forests remain live. Both await already-admitted materializations in their scope, propagate cancellation top-down, release handles child-first, and await every selected branch despite individual failures. Durable child Sessions survive that process-local teardown.
|
|
171
175
|
|
|
@@ -198,7 +202,7 @@ interface ContinuableStart {
|
|
|
198
202
|
}
|
|
199
203
|
```
|
|
200
204
|
|
|
201
|
-
When a resident Activation settles, the manager delivers one notice to the child's durable direct parent describing how that epoch ended and carrying its final assistant content. That delivery is unconditional for every child whose id a caller received, happens before the ownership release that would let the parent be judged settled, and reaches a resident parent through the same waking
|
|
205
|
+
When a resident Activation settles, the manager delivers one notice to the child's durable direct parent describing how that epoch ended and carrying its final assistant content. That delivery is unconditional for every child whose id a caller received, happens before the ownership release that would let the parent be judged settled, and reaches a resident parent through the same waking Agent delivery as an Agent message. A parent whose own lineage is already tearing down receives it without a wake, because waking an idle Agent starts a turn rather than queueing work. Its provenance is a distinct kind so a transcript never presents a runtime account as something the child wrote.
|
|
202
206
|
|
|
203
207
|
```ts type-equiv
|
|
204
208
|
/**
|
|
@@ -265,7 +269,7 @@ A local one-shot provider appends the descriptor inside the child's initial turn
|
|
|
265
269
|
|
|
266
270
|
## Durable enumeration: `listChildren()`, `listDescendants()`, and their entries
|
|
267
271
|
|
|
268
|
-
`SubagentRuntime.listChildren(parentSessionId)` enumerates the parent's direct session-backed subagents from the live-preferred merge of `ctx.sessions` and the session-query engine's `listSessions()` — no Agent is loaded or resumed. Candidates are the direct children whose durable header carries `origin: 'subagent'`; the marker classifies enumeration and coarse generic-route denial but cannot establish a valid descriptor, resumability, or authorization — the projection fold owns identity, and the Activation contract owns resume. Each row's `mode`/`label` is the registered `subagent` projection unit's value, served through a three-rung ladder: the registry's watermark cache for a live child (zero log reads); the optional projection checkpoint cache for a cold one (`cachedSnapshot` — an identity passing the own-suffix seq gate is final, because an own descriptor is immutable once appended); otherwise one `query.observeSession()` cold observation folded through the registry (bounded concurrency, recomputed per listing). The cache is a pure optional accelerator: absent, serving the `null` sentinel or missing the key, failing the seq gate, or faulting, it falls silently through to the authoritative refold. The fold is `subagent/descriptor` last-wins with no failure channel: the child's own descriptor overrides a fork-seeded ancestor's, and a malformed or unknown-version payload folds to a serializable `null` sentinel, treated as no value. The result is one `SubagentListEntry[]` in `createdAt`-then-id order: a served identity yields a `child` entry with `mode: 'one-shot' | 'continuable'` and `activity: 'running' | 'inactive'`; continuable entries always carry `label`, while one-shot entries carry it only when the start caller supplied presentation metadata. A settled candidate whose fold served no identity yields a `corrupt` diagnostic — missing, malformed, and unknown-version descriptors deliberately undistinguished (`unsupported` remains in the type but is never produced); a running candidate without an identity is omitted (the creation window before its descriptor lands); a failed cold inspection yields one `unavailable` diagnostic retried on the next listing, so one damaged sibling cannot hide healthy children. `hasChildren` marks a direct descendant with durable subagent origin, read from the same merged material. Activity snapshots only whether the logical record is live in `ctx.sessions`, not outcome or resumability. Absent persistence, enumeration is live-only rather than an error — a cold child cannot be resumed then either. `listChildren()` throws `SubagentError` with code `SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE` when the `ctx.sessionProjections` registry is absent and `SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE` when the session store is, both checked before any read so a deployment with zero children still fails deterministically; the list tool requires `ctx.subagents` and `ctx.agents` at plugin load. A service consumer such as a UI can display both modes and choose an unlabeled one-shot fallback, while the model-facing `list_agents` adapter (the separately loadable `/list-agents` plugin of [dsh-tool-subagent-control](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/subagent/tool-subagent-control)) keeps only continuable entries and refines status through the live Agent registry into its own `running`/`idle`/`ready` vocabulary, whose `ready` names a storage-only child as resumable rather than terminal. Listing does not consult the continuation manager's Activation map, Agent registry, or provider availability; `send_message` remains the authoritative delivery-time operation, and a listed running continuable child may still reject delivery as an ownership conflict. The
|
|
272
|
+
`SubagentRuntime.listChildren(parentSessionId)` enumerates the parent's direct session-backed subagents from the live-preferred merge of `ctx.sessions` and the session-query engine's `listSessions()` — no Agent is loaded or resumed. Candidates are the direct children whose durable header carries `origin: 'subagent'`; the marker classifies enumeration and coarse generic-route denial but cannot establish a valid descriptor, resumability, or authorization — the projection fold owns identity, and the Activation contract owns resume. Each row's `mode`/`label` is the registered `subagent` projection unit's value, served through a three-rung ladder: the registry's watermark cache for a live child (zero log reads); the optional projection checkpoint cache for a cold one (`cachedSnapshot` — an identity passing the own-suffix seq gate is final, because an own descriptor is immutable once appended); otherwise one `query.observeSession()` cold observation folded through the registry (bounded concurrency, recomputed per listing). The cache is a pure optional accelerator: absent, serving the `null` sentinel or missing the key, failing the seq gate, or faulting, it falls silently through to the authoritative refold. The fold is `subagent/descriptor` last-wins with no failure channel: the child's own descriptor overrides a fork-seeded ancestor's, and a malformed or unknown-version payload folds to a serializable `null` sentinel, treated as no value. The result is one `SubagentListEntry[]` in `createdAt`-then-id order: a served identity yields a `child` entry with `mode: 'one-shot' | 'continuable'` and `activity: 'running' | 'inactive'`; continuable entries always carry `label`, while one-shot entries carry it only when the start caller supplied presentation metadata. A settled candidate whose fold served no identity yields a `corrupt` diagnostic — missing, malformed, and unknown-version descriptors deliberately undistinguished (`unsupported` remains in the type but is never produced); a running candidate without an identity is omitted (the creation window before its descriptor lands); a failed cold inspection yields one `unavailable` diagnostic retried on the next listing, so one damaged sibling cannot hide healthy children. `hasChildren` marks a direct descendant with durable subagent origin, read from the same merged material. Activity snapshots only whether the logical record is live in `ctx.sessions`, not outcome or resumability. Absent persistence, enumeration is live-only rather than an error — a cold child cannot be resumed then either. `listChildren()` throws `SubagentError` with code `SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE` when the `ctx.sessionProjections` registry is absent and `SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE` when the session store is, both checked before any read so a deployment with zero children still fails deterministically; the list tool requires `ctx.subagents` and `ctx.agents` at plugin load. A service consumer such as a UI can display both modes and choose an unlabeled one-shot fallback, while the model-facing `list_agents` adapter (the separately loadable `/list-agents` plugin of [dsh-tool-subagent-control](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/subagent/tool-subagent-control)) keeps only continuable entries and refines status through the live Agent registry into its own `running`/`idle`/`ready` vocabulary, whose `ready` names a storage-only child as resumable rather than terminal. Listing does not consult the continuation manager's Activation map, Agent registry, or provider availability; `send_message` remains the authoritative delivery-time operation, and a listed running continuable child may still reject delivery as an ownership conflict. [The archived list-identity-projection record](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/archived/architecture/2026-08-06-subagent-list-identity-projection.md) documents the original read-path decision.
|
|
269
273
|
|
|
270
274
|
`SubagentRuntime.listDescendants(rootSessionId)` applies the same live-preferred corpus and projection-backed interpretation to the root's complete descendant tree in stable pre-order. Ordinary sessions and one-shot children remain traversal nodes, so continuable descendants below them are discovered; only `origin: 'subagent'` candidates produce rows. Each returned child or diagnostic adds its position from the enumerated durable header, while a cold inspection revalidates that complete lifecycle before serving identity:
|
|
271
275
|
|
|
@@ -472,11 +476,11 @@ Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnp
|
|
|
472
476
|
|
|
473
477
|
### `ctx.subagentModelSelection` — `SubagentModelSelectionConfig`
|
|
474
478
|
|
|
475
|
-
Singleton settings owner read
|
|
479
|
+
Singleton settings owner read when delegation tools are composed for a Session.
|
|
476
480
|
|
|
477
481
|
```ts cordis-catalog
|
|
478
482
|
/**
|
|
479
|
-
* Read a detached selection preference for the next eligible
|
|
483
|
+
* Read a detached selection preference for the next eligible Session composition.
|
|
480
484
|
* @returns the enabled state and exact allowed routes.
|
|
481
485
|
*/
|
|
482
486
|
current(): SubagentModelSelectionSettings
|
|
@@ -614,11 +618,12 @@ listDescendants(rootSessionId: SessionId, signal?: AbortSignal): Promise<Subagen
|
|
|
614
618
|
* Deliver one browser-authored message to a continuable child through the
|
|
615
619
|
* exact live direct parent, retaining the caller-minted request identity and
|
|
616
620
|
* validated browser zone on the accepted message. Success identifies the
|
|
617
|
-
* message the child's
|
|
618
|
-
*
|
|
621
|
+
* message the child's inbox accepted; later execution is independent of this
|
|
622
|
+
* call. Queue delivery targets a later turn; steer delivery targets the
|
|
623
|
+
* nearest step and retains the Agent loop's best-effort fallback semantics.
|
|
619
624
|
* Image parts are admitted and persisted through the attachment store
|
|
620
625
|
* before delivery, and the child's model must accept image input.
|
|
621
|
-
* @param request - durable address, minted identity, content, and optional browser zone.
|
|
626
|
+
* @param request - durable address, delivery, minted identity, content, and optional browser zone.
|
|
622
627
|
* @param signal - carrier cancellation, owning the call until inbox acceptance.
|
|
623
628
|
* @returns the accepted message's inbox identity.
|
|
624
629
|
* @throws {RemoteError} `gateway/bad-request`, `subagent/attachment-invalid`,
|
|
@@ -672,6 +677,8 @@ list(): string[]
|
|
|
672
677
|
* fulfills; a rejection therefore has no run for the caller to dispose and
|
|
673
678
|
* emits no run lifecycle events. Post-publication turn and infrastructure
|
|
674
679
|
* failures settle through the returned run.
|
|
680
|
+
* A catalog append failure disposes the run and handles its result rejection;
|
|
681
|
+
* the caller receives the catalog error even if disposal also fails.
|
|
675
682
|
* @param name - the provider to use.
|
|
676
683
|
* @param request - child label, prompt, parent, signal, and optional capabilities.
|
|
677
684
|
* @returns the published holder-owned run.
|
|
@@ -109,14 +109,15 @@ interface SubprocessSpawnSpec {
|
|
|
109
109
|
stdio: SubprocessStdio
|
|
110
110
|
/**
|
|
111
111
|
* Positive finite grace period in milliseconds, no greater than
|
|
112
|
-
* `MAX_TIMER_DELAY_MS`,
|
|
113
|
-
* and for draining still-open collected pipes after the process exits
|
|
114
|
-
* inherited descriptor held by a
|
|
115
|
-
*
|
|
112
|
+
* `MAX_TIMER_DELAY_MS`, available to the provider's termination procedure
|
|
113
|
+
* and used for draining still-open collected pipes after the process exits
|
|
114
|
+
* (an inherited descriptor held by a survivor cannot hold the outcome open
|
|
115
|
+
* indefinitely). Providers document whether range termination is staged or
|
|
116
|
+
* immediate.
|
|
116
117
|
*/
|
|
117
118
|
graceMs: number
|
|
118
119
|
/**
|
|
119
|
-
* Abort signal — starts the terminate escalation on the
|
|
120
|
+
* Abort signal — starts the terminate escalation on the managed range when
|
|
120
121
|
* it fires. The caller owns deadlines and cause classification; this seam
|
|
121
122
|
* only reacts to the abort.
|
|
122
123
|
*/
|
|
@@ -132,23 +133,20 @@ interface SubprocessSpawnSpec {
|
|
|
132
133
|
}
|
|
133
134
|
```
|
|
134
135
|
|
|
135
|
-
## Handles: streams, readers, and
|
|
136
|
+
## Handles: streams, readers, and managed-range termination
|
|
136
137
|
|
|
137
|
-
A spawn returns a live handle
|
|
138
|
+
A spawn returns a live handle synchronously while target and managed-range identities remain provider-private. Collect-mode readers take whole-stream byte offsets and never consume, so independent readers cannot steal one another's deltas; piped streams belong to the caller. `terminate()` starts the provider's documented procedure, and `waitForExit()` observes the same provider-managed range; staged providers may use `graceMs`, while immediate providers do not delay. Consumers can build their own teardown ladders over those two operations (the ACP backend's stdin-EOF-first `disposeAcpChild` is the template).
|
|
138
139
|
|
|
139
140
|
```ts type-equiv
|
|
140
141
|
/**
|
|
141
|
-
* A live
|
|
142
|
+
* A live subprocess and its provider-managed process range. Collected output
|
|
142
143
|
* remains readable after exit; piped streams belong to the caller.
|
|
143
144
|
*
|
|
144
|
-
* Termination
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
* the handle unnoticed.
|
|
145
|
+
* Termination and {@link SubprocessHandle.waitForExit} use the same managed
|
|
146
|
+
* range. Each provider documents the range it can observe and its signalling
|
|
147
|
+
* and observation limits.
|
|
148
148
|
*/
|
|
149
149
|
interface SubprocessHandle {
|
|
150
|
-
/** Process id (tree root); -1 when the spawn itself failed. */
|
|
151
|
-
readonly pid: number
|
|
152
150
|
/** The child's stdin, present iff spawned with `stdin: 'pipe'`. */
|
|
153
151
|
readonly stdin: Writable | undefined
|
|
154
152
|
/** The child's raw stdout, present iff spawned with `stdout: 'pipe'`. */
|
|
@@ -157,20 +155,20 @@ interface SubprocessHandle {
|
|
|
157
155
|
readonly stderr: Readable | undefined
|
|
158
156
|
/** Offset-based readers for collect-mode streams (also readable after exit). */
|
|
159
157
|
readonly collected: SubprocessCollectedOutputs
|
|
160
|
-
/** Resolves
|
|
158
|
+
/** Resolves with spawned-command exit facts; rejects for spawn or provider failures. */
|
|
161
159
|
readonly done: Promise<SubprocessOutcome>
|
|
162
160
|
/**
|
|
163
|
-
* Begin the
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* and also triggered by the spec's abort signal.
|
|
161
|
+
* Begin the provider's documented termination procedure on the managed range
|
|
162
|
+
* — the seam's only termination verb. Idempotent, a no-op once that range is
|
|
163
|
+
* gone, and also triggered by the spec's abort signal.
|
|
167
164
|
*/
|
|
168
165
|
terminate(): void
|
|
169
166
|
/**
|
|
170
|
-
* Wait until the
|
|
171
|
-
*
|
|
167
|
+
* Wait until the same managed range is empty — not just until the spawned
|
|
168
|
+
* command reports its outcome, so surviving work remains observable.
|
|
172
169
|
* @param signal - optional bound for the wait.
|
|
173
|
-
* @returns `true` when the
|
|
170
|
+
* @returns `true` when the managed range is empty, `false` when the signal aborted first.
|
|
171
|
+
* @throws when the selected provider can no longer observe its managed range.
|
|
174
172
|
*/
|
|
175
173
|
waitForExit(signal?: AbortSignal): Promise<boolean>
|
|
176
174
|
}
|
|
@@ -249,7 +247,7 @@ The terminal spec fully specifies argv, cwd, environment overrides, dimensions,
|
|
|
249
247
|
|
|
250
248
|
## Service behavior
|
|
251
249
|
|
|
252
|
-
The abstract [`SubprocessRuntime`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subprocess/subprocess/src/index.ts) Service Definition specifies execution-world coordinates, executable lookup, ordinary `spawn`, and `spawnTerminal`. [`LocalSubprocessRuntime`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subprocess/subprocess-local/src/index.ts) provides them with
|
|
250
|
+
The abstract [`SubprocessRuntime`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subprocess/subprocess/src/index.ts) Service Definition specifies execution-world coordinates, executable lookup, ordinary `spawn`, and `spawnTerminal`. [`LocalSubprocessRuntime`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subprocess/subprocess-local/src/index.ts) provides them with platform-selected managed ranges, per-disposition wiring, credential scrubbing, `node-pty`, platform process inspection, and terminate-and-join disposal. See [`dsh-subprocess`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subprocess/subprocess/README.md) for the Service Definition contract and [`dsh-subprocess-local`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subprocess/subprocess-local/README.md) for local mechanics.
|
|
253
251
|
|
|
254
252
|
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
|
255
253
|
|
|
@@ -285,9 +283,9 @@ Abstract subprocess service. Subclass, implement spawn, and load the subclass as
|
|
|
285
283
|
Implementations must honor these semantics:
|
|
286
284
|
|
|
287
285
|
- Executable paths belong to one execution world shared with the mounted filesystem provider.
|
|
288
|
-
- spawn returns
|
|
286
|
+
- spawn returns a live handle synchronously. Target identity remains provider-private; `done` resolves with the spawned command's exit facts and may reject for spawn or provider failures.
|
|
289
287
|
- Collect-mode readers are offset-based and non-consuming, so independent readers never consume one another's output; lossy reads report truncation and the spill file holding the complete stream when one exists. Piped streams are handed to the caller raw and never buffered here.
|
|
290
|
-
- SubprocessHandle.terminate (and the spec's abort signal)
|
|
288
|
+
- SubprocessHandle.terminate (and the spec's abort signal) starts the provider's documented procedure against its managed range. SubprocessHandle.waitForExit observes that same range so a consumer-owned teardown ladder can hold each tier on real quiescence; each provider documents its signalling and observability limits.
|
|
291
289
|
- Disposal of the service terminates all still-running managed processes and awaits their exit.
|
|
292
290
|
- spawnTerminal owns terminal allocation, text transport, foreground groups, signalling, and whole-session quiescence behind one awaited termination method; readiness and persistent-shell policy stay in the PTY consumer. Its output stream ends after queued terminal output when the top-level process exits.
|
|
293
291
|
|
|
@@ -310,13 +308,14 @@ abstract resolveExecutable( command: string, env?: Readonly<Record<string, strin
|
|
|
310
308
|
* applies no defaults.
|
|
311
309
|
* @param spec - argv, directory, stdio dispositions, grace, cancellation, and environment.
|
|
312
310
|
* @returns the live process handle (streams/readers, signalling, outcome promise).
|
|
311
|
+
* @throws synchronously when pre-aborted or when argv, cwd, environment, or grace is invalid before handle creation.
|
|
313
312
|
*/
|
|
314
313
|
abstract spawn(spec: SubprocessSpawnSpec): SubprocessHandle
|
|
315
314
|
|
|
316
315
|
/**
|
|
317
316
|
* Allocate a real terminal and start one owned process session. This is the
|
|
318
317
|
* only non-pipe process primitive: implementations own terminal byte I/O,
|
|
319
|
-
* foreground groups, signals, and
|
|
318
|
+
* foreground groups, signals, and whole-session quiescence.
|
|
320
319
|
* @param spec - fully specified argv, cwd, environment, dimensions, grace, and allocation cancellation.
|
|
321
320
|
* @returns the live terminal handle after allocation succeeds.
|
|
322
321
|
*/
|
|
@@ -42,7 +42,9 @@ interface ToolProviderResult {
|
|
|
42
42
|
|
|
43
43
|
## Prompt sections
|
|
44
44
|
|
|
45
|
-
`
|
|
45
|
+
The exported `PERSONA_PREFIX_SECTION` (`deployment:persona-prefix`) and `PERSONA_SUFFIX_SECTION` (`deployment:persona-suffix`) name the slots shared by global configuration and scoped contributions. Their `PromptSectionOrderName` entries are `DEPLOYMENT_PERSONA_PREFIX` and `DEPLOYMENT_PERSONA_SUFFIX`; the [package README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/system-prompt/README.md#configure-the-prompt) owns their placement and template configuration.
|
|
46
|
+
|
|
47
|
+
`PromptSection` is a readonly same-process registration contract. Its text may be static or resolved from the current assembly context. Sections sort by ascending order and then code-unit name; repository contributors resolve the service-owned named allocation through `getSectionOrder()`. Runtime-context contributors resolve their independent allocation through `getContextOrder()`. One effective `complete` section becomes the sole prompt section after cooperative assembly. agent-loop renders the assembled sections with `renderPrompt` and commits the text as a `system/message` surface node — appended as surface node 0 on the first step, then replaced in place when the rendered text changes or, when the prepared call declares `systemPromptUpdate: 'in-history'`, appended after the cached history for non-empty updates in a continuing series — so the prompt reaches the model as a message of derived history rather than as a request field ([decision](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-09-02-system-prompt-as-surface-node.md); [decision rule](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent-loop/README.md#understand-the-implementation)).
|
|
46
48
|
|
|
47
49
|
```ts type-equiv
|
|
48
50
|
/** One contributed section of the system prompt (registry input). */
|
|
@@ -81,7 +81,8 @@ Replay owner for one service-wide estimator and isolated per-session folds.
|
|
|
81
81
|
* usage is reused only when the latest successful call's canonical request
|
|
82
82
|
* envelope matches `requestHeader` and its total is no lower than that
|
|
83
83
|
* call's full route-priced anchor; otherwise the complete envelope and
|
|
84
|
-
* surface are repriced.
|
|
84
|
+
* surface are repriced. The anchor includes all surface nodes immediately
|
|
85
|
+
* before the assistant message, including inputs admitted after step/start.
|
|
85
86
|
*
|
|
86
87
|
* `requestHeader` replaces the latest logged envelope for pressure and node
|
|
87
88
|
* pricing; the node set always describes the current session surface. Every
|
|
@@ -265,14 +265,14 @@ PTC mode's bridge additionally exposes each settled sub-dispatch to the `tools/p
|
|
|
265
265
|
* copy a listener may reshape. `content` is the RENDERED result projection
|
|
266
266
|
* (what a native `tool/result` would carry) — the program itself received
|
|
267
267
|
* the structured `value` (or just the error message on failure); only the
|
|
268
|
-
* `tool/
|
|
268
|
+
* `tool/ptc-dispatch` event's copy changes.
|
|
269
269
|
*/
|
|
270
270
|
interface PtcDispatchLog {
|
|
271
271
|
/** The outer `run_code` execution. */
|
|
272
272
|
readonly exec: ToolExecution
|
|
273
273
|
/** The calling agent (the scope routing key and the spill owner), when the outer call has one. */
|
|
274
274
|
readonly agent?: Agent
|
|
275
|
-
/**
|
|
275
|
+
/** Opaque sub-call id; new calls use `<parent>:ptc:<n>`. */
|
|
276
276
|
readonly subCallId: ToolCallId
|
|
277
277
|
/** The dispatched sub-tool name. */
|
|
278
278
|
readonly name: string
|
|
@@ -370,7 +370,7 @@ interface ToolExecutionFailure {
|
|
|
370
370
|
type ToolExecutionResult = ToolExecutionSuccess | ToolExecutionFailure
|
|
371
371
|
```
|
|
372
372
|
|
|
373
|
-
The result carries only the outcome. Call identity remains on the immutable `ToolExecution` that accompanies it through every hook and on the durable `tool/call` / `tool/result` session events, so wrappers cannot create a second, disagreeing identity. The canonical `value` is execution-local: the loop persists only `content`, `error`, and `meta`, while `tool/
|
|
373
|
+
The result carries only the outcome. Call identity remains on the immutable `ToolExecution` that accompanies it through every hook and on the durable `tool/call` / `tool/result` session events, so wrappers cannot create a second, disagreeing identity. The canonical `value` is execution-local: the loop persists only `content`, `error`, and `meta`, while `tool/ptc-dispatch` stores the sub-call's rendered `content` and `isError` verbatim. Replay reproduces presentation but cannot reconstruct canonical intermediate values.
|
|
374
374
|
|
|
375
375
|
On success the registry snapshots and validates the body value, freezes it, and invokes the pure renderer plus the optional top-level-call metadata projector. It separately materializes the durable presentation fields immediately before `tools/result`; an invalid value, renderer/projector failure, or non-JSON presentation becomes a JSON-safe `isError`. The final live observer therefore sees the exact execution-local value beside fields safe for the later durable append.
|
|
376
376
|
|
|
@@ -677,13 +677,13 @@ Source: [`packages/core/tools/src/index.ts`](https://github.com/deepseek-ai/deep
|
|
|
677
677
|
|
|
678
678
|
#### `tools/ptc-dispatch-log` — waterfall
|
|
679
679
|
|
|
680
|
-
Allow a listener to replace content in the DURABLE LOG COPY of one `run_code` sub-dispatch outcome before the bridge appends its `tool/
|
|
680
|
+
Allow a listener to replace content in the DURABLE LOG COPY of one `run_code` sub-dispatch outcome before the bridge appends its `tool/ptc-dispatch` event. `next()` keeps the content unchanged; a listener may return replacement blocks (e.g. the spill policy's preview + locator for an oversized text result). Only the logged copy is affected — the program already received the complete value, and the model sees neither. A throwing listener is contained: the bridge falls back to logging the original settled content. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's dispatches.
|
|
681
681
|
|
|
682
682
|
```ts cordis-catalog
|
|
683
683
|
/**
|
|
684
684
|
* Allow a listener to replace content in the DURABLE LOG COPY of one
|
|
685
685
|
* `run_code` sub-dispatch outcome before the bridge appends its
|
|
686
|
-
* `tool/
|
|
686
|
+
* `tool/ptc-dispatch` event. `next()` keeps the
|
|
687
687
|
* content unchanged; a listener may return replacement blocks (e.g. the
|
|
688
688
|
* spill policy's preview + locator for an oversized text result). Only the
|
|
689
689
|
* logged copy is affected — the program already received the complete
|
|
@@ -5,7 +5,7 @@ outline: [2,3]
|
|
|
5
5
|
|
|
6
6
|
# Workspaces
|
|
7
7
|
|
|
8
|
-
A workspace is the persistent record of a directory the user works in: a stable id over a canonical path, a display title, and the ordered account of sessions that belong to it. The subsystem is one package ([dsh-workspace](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/workspace/workspace), `ctx.workspaceRegistry`) — an optional host-side capability, not part of the agent-loop spine, and invisible to models (no tools, no prompt text, no session events). It stores its records through the [storage domain form](./storage.md) and validates session membership against [`SessionHeader.cwd`](./persistence.md#sessionheader--metadata-beside-the-log), so `storageDomain` and `sessionPersistence` are mandatory startup dependencies: an unavailable persistence peer leaves the plugin pending rather than being mistaken for an empty history. Design record: [domain KV storage Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md); bootstrap and GUI ordering: [Workspace UI product-flow Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/
|
|
8
|
+
A workspace is the persistent record of a directory the user works in: a stable id over a canonical path, a display title, and the ordered account of sessions that belong to it. The subsystem is one package ([dsh-workspace](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/workspace/workspace), `ctx.workspaceRegistry`) — an optional host-side capability, not part of the agent-loop spine, and invisible to models (no tools, no prompt text, no session events). It stores its records through the [storage domain form](./storage.md) and validates session membership against [`SessionHeader.cwd`](./persistence.md#sessionheader--metadata-beside-the-log), so `storageDomain` and `sessionPersistence` are mandatory startup dependencies: an unavailable persistence peer leaves the plugin pending rather than being mistaken for an empty history. Design record: [domain KV storage Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md); bootstrap and GUI ordering: [Workspace UI product-flow Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/archived/feature/2026-07-25-workspace-ui-product-flow.md).
|
|
9
9
|
|
|
10
10
|
Source: [`packages/workspace/workspace/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/workspace/workspace/src/types.ts)
|
|
11
11
|
|
|
@@ -245,6 +245,85 @@ Host service backing the generated `ctx.remote.workspace` namespace.
|
|
|
245
245
|
|
|
246
246
|
Source: [`packages/api/workspace-controller/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/api/workspace-controller/src/index.ts)
|
|
247
247
|
|
|
248
|
+
<a id="ctxworkspacefiles--workspacefiles"></a>
|
|
249
|
+
|
|
250
|
+
### `ctx.workspaceFiles` — `WorkspaceFiles`
|
|
251
|
+
|
|
252
|
+
Host Remote file reads and workspace directory observations over the composed filesystem.
|
|
253
|
+
|
|
254
|
+
```ts cordis-catalog
|
|
255
|
+
/**
|
|
256
|
+
* Read one page of lines from a UTF-8 file readable by the filesystem backend.
|
|
257
|
+
* @param workspaceFileScope - header-derived workspace root for the Session identity on the wire.
|
|
258
|
+
* @param path - absolute path or path relative to the workspace root; files outside it are allowed.
|
|
259
|
+
* @param range - the line window; omitted fields take the page defaults.
|
|
260
|
+
* @param signal - caller cancellation.
|
|
261
|
+
* @returns the page, the file's version at the stat before it, and whether it reaches the last line.
|
|
262
|
+
*/
|
|
263
|
+
@Remote async read( workspaceFileScope: WorkspaceFileScope, path: string, range: WorkspaceFileRange, signal: AbortSignal, ): Promise<WorkspaceFileText>
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Read one byte window of a regular file readable by the filesystem backend: raw
|
|
267
|
+
* bytes, no text decoding and no binary rejection.
|
|
268
|
+
* @param workspaceFileScope - header-derived workspace root for the Session identity on the wire.
|
|
269
|
+
* @param path - absolute path or path relative to the workspace root; files outside it are allowed.
|
|
270
|
+
* @param range - the byte window; omitted fields take the window defaults.
|
|
271
|
+
* @param signal - caller cancellation.
|
|
272
|
+
* @returns the window in base64, the file's version and size at the stat before it, and whether it reaches the last byte.
|
|
273
|
+
*/
|
|
274
|
+
@Remote async readBytes( workspaceFileScope: WorkspaceFileScope, path: string, range: WorkspaceByteRange, signal: AbortSignal, ): Promise<WorkspaceFileBytes>
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Read a complete regular file as bytes, subject to the configured full-file cap.
|
|
278
|
+
* @param workspaceFileScope - header-derived workspace root for the Session identity on the wire.
|
|
279
|
+
* @param path - absolute or workspace-relative file path.
|
|
280
|
+
* @param signal - caller cancellation.
|
|
281
|
+
* @returns one complete base64 window with offset zero and eof true; oversized files fail with too-large.
|
|
282
|
+
*/
|
|
283
|
+
@Remote async readAll(workspaceFileScope: WorkspaceFileScope, path: string, signal: AbortSignal): Promise<WorkspaceFileBytes>
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Read a complete file relative to another file's directory, including outside the workspace.
|
|
287
|
+
* @param workspaceFileScope - header-derived workspace root for the Session identity on the wire.
|
|
288
|
+
* @param path - base file, absolute or workspace-relative.
|
|
289
|
+
* @param relativePath - relative filesystem path, not a URL or absolute path.
|
|
290
|
+
* @param signal - caller cancellation.
|
|
291
|
+
* @returns the complete related file using the ordinary file-size and access checks.
|
|
292
|
+
*/
|
|
293
|
+
@Remote async readRelated( workspaceFileScope: WorkspaceFileScope, path: string, relativePath: string, signal: AbortSignal, ): Promise<WorkspaceFileBytes>
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Report one regular file's identity, version, and size without its content.
|
|
297
|
+
* @param workspaceFileScope - header-derived workspace root for the Session identity on the wire.
|
|
298
|
+
* @param path - absolute path or path relative to the workspace root; files outside it are allowed.
|
|
299
|
+
* @param signal - caller cancellation.
|
|
300
|
+
* @returns the file's absolute path, current version, and byte size.
|
|
301
|
+
*/
|
|
302
|
+
@Remote async stat(workspaceFileScope: WorkspaceFileScope, path: string, signal: AbortSignal): Promise<WorkspaceFileStat>
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* List the direct children of one directory inside the Session's workspace.
|
|
306
|
+
* @param workspaceFileScope - header-derived workspace root for the Session identity on the wire.
|
|
307
|
+
* @param path - workspace path, absolute or relative to the workspace root.
|
|
308
|
+
* @param signal - caller cancellation.
|
|
309
|
+
* @returns the directory's children in the backend's stable name order, bounded by the entry cap.
|
|
310
|
+
*/
|
|
311
|
+
@Remote async list(workspaceFileScope: WorkspaceFileScope, path: string, signal: AbortSignal): Promise<WorkspaceDirectoryListing>
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Stream every `fs/observed` observation of a file inside the Session's
|
|
315
|
+
* workspace. Only instrumented filesystem operations report here; the OS is
|
|
316
|
+
* not watched.
|
|
317
|
+
* @param workspaceFileScope - header-derived workspace root for the Session identity on the wire.
|
|
318
|
+
* @param signal - generation cancellation.
|
|
319
|
+
* @returns `ready` once the Host observation queue is active and the workspace
|
|
320
|
+
* root is resolved, then queued and live observations in emission order.
|
|
321
|
+
*/
|
|
322
|
+
@Remote({ mode: 'stream' }) changes(workspaceFileScope: WorkspaceFileScope, signal: AbortSignal): AsyncIterable<WorkspaceFileWatchFrame>
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Source: [`packages/api/workspace-files/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/api/workspace-files/src/index.ts)
|
|
326
|
+
|
|
248
327
|
<a id="ctxworkspaceregistry--workspaceregistry"></a>
|
|
249
328
|
|
|
250
329
|
### `ctx.workspaceRegistry` — `WorkspaceRegistry`
|