dsh-plugin-dev-kb 1.0.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/LICENSE +21 -0
- package/README.md +56 -0
- package/cordis.patch.yml +12 -0
- package/kb/INDEX.md +210 -0
- package/kb/README.md +69 -0
- package/kb/extra/AGENTS.md +75 -0
- package/kb/extra/api-gateway.md +164 -0
- package/kb/extra/api-gateway.zh.md +164 -0
- package/kb/extra/cookbook/adding-a-vendored-package.md +59 -0
- package/kb/extra/cookbook/adding-a-vendored-package.zh.md +59 -0
- package/kb/extra/cookbook/maintaining-dsh-code-review.md +64 -0
- package/kb/extra/cookbook/maintaining-dsh-code-review.zh.md +64 -0
- package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.md +32 -0
- package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.zh.md +32 -0
- package/kb/extra/defensive-patterns.md +33 -0
- package/kb/extra/defensive-patterns.zh.md +33 -0
- package/kb/extra/development.md +171 -0
- package/kb/extra/development.zh.md +171 -0
- package/kb/extra/event-producer-consumer.md +76 -0
- package/kb/extra/event-producer-consumer.zh.md +78 -0
- package/kb/extra/glossary.md +45 -0
- package/kb/extra/glossary.zh.md +45 -0
- package/kb/extra/graph-atlas.md +24 -0
- package/kb/extra/graph-atlas.zh.md +26 -0
- package/kb/extra/i18n/README.md +60 -0
- package/kb/extra/i18n/README.zh.md +60 -0
- package/kb/extra/i18n/style-samples.md +87 -0
- package/kb/extra/i18n/terminology.md +214 -0
- package/kb/extra/i18n/translation-prompt.md +263 -0
- package/kb/extra/i18n/translation-rules.md +69 -0
- package/kb/extra/i18n/translation-rules.zh.md +69 -0
- package/kb/extra/module-graph.md +1641 -0
- package/kb/extra/module-graph.zh.md +1643 -0
- package/kb/extra/postmortem/0001-acp-default-export-drops-inject.md +113 -0
- package/kb/extra/postmortem/0001-acp-default-export-drops-inject.zh.md +113 -0
- package/kb/extra/postmortem/0002-js-expression-disabled-filesystem-tools.md +47 -0
- package/kb/extra/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md +47 -0
- package/kb/extra/postmortem/0003-web-agent-gui-feedback-loop.md +53 -0
- package/kb/extra/postmortem/0003-web-agent-gui-feedback-loop.zh.md +53 -0
- package/kb/extra/postmortem/0004-landlock-partial-notice-misclassified-child-failures.md +55 -0
- package/kb/extra/postmortem/0004-landlock-partial-notice-misclassified-child-failures.zh.md +55 -0
- package/kb/extra/postmortem/README.md +18 -0
- package/kb/extra/postmortem/README.zh.md +18 -0
- package/kb/extra/rescope.md +53 -0
- package/kb/extra/rescope.zh.md +53 -0
- package/kb/extra/subsystems/attachment.md +125 -0
- package/kb/extra/subsystems/attachment.zh.md +125 -0
- package/kb/extra/subsystems/extensions.md +364 -0
- package/kb/extra/subsystems/extensions.zh.md +364 -0
- package/kb/extra/subsystems/feedback.md +266 -0
- package/kb/extra/subsystems/feedback.zh.md +266 -0
- package/kb/extra/testing.md +49 -0
- package/kb/extra/testing.zh.md +49 -0
- package/kb/extra/web-styling.md +25 -0
- package/kb/extra/web-styling.zh.md +25 -0
- package/kb/meta/search-index.json +1328 -0
- package/kb/meta/site-pages.txt +168 -0
- package/kb/meta/source.json +13 -0
- package/kb/meta/topics.md +75 -0
- package/kb/site/develop/basic/config.md +108 -0
- package/kb/site/develop/basic/index.md +146 -0
- package/kb/site/develop/basic/publish.md +185 -0
- package/kb/site/develop/basic/tool.md +54 -0
- package/kb/site/develop/cordis-tutorial/01-first-plugin.md +95 -0
- package/kb/site/develop/cordis-tutorial/02-lifecycle-and-effects.md +98 -0
- package/kb/site/develop/cordis-tutorial/03-services.md +98 -0
- package/kb/site/develop/cordis-tutorial/04-events.md +144 -0
- package/kb/site/develop/cordis-tutorial/05-config.md +84 -0
- package/kb/site/develop/cordis-tutorial/06-composition-and-hmr.md +113 -0
- package/kb/site/develop/cordis-tutorial/07-into-the-harness.md +107 -0
- package/kb/site/develop/cordis-tutorial/index.md +62 -0
- package/kb/site/develop/framework/events.md +145 -0
- package/kb/site/develop/framework/index.md +139 -0
- package/kb/site/develop/framework/service.md +152 -0
- package/kb/site/develop/practice/index.md +157 -0
- package/kb/site/develop/practice/llm-adapter.md +190 -0
- package/kb/site/en/develop/basic/config.md +108 -0
- package/kb/site/en/develop/basic/index.md +146 -0
- package/kb/site/en/develop/basic/publish.md +185 -0
- package/kb/site/en/develop/basic/tool.md +54 -0
- package/kb/site/en/develop/cordis-tutorial/01-first-plugin.md +95 -0
- package/kb/site/en/develop/cordis-tutorial/02-lifecycle-and-effects.md +98 -0
- package/kb/site/en/develop/cordis-tutorial/03-services.md +98 -0
- package/kb/site/en/develop/cordis-tutorial/04-events.md +144 -0
- package/kb/site/en/develop/cordis-tutorial/05-config.md +84 -0
- package/kb/site/en/develop/cordis-tutorial/06-composition-and-hmr.md +113 -0
- package/kb/site/en/develop/cordis-tutorial/07-into-the-harness.md +107 -0
- package/kb/site/en/develop/cordis-tutorial/index.md +60 -0
- package/kb/site/en/develop/framework/events.md +145 -0
- package/kb/site/en/develop/framework/index.md +139 -0
- package/kb/site/en/develop/framework/service.md +150 -0
- package/kb/site/en/develop/practice/index.md +157 -0
- package/kb/site/en/develop/practice/llm-adapter.md +190 -0
- package/kb/site/en/guide/providers-custom-form.png +0 -0
- package/kb/site/en/guide/providers-models-page.png +0 -0
- package/kb/site/en/guide/providers.md +100 -0
- package/kb/site/en/guide/python-sdk.md +106 -0
- package/kb/site/en/guide/quickstart.md +32 -0
- package/kb/site/en/index.md +8 -0
- package/kb/site/en/reference/agent-lifecycle.md +86 -0
- package/kb/site/en/reference/capability-seams.md +475 -0
- package/kb/site/en/reference/config-catalog.md +3155 -0
- package/kb/site/en/reference/cookbook/adding-a-conversation-node.md +235 -0
- package/kb/site/en/reference/cookbook/adding-a-package.md +120 -0
- package/kb/site/en/reference/cookbook/adding-a-settings-card.md +102 -0
- package/kb/site/en/reference/cookbook/adding-a-tool.md +96 -0
- package/kb/site/en/reference/cookbook/adding-an-llm-adapter.md +45 -0
- package/kb/site/en/reference/cookbook/extension-cookbook.md +131 -0
- package/kb/site/en/reference/cordis-api/context.md +368 -0
- package/kb/site/en/reference/cordis-api/events.md +211 -0
- package/kb/site/en/reference/cordis-api/fiber.md +379 -0
- package/kb/site/en/reference/cordis-api/inherited.md +43 -0
- package/kb/site/en/reference/cordis-api/registry.md +156 -0
- package/kb/site/en/reference/cordis-api/service.md +106 -0
- package/kb/site/en/reference/cordis-primer.md +46 -0
- package/kb/site/en/reference/index.md +131 -0
- package/kb/site/en/reference/persistence-catalog.md +949 -0
- package/kb/site/en/reference/subsystems/approval.md +173 -0
- package/kb/site/en/reference/subsystems/client-modules.md +121 -0
- package/kb/site/en/reference/subsystems/code-runtime.md +194 -0
- package/kb/site/en/reference/subsystems/commands.md +190 -0
- package/kb/site/en/reference/subsystems/compaction.md +241 -0
- package/kb/site/en/reference/subsystems/core.md +1073 -0
- package/kb/site/en/reference/subsystems/credentials.md +136 -0
- package/kb/site/en/reference/subsystems/filesystem.md +498 -0
- package/kb/site/en/reference/subsystems/goal.md +280 -0
- package/kb/site/en/reference/subsystems/index.md +58 -0
- package/kb/site/en/reference/subsystems/invariants.md +91 -0
- package/kb/site/en/reference/subsystems/jobs.md +293 -0
- package/kb/site/en/reference/subsystems/llm-streaming.md +920 -0
- package/kb/site/en/reference/subsystems/lsp.md +205 -0
- package/kb/site/en/reference/subsystems/permission-presets.md +134 -0
- package/kb/site/en/reference/subsystems/persistence.md +388 -0
- package/kb/site/en/reference/subsystems/plan.md +90 -0
- package/kb/site/en/reference/subsystems/sandbox.md +221 -0
- package/kb/site/en/reference/subsystems/schedule.md +189 -0
- package/kb/site/en/reference/subsystems/scope.md +62 -0
- package/kb/site/en/reference/subsystems/session-projection.md +265 -0
- package/kb/site/en/reference/subsystems/session-query.md +498 -0
- package/kb/site/en/reference/subsystems/session-reference.md +111 -0
- package/kb/site/en/reference/subsystems/session-telemetry.md +197 -0
- package/kb/site/en/reference/subsystems/session-title.md +207 -0
- package/kb/site/en/reference/subsystems/session.md +852 -0
- package/kb/site/en/reference/subsystems/settings.md +313 -0
- package/kb/site/en/reference/subsystems/shell.md +306 -0
- package/kb/site/en/reference/subsystems/skills.md +334 -0
- package/kb/site/en/reference/subsystems/spill.md +120 -0
- package/kb/site/en/reference/subsystems/storage.md +232 -0
- package/kb/site/en/reference/subsystems/subagent.md +737 -0
- package/kb/site/en/reference/subsystems/subprocess.md +327 -0
- package/kb/site/en/reference/subsystems/system-prompt.md +210 -0
- package/kb/site/en/reference/subsystems/terminal.md +187 -0
- package/kb/site/en/reference/subsystems/token-meter.md +93 -0
- package/kb/site/en/reference/subsystems/tools.md +723 -0
- package/kb/site/en/reference/subsystems/typert.md +339 -0
- package/kb/site/en/reference/subsystems/user-questions.md +181 -0
- package/kb/site/en/reference/subsystems/web-server.md +111 -0
- package/kb/site/en/reference/subsystems/web.md +202 -0
- package/kb/site/en/reference/subsystems/workflow.md +281 -0
- package/kb/site/en/reference/subsystems/workspace.md +231 -0
- package/kb/site/en/reference/tool-catalog.md +1877 -0
- package/kb/site/en/reference/tool-execution-pipeline.md +66 -0
- package/kb/site/guide/providers-custom-form.zh.png +0 -0
- package/kb/site/guide/providers-models-page.zh.png +0 -0
- package/kb/site/guide/providers.md +100 -0
- package/kb/site/guide/python-sdk.md +106 -0
- package/kb/site/guide/quickstart.md +32 -0
- package/kb/site/index.md +8 -0
- package/kb/site/reference/agent-lifecycle.md +86 -0
- package/kb/site/reference/capability-seams.md +475 -0
- package/kb/site/reference/config-catalog.md +3154 -0
- package/kb/site/reference/cookbook/adding-a-conversation-node.md +235 -0
- package/kb/site/reference/cookbook/adding-a-package.md +120 -0
- package/kb/site/reference/cookbook/adding-a-settings-card.md +102 -0
- package/kb/site/reference/cookbook/adding-a-tool.md +98 -0
- package/kb/site/reference/cookbook/adding-an-llm-adapter.md +45 -0
- package/kb/site/reference/cookbook/extension-cookbook.md +133 -0
- package/kb/site/reference/cordis-api/context.md +368 -0
- package/kb/site/reference/cordis-api/events.md +211 -0
- package/kb/site/reference/cordis-api/fiber.md +379 -0
- package/kb/site/reference/cordis-api/inherited.md +43 -0
- package/kb/site/reference/cordis-api/registry.md +156 -0
- package/kb/site/reference/cordis-api/service.md +106 -0
- package/kb/site/reference/cordis-primer.md +52 -0
- package/kb/site/reference/index.md +135 -0
- package/kb/site/reference/persistence-catalog.md +949 -0
- package/kb/site/reference/subsystems/approval.md +173 -0
- package/kb/site/reference/subsystems/client-modules.md +121 -0
- package/kb/site/reference/subsystems/code-runtime.md +194 -0
- package/kb/site/reference/subsystems/commands.md +190 -0
- package/kb/site/reference/subsystems/compaction.md +241 -0
- package/kb/site/reference/subsystems/core.md +1081 -0
- package/kb/site/reference/subsystems/credentials.md +136 -0
- package/kb/site/reference/subsystems/filesystem.md +498 -0
- package/kb/site/reference/subsystems/goal.md +280 -0
- package/kb/site/reference/subsystems/index.md +58 -0
- package/kb/site/reference/subsystems/invariants.md +91 -0
- package/kb/site/reference/subsystems/jobs.md +293 -0
- package/kb/site/reference/subsystems/llm-streaming.md +926 -0
- package/kb/site/reference/subsystems/lsp.md +205 -0
- package/kb/site/reference/subsystems/permission-presets.md +134 -0
- package/kb/site/reference/subsystems/persistence.md +388 -0
- package/kb/site/reference/subsystems/plan.md +90 -0
- package/kb/site/reference/subsystems/sandbox.md +221 -0
- package/kb/site/reference/subsystems/schedule.md +189 -0
- package/kb/site/reference/subsystems/scope.md +62 -0
- package/kb/site/reference/subsystems/session-projection.md +265 -0
- package/kb/site/reference/subsystems/session-query.md +498 -0
- package/kb/site/reference/subsystems/session-reference.md +111 -0
- package/kb/site/reference/subsystems/session-telemetry.md +197 -0
- package/kb/site/reference/subsystems/session-title.md +207 -0
- package/kb/site/reference/subsystems/session.md +854 -0
- package/kb/site/reference/subsystems/settings.md +313 -0
- package/kb/site/reference/subsystems/shell.md +306 -0
- package/kb/site/reference/subsystems/skills.md +334 -0
- package/kb/site/reference/subsystems/spill.md +120 -0
- package/kb/site/reference/subsystems/storage.md +232 -0
- package/kb/site/reference/subsystems/subagent.md +739 -0
- package/kb/site/reference/subsystems/subprocess.md +327 -0
- package/kb/site/reference/subsystems/system-prompt.md +210 -0
- package/kb/site/reference/subsystems/terminal.md +187 -0
- package/kb/site/reference/subsystems/token-meter.md +93 -0
- package/kb/site/reference/subsystems/tools.md +723 -0
- package/kb/site/reference/subsystems/typert.md +339 -0
- package/kb/site/reference/subsystems/user-questions.md +181 -0
- package/kb/site/reference/subsystems/web-server.md +111 -0
- package/kb/site/reference/subsystems/web.md +202 -0
- package/kb/site/reference/subsystems/workflow.md +281 -0
- package/kb/site/reference/subsystems/workspace.md +231 -0
- package/kb/site/reference/tool-catalog.md +1880 -0
- package/kb/site/reference/tool-execution-pipeline.md +66 -0
- package/package.json +40 -0
- package/scripts/rebuild-index.mjs +88 -0
- package/skills/dsh-plugin-dev-kb.md +66 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
---
|
|
2
|
+
editSource: "docs/subsystems/approval.md"
|
|
3
|
+
outline: [2,3]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# User Approval
|
|
7
|
+
|
|
8
|
+
The user-approval seam of [dsh-user-approval](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/interaction/user-approval) answers one question: may this specific action proceed? It owns the shared request/outcome vocabulary, the `ctx.approval` dispatch service, the `approval/request` answerer waterfall, the log-only audit pair, and the per-session `ask`/`never` policy. UI channels may provide human answerers; the [ACP automation bridge](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/acp/acp) provides one-shot machine decisions for its own agents. Callers such as [dsh-tools](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/core/tools) and [dsh-tool-bash](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/shell/tool-bash) consume the closed outcome and fail closed unless it is `allowed-once`.
|
|
9
|
+
|
|
10
|
+
Source: [`packages/interaction/user-approval/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/user-approval/src/index.ts)
|
|
11
|
+
|
|
12
|
+
## Identity and outcome
|
|
13
|
+
|
|
14
|
+
Every request receives a fresh `ApprovalRequestId`. The brand pairs the `approval/asked` and `approval/decided` audit events without making approval ids interchangeable with tool-call or agent/session ids.
|
|
15
|
+
|
|
16
|
+
```ts type-equiv
|
|
17
|
+
/**
|
|
18
|
+
* Pairs one `approval/asked` audit event with its `approval/decided`.
|
|
19
|
+
* Service-issued (one fresh id per {@link ApprovalService.request} call).
|
|
20
|
+
*/
|
|
21
|
+
type ApprovalRequestId = Branded<'ApprovalRequestId'>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`ApprovalOutcome` is closed and fail-closed. `allowed-once` grants only the asked-about action; callers deny on `rejected`, `cancelled`, and `unavailable`. A missing, non-owning, throwing, or non-conforming answerer becomes `unavailable` rather than opening the gate.
|
|
25
|
+
|
|
26
|
+
```ts type-equiv
|
|
27
|
+
/**
|
|
28
|
+
* Closed approval outcomes: a one-shot grant, explicit rejection, withdrawn
|
|
29
|
+
* request, or unavailable answerer. Callers fail closed on `unavailable`.
|
|
30
|
+
*/
|
|
31
|
+
type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Per-session policy
|
|
35
|
+
|
|
36
|
+
`ApprovalPolicy` determines what happens before interactive answerers run. `ask` delegates to the composed answerer chain, whose no-answer default is `unavailable`; `never` deterministically returns `rejected` without dispatching any answerer. The effective value is the last `approval/policy` event in the session log, falling back to the service config. `setApprovalPolicy(session, policy)` is the single write path, so replay reconstructs the override.
|
|
37
|
+
|
|
38
|
+
```ts type-equiv
|
|
39
|
+
/**
|
|
40
|
+
* A session's approval policy — what happens to an {@link ApprovalService}
|
|
41
|
+
* ask BEFORE any interactive answerer sees it:
|
|
42
|
+
*
|
|
43
|
+
* - `'ask'` (the default) — delegate to the composed answerers; with none
|
|
44
|
+
* composed the chain falls through to the fail-closed `'unavailable'`.
|
|
45
|
+
* - `'never'` — never prompt anyone: every ask resolves `'rejected'`
|
|
46
|
+
* deterministically. The strict headless stance (CI, unattended runs) and
|
|
47
|
+
* the policy whose outcome is knowable without asking.
|
|
48
|
+
*/
|
|
49
|
+
type ApprovalPolicy = 'ask' | 'never'
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Both policies contribute their complete current meaning to the cache-safe runtime-context snapshot. The sourced `user/message` is the durable model-visible input; changing approval state appends a new full snapshot after retained history without rewriting the request header's system prompt.
|
|
53
|
+
|
|
54
|
+
## Approval request
|
|
55
|
+
|
|
56
|
+
`ApprovalRequest` identifies the agent and tool action closely enough to route and audit the question. It deliberately omits tool arguments: an answerer attaches the prompt to the already-streamed tool call through `callId` instead of rendering a second copy that could drift.
|
|
57
|
+
|
|
58
|
+
```ts type-equiv
|
|
59
|
+
/**
|
|
60
|
+
* Readonly same-process permission question. `callId` links to an already
|
|
61
|
+
* presented tool call, so arguments are not duplicated here.
|
|
62
|
+
*/
|
|
63
|
+
interface ApprovalRequest {
|
|
64
|
+
/**
|
|
65
|
+
* The agent on whose behalf the question is asked. Routes the question (a
|
|
66
|
+
* UI answerer only answers for agents it owns) and receives the audit
|
|
67
|
+
* events on its session log.
|
|
68
|
+
*/
|
|
69
|
+
readonly agent: Agent
|
|
70
|
+
/** The tool the question is about (presentation and audit). */
|
|
71
|
+
readonly toolName: string
|
|
72
|
+
/**
|
|
73
|
+
* The exact tool call being decided, when the asker has one — lets a UI
|
|
74
|
+
* attach the prompt to the tool call it already streamed.
|
|
75
|
+
*/
|
|
76
|
+
readonly callId?: CallId
|
|
77
|
+
/** The asker's human-readable explanation of WHY it is asking. */
|
|
78
|
+
readonly reason?: string
|
|
79
|
+
/**
|
|
80
|
+
* Aborting withdraws the question: the request settles `'cancelled'`
|
|
81
|
+
* immediately and a late answer from a still-pending answerer is discarded.
|
|
82
|
+
*/
|
|
83
|
+
readonly signal?: AbortSignal
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Dispatch and audit
|
|
88
|
+
|
|
89
|
+
`ctx.approval.request(req)` requires the requesting session to be inside an open turn. It appends `approval/asked`, obtains one outcome, appends the matching `approval/decided`, and resolves with that outcome. The `never` policy is enforced inside the service before waterfall dispatch, so even an answerer registered later with `prepend` cannot bypass it. Answerers return an outcome when they own the request or call `next()` to delegate; the first answer occupies the single decision slot.
|
|
90
|
+
|
|
91
|
+
The audit events are log-only and do not enter the model transcript. Model-visible behavior is the caller's derived tool result plus the current runtime-context snapshot. Service disposal removes its context contribution; answerer listeners are independently effect-bound to their owning plugins.
|
|
92
|
+
|
|
93
|
+
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
|
94
|
+
|
|
95
|
+
<a id="cordis-surface"></a>
|
|
96
|
+
|
|
97
|
+
## Cordis API
|
|
98
|
+
|
|
99
|
+
Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — this section is byte-identical in both language sides of the page. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
|
|
100
|
+
|
|
101
|
+
<a id="ctxapproval--approvalservice"></a>
|
|
102
|
+
|
|
103
|
+
### `ctx.approval` — `ApprovalService`
|
|
104
|
+
|
|
105
|
+
Approval service that applies session policy before answerers and logs every ask/outcome pair to the requesting session. It exposes deterministic policy changes to the model through the runtime-context snapshot and switch notices.
|
|
106
|
+
|
|
107
|
+
```ts cordis-catalog
|
|
108
|
+
/**
|
|
109
|
+
* Switch one live agent's policy and queue the transition for its next model
|
|
110
|
+
* step. Session initialization uses {@link setApprovalPolicy} directly
|
|
111
|
+
* because there is no previously visible policy to change.
|
|
112
|
+
* @param agent - the live agent whose policy is changing.
|
|
113
|
+
* @param policy - the new effective policy.
|
|
114
|
+
*/
|
|
115
|
+
setPolicy(agent: Agent, policy: ApprovalPolicy): void
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Ask the composed answerers to decide one readonly same-process request.
|
|
119
|
+
* The service borrows the request, agent, session, and live signal directly.
|
|
120
|
+
* The request requires an open turn because the audit pair must be enclosed
|
|
121
|
+
* by the durable log's commit/replay boundary; an idle ask rejects before
|
|
122
|
+
* appending anything. The answerer phase always produces an outcome: an
|
|
123
|
+
* aborted signal yields `'cancelled'`, a missing or throwing answerer yields
|
|
124
|
+
* `'unavailable'` (fail closed), and a rogue non-vocabulary return value is
|
|
125
|
+
* normalized to `'unavailable'`. A failure that prevents either audit append
|
|
126
|
+
* from committing still rejects because returning an unlogged decision would
|
|
127
|
+
* violate the pair. Session contains post-commit observer failures, so an
|
|
128
|
+
* authoritative append cannot reject the request or suppress its matching
|
|
129
|
+
* audit event.
|
|
130
|
+
* @param req - the pending decision (agent, tool identity, reason, signal).
|
|
131
|
+
* @returns the closed outcome; `'allowed-once'` is the only grant.
|
|
132
|
+
* @throws when no turn is open or either audit event fails before the session
|
|
133
|
+
* append commit point.
|
|
134
|
+
*/
|
|
135
|
+
async request(req: ApprovalRequest): Promise<ApprovalOutcome>
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Read the session override without applying the configured default.
|
|
139
|
+
* @param session - session whose log supplies the override.
|
|
140
|
+
* @returns the last logged policy, or `undefined` without one.
|
|
141
|
+
*/
|
|
142
|
+
overrideOf(session: Session): ApprovalPolicy | undefined
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Types: [Agent](./core.md) · [Session](./session.md)
|
|
146
|
+
|
|
147
|
+
Source: [`packages/interaction/user-approval/src/index.ts:192`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/user-approval/src/index.ts)
|
|
148
|
+
|
|
149
|
+
<a id="approval-events"></a>
|
|
150
|
+
|
|
151
|
+
### `approval/*` events
|
|
152
|
+
|
|
153
|
+
<a id="approvalrequest--waterfall"></a>
|
|
154
|
+
|
|
155
|
+
#### `approval/request` — waterfall
|
|
156
|
+
|
|
157
|
+
Ask composed answerers for one decision. Return an outcome to claim the request or call `next()`; failure yields the fail-closed default. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
|
|
158
|
+
|
|
159
|
+
```ts cordis-catalog
|
|
160
|
+
/**
|
|
161
|
+
* Ask composed answerers for one decision. Return an outcome to claim the
|
|
162
|
+
* request or call `next()`; failure yields the fail-closed default.
|
|
163
|
+
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
|
|
164
|
+
* @param req - the pending decision (agent, tool identity, reason, signal).
|
|
165
|
+
* @mode waterfall
|
|
166
|
+
*/
|
|
167
|
+
'approval/request'(this: Scoped<ApprovalService>, req: ApprovalRequest, next: () => Promise<ApprovalOutcome>): Promise<ApprovalOutcome>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Types: [Scoped](./scope.md)
|
|
171
|
+
|
|
172
|
+
Source: [`packages/interaction/user-approval/src/index.ts:30`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/user-approval/src/index.ts)
|
|
173
|
+
<!-- END GENERATED cordis-surface -->
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
editSource: "docs/subsystems/client-modules.md"
|
|
3
|
+
outline: [2,3]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Client Modules
|
|
7
|
+
|
|
8
|
+
The web plugin table: the Node half of the client module system in [dsh-client-modules](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/client/modules), provided as `ctx.clientModules` (`ClientModuleRegistry`). It scans the host Loader's entries for packages declaring `dsh.client`, composes the `window.__DSH_BOOT__` entry graph, serves each bundle at `/plugins/<id>/client.js`, and taps the index render to inject the boot manifest — the four faces of one service. It is an optional capability of the web GUI stack, not part of the agent-loop spine, and it is a consumer of [dsh-host-webserver](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/host/webserver): the carrier described in [web-server.md](./web-server.md) supplies the prefix route and index tap this service registers. The same package's browser half (`ctx.modules`, the lazy-CJS module table that fetches and materializes these bundles) is kernel machinery documented in the [package README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/modules/README.md), not here.
|
|
9
|
+
|
|
10
|
+
Source: [`packages/client/modules/src/client/manifest.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/modules/src/client/manifest.ts)
|
|
11
|
+
|
|
12
|
+
## The wire
|
|
13
|
+
|
|
14
|
+
The graph is the wire single source between the Node and browser halves: the host composes `WebBootEntry` rows from scanned packages, injects the graph as the first script in `<head>` (`window.__DSH_BOOT__`, with `<` escaped so plugin-controlled strings cannot break out of the script element), and the shell parses it before booting anything. A page without a valid manifest cannot boot — the browser-side parser throws loud on a missing or malformed graph.
|
|
15
|
+
|
|
16
|
+
```ts type-equiv
|
|
17
|
+
/**
|
|
18
|
+
* One composed client entry pushed by the host (a graph row). Wire
|
|
19
|
+
* single source: the host node half (package root) produces this same shape.
|
|
20
|
+
* `immediately` marks stage-one prefetch; `inject` is informational graph
|
|
21
|
+
* metadata (the authoritative edges live in each package's `dsh.client`
|
|
22
|
+
* declaration and reach fibers through entry creation).
|
|
23
|
+
*/
|
|
24
|
+
interface WebBootEntry {
|
|
25
|
+
/** Entry name == package name. */
|
|
26
|
+
id: string
|
|
27
|
+
/** Bundle endpoint, '/plugins/<id>/client.js?rev=<rev>'. */
|
|
28
|
+
url: string
|
|
29
|
+
/** Bundle content hash (cache-busting consistency anchor). */
|
|
30
|
+
rev: string
|
|
31
|
+
/** Package-name dependency edges, informational (preflight display / HMR diffing). */
|
|
32
|
+
inject?: string[]
|
|
33
|
+
/** Stage-one prefetch mark: load the script for factory registration during module-face boot. */
|
|
34
|
+
immediately?: boolean
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```ts type-equiv
|
|
39
|
+
/** The composed client entry graph the host injects as `window.__DSH_BOOT__`. */
|
|
40
|
+
interface WebBootGraph {
|
|
41
|
+
/** Consistency anchor over the whole graph (content + bundle hashes). */
|
|
42
|
+
rev: string
|
|
43
|
+
/** Composed entries; order carries no semantics (activation order is fiber inject waiting). */
|
|
44
|
+
entries: WebBootEntry[]
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Each row's `rev` is the bundle's content hash and rides the URL as a cache-busting query; the graph `rev` hashes the composed rows, so any row change changes it. `immediately` marks the stage-one prefetch tier (fetch and execute during module-face boot, registration only); a lazy row is fetched on first import.
|
|
49
|
+
|
|
50
|
+
## The scan
|
|
51
|
+
|
|
52
|
+
A package joins the table by declaring `dsh.client` (`platform: 'web'`, optional `inject` edges, optional `immediately`) in its package.json and exporting its built bundle at `exports["./client"]`. Package resolution anchors at the config tree's `ctx.baseUrl` — the cordis.yml directory, whose package declares every composed plugin as a dependency — and construction throws when that anchor is unset.
|
|
53
|
+
|
|
54
|
+
Scanning is incremental per package; there is no full-rescan code path. Every cordis `internal/plugin` emission (fiber construction or disposal) marks the fiber's entry name dirty, and a microtask flush reconciles each dirty name against the live loader entries. The activation pass seeds the same dirty set with all current entries and flushes synchronously, so first scan and steady state share one implementation — with opposite failure postures. At activation, a malformed declaration or missing bundle among the already-loaded entries aggregates into one loud `AggregateError` listing every broken package: the fiber FAILS and the boot's fail-loud sweep reports it. In steady state, a broken package logs a warning and must not poison the others.
|
|
55
|
+
|
|
56
|
+
Package metadata — including the negative "not a client package" verdict — is cached per name and never expires: plugin-set changes take effect on restart. A fiber restart reuses its row and rev untouched; bundle content changes reach the graph only through `rebuilt()`.
|
|
57
|
+
|
|
58
|
+
## The bundle route and index tap
|
|
59
|
+
|
|
60
|
+
`GET`/`HEAD /plugins/<id>/client.js` serves the registered bundle from disk with `no-cache` (the rev query, not HTTP caching, anchors consistency); other methods are 405. An unknown id — or a registered row whose bundle is unreadable because it has not been built yet — answers a loud 404 rather than letting the carrier's SPA fallback ship HTML as JavaScript. The index tap injects the current graph on every index render, so a reload always boots against the live composition.
|
|
61
|
+
|
|
62
|
+
## The service
|
|
63
|
+
|
|
64
|
+
`ClientModuleRegistry` (`ctx.clientModules`, defined in [`packages/client/modules/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/modules/src/index.ts)) exposes reads and the rebuild face; signatures are in the generated [service catalog](#ctxclientmodules--clientmoduleregistry). `graph()` returns the current composed graph (a stable object between changes) and `clientPath(id)` the bundle's absolute path. `rebuilt(id)` is the only entry point through which bundle content reaches the graph: it re-hashes the file, and only a real rev change recomposes the graph and notifies. `onRebuilt` fires per changed bundle with the new rev; `onGraphChanged` fires after any flush that recomposed the graph (row added or removed, or a rebuilt rev change) and is pull-model — listeners re-read `graph()`. Both notification paths contain listener exceptions so one throwing subscriber cannot skip later subscribers or kill whatever triggered the flush.
|
|
65
|
+
|
|
66
|
+
In development, [dsh-client-hmr](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/hmr/README.md) is the registry's watch driver: its node half stat-polls every graph row's bundle from a synchronously captured baseline, calls `rebuilt(id)` on change, resyncs its watch set through `onGraphChanged`, and broadcasts rev changes to the browser half over SSE. Production graphs omit the HMR row entirely; the module host itself never watches files.
|
|
67
|
+
|
|
68
|
+
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
|
69
|
+
|
|
70
|
+
<a id="cordis-surface"></a>
|
|
71
|
+
|
|
72
|
+
## Cordis API
|
|
73
|
+
|
|
74
|
+
Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — this section is byte-identical in both language sides of the page. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
|
|
75
|
+
|
|
76
|
+
<a id="ctxclientmodules--clientmoduleregistry"></a>
|
|
77
|
+
|
|
78
|
+
### `ctx.clientModules` — `ClientModuleRegistry`
|
|
79
|
+
|
|
80
|
+
The web plugin table service: incremental `dsh.client` scan + wire composition + bundle route + index tap. Construction runs the activation scan synchronously — a malformed declaration or missing bundle among the already-loaded entries aggregates into one loud throw (FAILED fiber; the boot activation audit reports it).
|
|
81
|
+
|
|
82
|
+
```ts cordis-catalog
|
|
83
|
+
/**
|
|
84
|
+
* Current composed entry graph (stable object between changes).
|
|
85
|
+
* @returns the graph served as `window.__DSH_BOOT__`.
|
|
86
|
+
*/
|
|
87
|
+
graph(): WebBootGraph
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Absolute path of an entry's client bundle.
|
|
91
|
+
* @param id - entry id (package name).
|
|
92
|
+
* @returns the path, or undefined for an unknown id.
|
|
93
|
+
*/
|
|
94
|
+
clientPath(id: string): string | undefined
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Re-hash one bundle (the HMR watch's registration hook — the only entry
|
|
98
|
+
* point through which bundle content changes reach the graph).
|
|
99
|
+
* @param id - entry id (package name).
|
|
100
|
+
* @returns the new rev, or undefined for an unknown id.
|
|
101
|
+
*/
|
|
102
|
+
rebuilt(id: string): string | undefined
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Subscribe to bundle rebuilds; fires only when the re-hash changed the rev.
|
|
106
|
+
* @param listener - receives the entry id and its new bundle rev.
|
|
107
|
+
* @returns the unsubscriber.
|
|
108
|
+
*/
|
|
109
|
+
onRebuilt(listener: (id: string, rev: string) => void): () => void
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Fires after any flush that recomposed the graph (row added/removed, or a
|
|
113
|
+
* rebuilt rev change). Pull model: listeners re-read {@link graph}.
|
|
114
|
+
* @param listener - notified with no payload.
|
|
115
|
+
* @returns the unsubscriber.
|
|
116
|
+
*/
|
|
117
|
+
onGraphChanged(listener: () => void): () => void
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Source: [`packages/client/modules/src/index.ts:184`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/modules/src/index.ts)
|
|
121
|
+
<!-- END GENERATED cordis-surface -->
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
---
|
|
2
|
+
editSource: "docs/subsystems/code-runtime.md"
|
|
3
|
+
outline: [2,3]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Code Runtime
|
|
7
|
+
|
|
8
|
+
The code-execution seam — a [capability seam](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-13-capability-seams.md) whose Service Definition ([dsh-code-runtime](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/code-runtime/code-runtime), `ctx.codeRuntime`) runs one model-written program against host-provided async bindings and reports what it printed and returned. Code execution is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](./core.md). Backends differ by execution substrate and source language, both readonly descriptors on the service; the worker-thread Service Provider and tool-registry Consumer are specified by the [Code Mode foundation](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-06-15-code-mode.md) and [typed-return contract](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-07-20-code-mode-typed-tool-returns.md).
|
|
9
|
+
|
|
10
|
+
Source: [`packages/code-runtime/code-runtime/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/code-runtime/code-runtime/src/types.ts)
|
|
11
|
+
|
|
12
|
+
## The run: request in, result out
|
|
13
|
+
|
|
14
|
+
A `CodeRunRequest` carries **everything the runtime acts on** — per the "explicit > implicit at package boundaries" rule, defaulting (time budgets, output caps) is the implementation's validated config, never a hidden `??` inside `run()`:
|
|
15
|
+
|
|
16
|
+
```ts type-equiv
|
|
17
|
+
/**
|
|
18
|
+
* One run: the program source plus everything the runtime acts on. Per the
|
|
19
|
+
* explicit-over-implicit convention, defaulting (time budgets, output caps)
|
|
20
|
+
* is the implementation's validated config — a request carries no optional
|
|
21
|
+
* tuning knobs for a hidden `??` to fill in.
|
|
22
|
+
*/
|
|
23
|
+
interface CodeRunRequest {
|
|
24
|
+
/**
|
|
25
|
+
* The program source, in the runtime's {@link ../index.ts | language}. It
|
|
26
|
+
* runs as the body of an async function: top-level `await` and `return`
|
|
27
|
+
* are available, and the completion value becomes
|
|
28
|
+
* {@link CodeRunResult.value}.
|
|
29
|
+
*/
|
|
30
|
+
program: string
|
|
31
|
+
/** Host functions exposed to the program, one global object per namespace. */
|
|
32
|
+
bindings: CodeBindingNamespace[]
|
|
33
|
+
/**
|
|
34
|
+
* Abort the run: the runtime stops the program (hard, even mid-loop) and
|
|
35
|
+
* resolves with a {@link CodeRunFailure} of kind `'abort'`. In-flight
|
|
36
|
+
* binding calls are the CALLER's to settle — the runtime only stops asking.
|
|
37
|
+
*/
|
|
38
|
+
signal?: AbortSignal
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The result reports an error as a **field**, never a rejection of `run()` — reporting a failed program is the caller's job, not an exception path (matching `ShellExecutor.run`'s resolve-on-failure contract):
|
|
43
|
+
|
|
44
|
+
```ts type-equiv
|
|
45
|
+
/**
|
|
46
|
+
* The outcome of one run. An error is a FIELD on a resolved result, never a
|
|
47
|
+
* rejection of `run()` — reporting a failed program is the caller's job, not
|
|
48
|
+
* an exception path.
|
|
49
|
+
*/
|
|
50
|
+
interface CodeRunResult {
|
|
51
|
+
/**
|
|
52
|
+
* The program's completion value (its top-level `return`), when it ran to
|
|
53
|
+
* completion and the value crossed the runtime's lossless-JSON boundary.
|
|
54
|
+
* Invalid or over-limit completions fail the run instead of substituting a
|
|
55
|
+
* rendered string; a failed or value-less run leaves this absent.
|
|
56
|
+
*/
|
|
57
|
+
value?: CodeJsonValue
|
|
58
|
+
/** Text the program emitted, in order, bounded only as part of the outer result. */
|
|
59
|
+
logs: string[]
|
|
60
|
+
/** Present iff the run failed; see {@link CodeRunFailure} for the taxonomy. */
|
|
61
|
+
error?: CodeRunFailure
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Bindings: host functions as program globals
|
|
66
|
+
|
|
67
|
+
Each `CodeBindingNamespace` becomes one global object of async callables inside the program (the Code Mode consumer passes one: `tools`). Arguments and resolutions must be lossless JSON and cross without a seam-level byte cap; the runtime may bridge them through structured clone. A namespace may declare a program-visible error class without making the runtime know the consumer's names: the runtime injects the real constructor and turns rejected calls into its instances. A runtime also treats binding names as hostile input (`__proto__` is an ordinary own property, never a prototype collision):
|
|
68
|
+
|
|
69
|
+
```ts type-equiv
|
|
70
|
+
/**
|
|
71
|
+
* Program-visible typed rejection for one binding namespace. The runtime
|
|
72
|
+
* injects a real error constructor under `name`; rejected member calls become
|
|
73
|
+
* its instances and expose the exact member name through
|
|
74
|
+
* `memberNameProperty`. Both strings are runtime data rather than knowledge
|
|
75
|
+
* of a particular consumer such as Code Mode.
|
|
76
|
+
*/
|
|
77
|
+
interface CodeBindingErrorClass {
|
|
78
|
+
/** Constructor global and resulting `Error.name`; same portable identifier rule as {@link CodeBindingNamespace.global}. */
|
|
79
|
+
name: string
|
|
80
|
+
/**
|
|
81
|
+
* Non-empty own property for the member name. The portable exclusion set is
|
|
82
|
+
* `RESERVED_ERROR_MEMBERS` plus dunder-form names (`__x__`, non-empty
|
|
83
|
+
* middle), enforced identically by every backend; any other name —
|
|
84
|
+
* identifiers or not — is accepted everywhere.
|
|
85
|
+
*/
|
|
86
|
+
memberNameProperty: string
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```ts type-equiv
|
|
91
|
+
/**
|
|
92
|
+
* A named group of {@link CodeBindingFunction}s the runtime exposes to the
|
|
93
|
+
* program as one global object (e.g. `tools`). Function names are arbitrary
|
|
94
|
+
* strings — a runtime must treat names like `__proto__` or `constructor` as
|
|
95
|
+
* ordinary own properties (null-prototype construction), never as prototype
|
|
96
|
+
* collisions.
|
|
97
|
+
*/
|
|
98
|
+
interface CodeBindingNamespace {
|
|
99
|
+
/**
|
|
100
|
+
* The global identifier the program sees. Must match the LANGUAGE-PORTABLE
|
|
101
|
+
* identifier subset `[A-Za-z_][A-Za-z0-9_]*` and no language's reserved
|
|
102
|
+
* words, so the same namespace list works against every backend regardless
|
|
103
|
+
* of `language` — a JS-only spelling like `$tools` is rejected by design,
|
|
104
|
+
* not just by the Python backend. Names that satisfy the identifier rule but
|
|
105
|
+
* name a backend-owned slot (`RESERVED_BINDING_GLOBALS`, e.g. `console`,
|
|
106
|
+
* `__dsh_main__`) are also refused everywhere; see its declaration for the
|
|
107
|
+
* exact set and why each entry is reserved.
|
|
108
|
+
*/
|
|
109
|
+
global: string
|
|
110
|
+
/** The callable members, keyed by the exact name the program calls. */
|
|
111
|
+
functions: Record<string, CodeBindingFunction>
|
|
112
|
+
/** Optional program-visible typed rejection contract for this namespace. */
|
|
113
|
+
errorClass?: CodeBindingErrorClass
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
```ts type-equiv
|
|
118
|
+
/** A lossless JSON value transferable through the dependency-light Service Definition. */
|
|
119
|
+
type CodeJsonValue = null | boolean | number | string | CodeJsonValue[] | { [key: string]: CodeJsonValue }
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
```ts type-equiv
|
|
123
|
+
/**
|
|
124
|
+
* One host-side function exposed to the program as an async callable. The
|
|
125
|
+
* runtime bridges calls to it (possibly across a serialization boundary), so
|
|
126
|
+
* `args` and the resolution value MUST be lossless JSON. A runtime rejects a
|
|
127
|
+
* lossy or non-cloneable value with a descriptive error rather than corrupting
|
|
128
|
+
* the run. No seam-level byte cap applies to a binding resolution. A rejection
|
|
129
|
+
* of this function surfaces inside the program as a rejection of the
|
|
130
|
+
* corresponding call.
|
|
131
|
+
*/
|
|
132
|
+
type CodeBindingFunction = (args: unknown) => Promise<CodeJsonValue>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Captured output and the failure taxonomy
|
|
136
|
+
|
|
137
|
+
Logs are plain strings in emission order. The runtime captures the program's console and stream output, but channel and console-method metadata are not part of the seam because consumers render only the text. Implementations cap the serialized outer log-array plus completion-value or failure-message payload; fixed result-envelope syntax and consumer presentation whitespace are not part of that variable-payload ledger. Overflow is an explicit failure rather than in-band value substitution.
|
|
138
|
+
|
|
139
|
+
Failure kinds are **orthogonal outcomes reported independently** (per [defensive-patterns](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/defensive-patterns.md)): a budget expiry is not an exception, an abort is not a timeout, and a substrate death (e.g. OOM) is neither:
|
|
140
|
+
|
|
141
|
+
```ts type-equiv
|
|
142
|
+
/**
|
|
143
|
+
* Why a run failed. The kinds are orthogonal outcomes reported independently
|
|
144
|
+
* (per docs/defensive-patterns.md): a budget expiry is not an exception, an
|
|
145
|
+
* abort is not a timeout, and a substrate death is neither.
|
|
146
|
+
*
|
|
147
|
+
* - `'exception'` — the program threw or failed to parse/transform.
|
|
148
|
+
* - `'timeout'` — an implementation-owned budget expired; the message says which.
|
|
149
|
+
* - `'abort'` — {@link CodeRunRequest.signal} fired.
|
|
150
|
+
* - `'worker-exit'` — the execution substrate died without settling (e.g. OOM).
|
|
151
|
+
* - `'invalid-output'` — the completion value was not lossless JSON.
|
|
152
|
+
* - `'output-limit'` — the serialized outer logs/value/diagnostic exceeded the configured cap.
|
|
153
|
+
*/
|
|
154
|
+
interface CodeRunFailure {
|
|
155
|
+
/** The failure class (see the interface doc for each kind's meaning). */
|
|
156
|
+
kind: 'exception' | 'timeout' | 'abort' | 'worker-exit' | 'invalid-output' | 'output-limit'
|
|
157
|
+
/** Human-readable detail, suitable for feeding back to a model to self-correct. */
|
|
158
|
+
message: string
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## The service
|
|
163
|
+
|
|
164
|
+
`CodeRuntime` (`ctx.codeRuntime`, abstract — defined in [`packages/code-runtime/code-runtime/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/code-runtime/code-runtime/src/index.ts)) is `run(request)` plus two readonly descriptors: `language` (what the program must be written in — `'typescript'` and `'python'` are the well-known values, those `dsh-tools` presents, and only `'typescript'` has a published backend; a consumer generating language-specific presentation switches on it and fails loud on one it cannot present) and `isolation` (the execution substrate — `'worker-thread'`, `'process'`, `'container'`; a diagnostic label, **not a security claim**). Implementations must keep runs isolated from each other (no cross-run state) and dispose to quiescence: in-flight runs are terminated and awaited before teardown completes.
|
|
165
|
+
|
|
166
|
+
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
|
167
|
+
|
|
168
|
+
<a id="cordis-surface"></a>
|
|
169
|
+
|
|
170
|
+
## Cordis API
|
|
171
|
+
|
|
172
|
+
Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — this section is byte-identical in both language sides of the page. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
|
|
173
|
+
|
|
174
|
+
<a id="ctxcoderuntime--coderuntime-abstract-seam"></a>
|
|
175
|
+
|
|
176
|
+
### `ctx.codeRuntime` — `CodeRuntime` (abstract seam)
|
|
177
|
+
|
|
178
|
+
Registers one `ctx.codeRuntime` implementation. Program, budget, abort, and substrate failures resolve in CodeRunResult; only Service Definition contract misuse rejects. Implementations bridge structured-cloneable bindings, materialize each declared namespace rejection class, treat programs as hostile peers, isolate runs from one another, and terminate and await in-flight runs during disposal.
|
|
179
|
+
|
|
180
|
+
```ts cordis-catalog
|
|
181
|
+
/**
|
|
182
|
+
* Execute one program against the request's bindings and capture what it
|
|
183
|
+
* emitted. See the class doc for the resolution contract (error is a result
|
|
184
|
+
* field; rejection means Service Definition contract misuse only).
|
|
185
|
+
* @param request - the program, its bindings, and the abort signal; the
|
|
186
|
+
* request carries everything the runtime acts on, with no hidden defaults.
|
|
187
|
+
* @returns the run's outcome: completion value (when transferable), the
|
|
188
|
+
* ordered log capture, and the failure (if any).
|
|
189
|
+
*/
|
|
190
|
+
abstract run(request: CodeRunRequest): Promise<CodeRunResult>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Source: [`packages/code-runtime/code-runtime/src/index.ts:102`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/code-runtime/code-runtime/src/index.ts)
|
|
194
|
+
<!-- END GENERATED cordis-surface -->
|