dsh-plugin-dev-kb 1.0.9 → 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 +26 -0
- package/README.en.md +14 -8
- package/README.md +14 -8
- package/docs/banner.svg +25 -0
- package/kb/INDEX.md +8 -2
- package/kb/README.md +4 -4
- package/kb/extra/AGENTS.md +3 -3
- package/kb/extra/cookbook/adding-a-remote-api.md +197 -0
- package/kb/extra/cookbook/adding-a-remote-api.zh.md +197 -0
- 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 +19 -15
- package/kb/extra/deepseek-llm-api-wire-extensions.zh.md +19 -15
- package/kb/extra/development.md +13 -3
- package/kb/extra/development.zh.md +13 -3
- package/kb/extra/event-producer-consumer.md +49 -46
- package/kb/extra/event-producer-consumer.zh.md +52 -49
- package/kb/extra/i18n/README.md +2 -1
- package/kb/extra/i18n/README.zh.md +3 -2
- package/kb/extra/i18n/style-samples.md +2 -2
- package/kb/extra/i18n/translation-prompt.md +1 -1
- package/kb/extra/module-graph.md +493 -1002
- package/kb/extra/module-graph.zh.md +495 -1004
- 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 +3 -2
- package/kb/extra/subsystems/agent-team.zh.md +3 -2
- package/kb/extra/subsystems/attachment.md +157 -4
- package/kb/extra/subsystems/attachment.zh.md +157 -4
- package/kb/extra/subsystems/feedback.md +164 -30
- package/kb/extra/subsystems/feedback.zh.md +164 -30
- package/kb/extra/testing.md +9 -4
- package/kb/extra/testing.zh.md +9 -4
- package/kb/extra/web-styling.md +5 -0
- package/kb/extra/web-styling.zh.md +5 -0
- package/kb/meta/search-index.json +223 -151
- package/kb/meta/site-pages.txt +187 -181
- package/kb/meta/source.json +5 -5
- package/kb/meta/topics.md +5 -5
- package/kb/site/develop/basic/publish.md +1 -1
- package/kb/site/develop/cordis-tutorial/07-into-the-harness.md +3 -2
- package/kb/site/develop/practice/llm-adapter.md +4 -3
- package/kb/site/en/develop/basic/publish.md +1 -1
- package/kb/site/en/develop/cordis-tutorial/07-into-the-harness.md +3 -2
- package/kb/site/en/develop/practice/llm-adapter.md +4 -3
- package/kb/site/en/guide/network-proxy.md +87 -0
- package/kb/site/en/guide/providers.md +70 -17
- package/kb/site/en/guide/python-sdk.md +19 -3
- package/kb/site/en/guide/schedule.md +2 -0
- package/kb/site/en/reference/agent-lifecycle.md +17 -8
- package/kb/site/en/reference/api-gateway.md +2 -2
- package/kb/site/en/reference/capability-seams.md +24 -10
- package/kb/site/en/reference/config-catalog.md +322 -264
- package/kb/site/en/reference/cookbook/adding-a-package.md +1 -2
- package/kb/site/en/reference/cookbook/adding-a-settings-card.md +10 -8
- package/kb/site/en/reference/cookbook/adding-a-tool.md +1 -1
- package/kb/site/en/reference/cookbook/extension-cookbook.md +16 -13
- package/kb/site/en/reference/index.md +26 -9
- package/kb/site/en/reference/persistence-catalog.md +189 -95
- 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/code-runtime.md +7 -3
- package/kb/site/en/reference/subsystems/commands.md +25 -16
- package/kb/site/en/reference/subsystems/compaction.md +10 -10
- package/kb/site/en/reference/subsystems/conversation.md +11 -4
- package/kb/site/en/reference/subsystems/core.md +173 -29
- package/kb/site/en/reference/subsystems/credentials.md +5 -4
- package/kb/site/en/reference/subsystems/filesystem.md +15 -0
- package/kb/site/en/reference/subsystems/goal.md +38 -2
- package/kb/site/en/reference/subsystems/index.md +3 -1
- package/kb/site/en/reference/subsystems/invariants.md +1 -1
- package/kb/site/en/reference/subsystems/llm-streaming.md +43 -12
- package/kb/site/en/reference/subsystems/lsp.md +1 -1
- package/kb/site/en/reference/subsystems/permission-presets.md +5 -5
- package/kb/site/en/reference/subsystems/persistence.md +211 -199
- package/kb/site/en/reference/subsystems/plan.md +3 -3
- package/kb/site/en/reference/subsystems/sandbox.md +2 -0
- package/kb/site/en/reference/subsystems/schedule.md +9 -3
- package/kb/site/en/reference/subsystems/scope.md +1 -1
- package/kb/site/en/reference/subsystems/session-projection.md +50 -24
- package/kb/site/en/reference/subsystems/session-query.md +19 -13
- package/kb/site/en/reference/subsystems/session-reference.md +29 -1
- package/kb/site/en/reference/subsystems/session-telemetry.md +27 -10
- package/kb/site/en/reference/subsystems/session-title.md +6 -6
- package/kb/site/en/reference/subsystems/session.md +208 -103
- package/kb/site/en/reference/subsystems/settings.md +30 -12
- 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/skills.md +1 -1
- package/kb/site/en/reference/subsystems/slots.md +41 -32
- package/kb/site/en/reference/subsystems/spill.md +13 -6
- package/kb/site/en/reference/subsystems/storage.md +28 -5
- package/kb/site/en/reference/subsystems/subagent.md +58 -105
- package/kb/site/en/reference/subsystems/subprocess.md +25 -26
- package/kb/site/en/reference/subsystems/system-prompt.md +18 -3
- package/kb/site/en/reference/subsystems/token-meter.md +4 -3
- package/kb/site/en/reference/subsystems/tools.md +5 -5
- package/kb/site/en/reference/subsystems/typert.md +18 -18
- package/kb/site/en/reference/subsystems/web-client.md +1 -1
- package/kb/site/en/reference/subsystems/workspace.md +88 -9
- package/kb/site/en/reference/tool-catalog.md +56 -66
- package/kb/site/en/reference/tool-execution-pipeline.md +2 -2
- package/kb/site/guide/network-proxy.md +87 -0
- package/kb/site/guide/providers.md +70 -17
- package/kb/site/guide/python-sdk.md +19 -3
- package/kb/site/guide/schedule.md +2 -0
- package/kb/site/reference/agent-lifecycle.md +17 -8
- package/kb/site/reference/api-gateway.md +2 -2
- package/kb/site/reference/capability-seams.md +24 -10
- package/kb/site/reference/config-catalog.md +321 -263
- package/kb/site/reference/cookbook/adding-a-package.md +1 -2
- package/kb/site/reference/cookbook/adding-a-settings-card.md +10 -8
- package/kb/site/reference/cookbook/adding-a-tool.md +1 -1
- package/kb/site/reference/cookbook/extension-cookbook.md +16 -13
- package/kb/site/reference/index.md +26 -9
- package/kb/site/reference/persistence-catalog.md +190 -96
- 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/code-runtime.md +7 -3
- package/kb/site/reference/subsystems/commands.md +25 -16
- package/kb/site/reference/subsystems/compaction.md +10 -10
- package/kb/site/reference/subsystems/conversation.md +11 -4
- package/kb/site/reference/subsystems/core.md +173 -29
- package/kb/site/reference/subsystems/credentials.md +5 -4
- package/kb/site/reference/subsystems/filesystem.md +15 -0
- package/kb/site/reference/subsystems/goal.md +38 -2
- 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 +43 -12
- package/kb/site/reference/subsystems/lsp.md +1 -1
- package/kb/site/reference/subsystems/permission-presets.md +5 -5
- package/kb/site/reference/subsystems/persistence.md +210 -198
- package/kb/site/reference/subsystems/plan.md +3 -3
- package/kb/site/reference/subsystems/schedule.md +9 -3
- package/kb/site/reference/subsystems/scope.md +1 -1
- package/kb/site/reference/subsystems/session-projection.md +50 -24
- package/kb/site/reference/subsystems/session-query.md +19 -13
- package/kb/site/reference/subsystems/session-reference.md +29 -1
- package/kb/site/reference/subsystems/session-telemetry.md +27 -10
- package/kb/site/reference/subsystems/session-title.md +6 -6
- package/kb/site/reference/subsystems/session.md +208 -103
- package/kb/site/reference/subsystems/settings.md +30 -12
- package/kb/site/reference/subsystems/shell.md +9 -6
- package/kb/site/reference/subsystems/sidebar-right.md +151 -0
- package/kb/site/reference/subsystems/skills.md +1 -1
- package/kb/site/reference/subsystems/slots.md +41 -32
- package/kb/site/reference/subsystems/spill.md +13 -6
- package/kb/site/reference/subsystems/storage.md +28 -5
- package/kb/site/reference/subsystems/subagent.md +58 -105
- package/kb/site/reference/subsystems/subprocess.md +25 -26
- package/kb/site/reference/subsystems/system-prompt.md +18 -3
- package/kb/site/reference/subsystems/token-meter.md +4 -3
- package/kb/site/reference/subsystems/tools.md +5 -5
- package/kb/site/reference/subsystems/typert.md +18 -18
- package/kb/site/reference/subsystems/web-client.md +1 -1
- package/kb/site/reference/subsystems/workspace.md +88 -9
- package/kb/site/reference/tool-catalog.md +55 -65
- 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 +4 -4
|
@@ -24,7 +24,7 @@ packages/<group>/<pkg>/
|
|
|
24
24
|
|
|
25
25
|
Choose an existing group when one matches the package's role (`core`, `llm`, `shell`, `compaction`, `subagent`, `todo`, `session`, `client`/`host`, `util`, or `test-support`). A new group is allowed, but it is a pure container: no `package.json`, no source files, and packages still sit exactly one level below it.
|
|
26
26
|
|
|
27
|
-
package.json invariants (enforced by `pnpm run constraints` / `scripts/check-workspace-constraints.ts`): `private: true`, a `version` matching the root `package.json`, `type: module`, `main: "lib/index.js"`, `types: "lib/types/index.d.ts"`, `exports["."].types: "./lib/types/index.d.ts"`, `exports["."].default: "./lib/index.js"`, `@deepseek-ai/cordis` in BOTH peerDependencies and devDependencies (same range). Mirror every dsh peer dependency in devDependencies. `@deepseek-ai/schemastery` goes in `dependencies` (it is a runtime validator), matching agent-loop. The `files` list contains exactly `lib/index.js`, `lib/
|
|
27
|
+
package.json invariants (enforced by `pnpm run constraints` / `scripts/check-workspace-constraints.ts`): `private: true`, a `version` matching the root `package.json`, `type: module`, `main: "lib/index.js"`, `types: "lib/types/index.d.ts"`, `exports["."].types: "./lib/types/index.d.ts"`, `exports["."].default: "./lib/index.js"`, `@deepseek-ai/cordis` in BOTH peerDependencies and devDependencies (same range). Mirror every dsh peer dependency in devDependencies. `@deepseek-ai/schemastery` goes in `dependencies` (it is a runtime validator), matching agent-loop. The `files` list contains exactly `lib/index.js`, `lib/types/**/*.d.ts`, and package-specific runtime artifacts recognized by the gate; a package that publishes `./invariant` also includes `lib/invariant.js`. A package whose runtime export points into the emitted tree also includes `lib/types/**/*.js`. Do not publish `src`, declaration maps, JS maps, or stale root declaration files. CLI app packages with a package `bin` include `lib/bin.js` immediately after `lib/index.js` in `files`.
|
|
28
28
|
|
|
29
29
|
In-package relative imports use explicit `.ts` specifiers in source (for example, `export * from './types.ts'`). The compiler rewrites those to `.js` in emitted JS and leaves explicit `.ts` specifiers in declarations, which standard NodeNext/Node16 TypeScript consumers resolve to the sibling `.d.ts` files.
|
|
30
30
|
|
|
@@ -34,7 +34,6 @@ In-package relative imports use explicit `.ts` specifiers in source (for example
|
|
|
34
34
|
|---|---|
|
|
35
35
|
| `tsconfig.base.json` | no edit for an existing group; for a new group, add a `./packages/<group>/*/src` candidate to the `@deepseek-ai/dsh-*` wildcard |
|
|
36
36
|
| `tsconfig.host.json` (Host package) or `tsconfig.client.json` (Client package) | add `{ "path": "./packages/<group>/<pkg>" }` to `references` — an ordinary package belongs to exactly one aggregate, never both. `api/remotes` uses a repository-specific split because the Host generates a contract that the Client consumes in a later phase; new packages must not copy it ([layout](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/development.md#typescript-project-layout)) |
|
|
37
|
-
| `knip.json` | only if the package has entrypoints that repository discovery does not already cover |
|
|
38
37
|
|
|
39
38
|
A `packages/client/*` package additionally extends `tsconfig.base.client.json` instead of `tsconfig.base.json`, and a client plugin package declares `dsh.client` in package.json, exports `./client`, and calls the shared tsdown preset (`packages/client/tsdown.client.ts`) — see [packages/client/AGENTS.md](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/AGENTS.md) for the client-side contract.
|
|
40
39
|
|
|
@@ -10,17 +10,17 @@ The two halves live in one package — the Host half under `src/`, the browser h
|
|
|
10
10
|
|
|
11
11
|
## 1. Register the namespace (Host half)
|
|
12
12
|
|
|
13
|
-
The namespace is the join key, so pick it once and spell it in both halves. A consumer that already has a `cordis.yml` entry should register through `
|
|
13
|
+
The namespace is the join key, so pick it once and spell it in both halves. A consumer that already has a `cordis.yml` entry should register through `ctx.settings.installSection()`, which layers the entry under the user document and keeps working when no settings provider is mounted:
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
16
|
import type { Context } from '@deepseek-ai/cordis'
|
|
17
|
-
import {
|
|
17
|
+
import type {} from '@deepseek-ai/dsh-settings'
|
|
18
18
|
import z from '@deepseek-ai/schemastery'
|
|
19
19
|
|
|
20
20
|
declare function assertReachable(endpoint: string | undefined): void
|
|
21
21
|
declare function rebuildFromSettings(config: Config): void
|
|
22
22
|
|
|
23
|
-
export const MY_PLUGIN_NS =
|
|
23
|
+
export const MY_PLUGIN_NS = 'my-plugin'
|
|
24
24
|
|
|
25
25
|
export interface Config {
|
|
26
26
|
endpoint?: string
|
|
@@ -34,11 +34,13 @@ export const Config: z<Config> = z.object({
|
|
|
34
34
|
|
|
35
35
|
export function apply(ctx: Context, config: Config) {
|
|
36
36
|
let source = () => config
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
ctx.inject(['settings'], (settingsCtx) => {
|
|
38
|
+
settingsCtx.settings.installSection(ctx, MY_PLUGIN_NS, Config, config, {
|
|
39
|
+
// Constraints the schema cannot express refuse the write, not the next use.
|
|
40
|
+
validate: value => void assertReachable(value.endpoint),
|
|
41
|
+
setSource: (current) => { source = current },
|
|
42
|
+
onChange: () => { rebuildFromSettings(source()) },
|
|
43
|
+
})
|
|
42
44
|
})
|
|
43
45
|
}
|
|
44
46
|
```
|
|
@@ -41,7 +41,7 @@ Registration is effect-based: disposing the plugin fiber unregisters the tool. S
|
|
|
41
41
|
|
|
42
42
|
## Rules of the execute() contract
|
|
43
43
|
|
|
44
|
-
- **Args are validated for you.** `defineTool` validates model-generated `arguments` against the unified `ParameterSchemaSpec` before `execute` runs (types, required keys, literal constraints, exact-one unions, and nested values
|
|
44
|
+
- **Args are validated for you.** `defineTool` validates model-generated `arguments` against the unified `ParameterSchemaSpec` before `execute` runs (types, required keys, literal constraints, exact-one unions, and nested values), so inside `execute` the args match `InferArgs`. Explicit object nodes declare `additionalProperties: true | false`; the implicit parameter root stays open. You still hand-check constraints the DSL does not express, such as non-empty strings, positive numbers, or cross-field rules. Raw JSON-Schema tools registered directly own their input validation.
|
|
45
45
|
- **Registration borrows your readonly definition.** A typed same-process contribution is not a serialization boundary; do not mutate its schema or replace callbacks after registration. `schemas()` materializes only the explicit model-facing projection. To hot-swap a tool, dispose its owning effect and register the replacement; mutable state inside the callback's closure remains ordinary plugin state.
|
|
46
46
|
- **Execution identity is protected.** The registry materializes `arguments` as detached lossless JSON in one recursive pass, freezes that value before policy starts, and assigns an opaque `exec.token`; `callId`, `name`, `arguments`, `agent`, `token`, the required caller-owned `signal`, and an optional enclosing-transport `parent` token stay immutable through dispatch. `parent` is identity-only and exposes no live outer execution. Treat `args` as readonly input. Only an around-dispatch wrapper receives a mutable view, and it may replace and restore the required `exec.signal` to impose a deadline but cannot remove it.
|
|
47
47
|
- **Declare and return one canonical JSON value.** `output.schema` uses `ValueSchemaSpec` and may have an object, array, scalar, or null root. `execute` returns only the inferred value; the registry snapshots it as lossless JSON, validates it, freezes it, and passes it to `output.render(args, value)`. Do not return content blocks from the body or make callers parse prose for ids and fields.
|
|
@@ -4,7 +4,7 @@ editSource: "docs/cookbook/extension-cookbook.md"
|
|
|
4
4
|
|
|
5
5
|
# Cookbook: extension plugin shapes
|
|
6
6
|
|
|
7
|
-
Reference patterns for harness extensions. The snippets omit imports and helper implementations and are not copy-paste-complete. For concrete authoring paths, see the [package checklist](./adding-a-package.md), [first-tool tutorial](../../develop/basic/tool.md), [tool reference](./adding-a-tool.md),
|
|
7
|
+
Reference patterns for harness extensions. The snippets omit imports and helper implementations and are not copy-paste-complete. For concrete authoring paths, see the [package checklist](./adding-a-package.md), [first-tool tutorial](../../develop/basic/tool.md), [tool reference](./adding-a-tool.md), [LLM adapter guide](./adding-an-llm-adapter.md), and [Session format version tutorial](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/cookbook/adding-a-session-format-version.md); the [architecture](../index.md) owns the system and extension-point map.
|
|
8
8
|
|
|
9
9
|
## A tool plugin
|
|
10
10
|
|
|
@@ -36,12 +36,13 @@ This waterfall is the reorderable policy layer. Use `ctx.tools.guard()` when an
|
|
|
36
36
|
|
|
37
37
|
## A UI plugin
|
|
38
38
|
|
|
39
|
-
A UI plugin
|
|
39
|
+
A UI plugin combines durable `session/event` records (Assistant settlements, turn/step boundaries, and tool activity) with transient `agent/assistant-stream` frames for live token presentation, and drives input back in via `agent.followup()` / `agent.steer()`. A browser plugin contributing a business row to the built-in Web Client instead registers a `ConversationNodeDefinition` and keyed Chat renderer; follow the [Conversation subsystem reference](../subsystems/conversation.md).
|
|
40
40
|
|
|
41
41
|
```ts
|
|
42
42
|
import type { Context } from '@deepseek-ai/cordis'
|
|
43
|
+
import { brandString } from '@deepseek-ai/dsh-brand'
|
|
43
44
|
import { createUserMessage } from '@deepseek-ai/dsh-llm'
|
|
44
|
-
import { SessionId } from '@deepseek-ai/dsh-session'
|
|
45
|
+
import type { SessionId } from '@deepseek-ai/dsh-session'
|
|
45
46
|
|
|
46
47
|
declare function render(text: string): void
|
|
47
48
|
declare function onUserInput(handler: (text: string) => void): void
|
|
@@ -50,12 +51,12 @@ export const name = 'my-ui'
|
|
|
50
51
|
export const inject = ['agents']
|
|
51
52
|
|
|
52
53
|
export function apply(ctx: Context) {
|
|
53
|
-
ctx.on('
|
|
54
|
-
if (
|
|
55
|
-
render(
|
|
54
|
+
ctx.on('agent/assistant-stream', ({ frame }) => {
|
|
55
|
+
if (frame.type === 'chunk' && frame.chunk.type === 'text-delta') {
|
|
56
|
+
render(frame.chunk.text)
|
|
56
57
|
}
|
|
57
58
|
})
|
|
58
|
-
onUserInput(text => ctx.agents.get(SessionId('client-session'))?.followup(createUserMessage({
|
|
59
|
+
onUserInput(text => ctx.agents.get(brandString<SessionId>('client-session'))?.followup(createUserMessage({
|
|
59
60
|
content: [{ type: 'text', text }],
|
|
60
61
|
source: { kind: 'user' },
|
|
61
62
|
})))
|
|
@@ -70,17 +71,19 @@ A *protocol driver* adapts a wire peer to `ctx.agents`; it may serve a UI or an
|
|
|
70
71
|
|
|
71
72
|
```ts
|
|
72
73
|
import type { Context } from '@deepseek-ai/cordis'
|
|
74
|
+
import { expandAssistantStream } from '@deepseek-ai/dsh-llm'
|
|
73
75
|
|
|
74
76
|
export const name = 'my-protocol-bridge'
|
|
75
77
|
export const inject = ['agents', 'sessions', 'sessionPersistence']
|
|
76
78
|
|
|
77
79
|
export function apply(ctx: Context) {
|
|
78
|
-
//
|
|
80
|
+
// Publish every committed Assistant text delta to the client.
|
|
79
81
|
ctx.on('session/event', (_session, event) => {
|
|
80
|
-
if (event.type === 'assistant/
|
|
81
|
-
const chunk
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
if (event.type === 'assistant/message' || event.type === 'assistant/attempt') {
|
|
83
|
+
for (const { chunk } of expandAssistantStream(event.data.stream)) {
|
|
84
|
+
if (chunk.type === 'text-delta') {
|
|
85
|
+
// sendToClient({ kind: 'message_chunk', text: chunk.text })
|
|
86
|
+
}
|
|
84
87
|
}
|
|
85
88
|
}
|
|
86
89
|
})
|
|
@@ -124,7 +127,7 @@ Every product feature maps to a listener on a documented extension point — the
|
|
|
124
127
|
| Skills | section + tool registration; `inject()` skill content on invocation |
|
|
125
128
|
| Memory | section provider + tool |
|
|
126
129
|
| Scheduled tasks (cron) | a plugin registers model-callable scheduling tools; timer fires → `followup(…, {source: {kind: 'plugin', plugin: 'schedule'}})` when idle / `inject()` notification when busy |
|
|
127
|
-
| UI (GUI; CLI emits JSONL) | listen `session/event`
|
|
130
|
+
| UI (GUI; CLI emits JSONL) | listen to `agent/assistant-stream` for live chunks and `session/event` for durable settlements, boundaries, and tool activity; input → `followup()` |
|
|
128
131
|
| Web Client Chat business node | register a `ConversationNodeDefinition` and `conversation.chat.node` keyed renderer |
|
|
129
132
|
| SessionTelemetryBackend / replayable trace | `session/event` → JSONL; replay = `sessions.create(id, { seed })` |
|
|
130
133
|
| Model adapters | `LlmAdapter` subclass via `registerAdapter` (`dsh-llm-deepseek`, `dsh-llm-pi-ai`) |
|
|
@@ -48,6 +48,12 @@ Vendored CLIs, build-only and test-only executables, direct in-process plugin mo
|
|
|
48
48
|
|
|
49
49
|
The Python SDK follows the same application architecture. Its runtime wheel packages the normal `dsh` CLI as `deepseek-harness-sdk-runtime-<platform>-<arch>`, and the client launches `dsh --profile sdk` with an explicit Harness home by default. The minimal example selects the shipped `sdk-minimal` profile. Python exposes profile selection and ordered patch files rather than a complete Cordis tree; persistent external plugins are installed through `dsh plugin`. The removed private direct-config carrier has no compatibility bin or fallback parser.
|
|
50
50
|
|
|
51
|
+
## Desktop application
|
|
52
|
+
|
|
53
|
+
The [Electron desktop application](https://github.com/deepseek-ai/deepseek-harness/blob/master/apps/desktop/README.md) owns the reserved `$DSH_HOME/profiles/desktop` npm project. Each signed Electron release binds one exact dsh version and carries a first-party offline seed; startup installs that version into the writable profile with the bundled pnpm, while retaining exact desktop-plugin versions from the previous profile. CLI profiles share supported product data under `$DSH_HOME`, but never executable packages, plugin activation, lockfiles, or `node_modules` with Desktop.
|
|
54
|
+
|
|
55
|
+
Electron starts the private Desktop Host package under its bundled upstream Node.js process; that package loads the installed dsh backend and matching client graph from the reserved profile. Unary RPC, Remote streams, and version-matched client assets cross versioned framed byte pipes with Node IPC reserved for lifecycle control, then reach the renderer through the secure `dsh-app://` protocol; the desktop composition opens no Web server or loopback port. Only shell-owned UI can run plugin transactions through the bundled pnpm and its private `$DSH_HOME/desktop/pnpm/store`.
|
|
56
|
+
|
|
51
57
|
## Core packages
|
|
52
58
|
|
|
53
59
|
Here are some core packages that contribute to the Cordis tree.
|
|
@@ -80,13 +86,17 @@ A **step** is one model request plus the tools it calls. A **turn** is zero or m
|
|
|
80
86
|
```text
|
|
81
87
|
turn/start
|
|
82
88
|
claim next-step input plus one queued message
|
|
83
|
-
assemble prompt sections + tool schemas
|
|
89
|
+
assemble prompt sections + tool schemas; project runtime context
|
|
84
90
|
-> agent/pre-step reject | enter(messages, startsRequestSeries?)
|
|
85
91
|
reject, or a first enter rewritten empty -> close the turn with no step
|
|
86
92
|
step/start
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
93
|
+
agent/request -> prepareCall (cancellation commits neither system nor users)
|
|
94
|
+
reconcile system/message using the prepared call capability
|
|
95
|
+
append entered messages as user/message; log request/header and request/context as needed
|
|
96
|
+
derive and freeze model history from the log
|
|
97
|
+
stream the bound prepared call -> llm/stream -> agent/assistant-stream start
|
|
98
|
+
agent/assistant-stream chunk*
|
|
99
|
+
assistant/message | assistant/attempt -> agent/assistant-stream end
|
|
90
100
|
tool/call* -> tools/pre-execute -> tools/execute -> tools/post-execute -> tool/result*
|
|
91
101
|
step/end
|
|
92
102
|
tools owe another request, or next-step input arrived -> claim -> next step
|
|
@@ -94,27 +104,33 @@ turn/start
|
|
|
94
104
|
turn/end
|
|
95
105
|
```
|
|
96
106
|
|
|
97
|
-
`turn/*`, `step/*`, `user/message`, `assistant
|
|
107
|
+
`turn/*`, `step/*`, `system/message`, `user/message`, `assistant/message`, `assistant/attempt`, and `tool/*` are durable session events; the rest are live extension points across three domains. `agent/assistant-stream` publishes process-local start, transient chunk, and end frames. The loop commits the complete compact stream as one message or log-only attempt before a committed end frame, and the Web Session-follow adapter is the live event's only remote consumer. `agent/pre-step`, `agent/request`, `llm/stream`, and the three `tools/*` events are waterfalls, whose listeners must call `next()` to delegate; `agent/turn-stopping` is serial and has no `next()`.
|
|
98
108
|
|
|
99
109
|
Input reaches the driver through one inbox. Some messages wake it immediately; injected context waits in the inbox until another message does.
|
|
100
110
|
|
|
101
|
-
`agent/pre-step` decides
|
|
111
|
+
`agent/pre-step` decides the accepted input. Listeners may rewrite or reject claimed messages; a rejected or empty first claim closes a durable turn without a step. An enter decision may set `startsRequestSeries`: the loop logs a fresh `request/header` (reason `series`, or `change` with `startsSeries: true` when the envelope also changed). Wrapping listeners preserve that declaration with `{ ...decision, messages }`. After assembly and `step/start`, `agent/request` and `prepareCall()` resolve the actual route before the system prompt and accepted users are committed; cancellation during either async phase commits neither. The prepared call capability governs prompt admission, not the preceding `request/context`. Every attempt synchronously reconciles the same rendered assembly, appends users only on the first attempt, logs header/context as needed, and derives and freezes the request before streaming the bound call. Retries do not repeat assembly or `agent/pre-step`. Surface replacements after attachment start a new request series, including during the first resumed pre-step; unchanged resume continues the series. The first admitted step reserves the system head before user messages even for an empty prompt (no wire message). The prompt travels only as `system/message` history: an empty rendering clears all active system nodes, leaving no old prompt model-visible; capable routes can append non-empty updates after the cached prefix; incapable routes and new request series consolidate non-empty prompt text at the first system node, with logged empty replacements for non-empty later system nodes ([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)).
|
|
112
|
+
|
|
113
|
+
The loop sends immutable requests while keeping cancellation live. It reuses message-freeze provenance only for identities it has fully frozen; [agent-loop](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent-loop/README.md) owns the request construction rules.
|
|
102
114
|
|
|
103
115
|
Details: the [sequence diagram](./agent-lifecycle.md), the [tool pipeline](./tool-execution-pipeline.md), and [cancellation and error recovery](./subsystems/core.md#the-agent-handle).
|
|
104
116
|
|
|
105
117
|
## Session log
|
|
106
118
|
|
|
107
|
-
The session log is the source of the context the model sees. `deriveMessages()` projects model history from it
|
|
119
|
+
The session log is the source of the context the model sees. `deriveMessages()` projects model history from it. Each `assistant/message` embeds the exact compact timed stream that produced its assembled content; `assistant/attempt` retains settled failed, retried, cancelled, and stream-error attempts without adding model history. Fork, resume, transcripts, telemetry, and persistence all derive from these durable settlements, while live UI incrementality comes from `agent/assistant-stream`; a hard process loss before settlement leaves no durable attempt stream ([decision](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-09-01-v2-embedded-assistant-streams.md)).
|
|
120
|
+
|
|
121
|
+
Session consumers know only the current logical format. Header-only `stat` and `list` rescan each Session directory, select its numerically highest canonical generation, and translate a supported historical header without loading events or publishing a successor. A stored-session `open` selects that same generation, refuses a future version, or decodes and composes the static adjacent migration chain once before returning validated current logical events. A read open uses that in-memory result without publishing a successor; a write open first encodes, verifies, and exclusively publishes the final version-named successor beside the unchanged source. Ordinary repair of an unsealed interrupted tail remains a handle consumer responsibility; migration inserts a missing interrupted `turn/end` only for the bounded released restart already sealed by a later `turn/start`. JSONL v0 uses `session.jsonl[.zstd]`, v1 and later use lowercase `session.vN.jsonl[.zstd]`, and committed generation paths are never renamed, replaced, or deleted. The JSONL provider owns physical framing, compression, generation selection, and exclusive publication, while each adjacent migration package owns exactly one `vN -> vN+1` step ([decision](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md)).
|
|
108
122
|
|
|
109
123
|
**Model-visible means logged.** Anything that reaches a model request must be reconstructable from the log, and a runtime invariant asserts it. This is why a new model-visible input requires a new session event: extend `SessionEventMap` and render from the log.
|
|
110
124
|
|
|
125
|
+
**Projection seam.** `dsh-session-projection` owns `ctx.sessionProjections`: registered units fold committed events incrementally, host consumers read one typed state with `stateOf()`, and carriers batch cropped client views with `snapshot()`. A host reader either requires this service during activation or fails explicitly when the registry or required key is absent. Contributors may retain `ctx.inject(['sessionProjections'], ...)` registration without silently defaulting a missing host value. The agent loop registers shared `turnBoundary` state for its readers ([decision](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-19-session-projection-mandatory-seam.md)).
|
|
126
|
+
|
|
111
127
|
## Capability seams
|
|
112
128
|
|
|
113
129
|
A **seam** is a swappable capability with three roles: a **Service Definition** declaring the interface, a **Service Provider** implementing it, and a **Consumer** using it, commonly a model-facing tool. A package may combine roles, but one role alone is not a seam; adding a capability means designing all three ([capability graph](./capability-seams.md)).
|
|
114
130
|
|
|
115
131
|
Seams are why one provider swap changes the whole product. Filesystem and subprocess providers share one execution world, so pointing them at a remote sandbox moves Bash, PTY, and LSP with them, with no provider forks. [Subagent providers](./subsystems/subagent.md) vary just as widely behind one interface, from a fresh child agent to a delegated turn in another product.
|
|
116
132
|
|
|
117
|
-
[Experimental Agent Teams](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/agent-team.md) is a
|
|
133
|
+
[Experimental Agent Teams](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/agent-team.md) is a published opt-in coordination seam on `ctx.agentTeams`, with a durable roster, task board, and mailbox layered over continuable subagents.
|
|
118
134
|
|
|
119
135
|
## Where new behavior goes
|
|
120
136
|
|
|
@@ -139,7 +155,8 @@ New behavior attaches to a documented extension point. Changing the loop itself
|
|
|
139
155
|
| Add durable session state | extend `SessionEventMap`; render and replay from the log |
|
|
140
156
|
| Generate session titles | register the sole `ctx.sessionTitle` provider |
|
|
141
157
|
| Manage a same-session objective | use `ctx.goals`; continue through `agent/*` |
|
|
142
|
-
| Fork a
|
|
158
|
+
| Fork a session at a turn boundary | `ctx.agents.create({ sessionId, seed, meta: { parentSession, seedLength } })` — only agent-loop-published sessions persist |
|
|
159
|
+
| Store sessions in a new backend | implement `SessionPersistence` (`create`/`open`/`stat`/`list`/`export`) over the shared handle scaffolding |
|
|
143
160
|
| Scope a registration to one agent | use that agent's `agent.ctx` |
|
|
144
161
|
|
|
145
162
|
The [extension cookbook](./cookbook/extension-cookbook.md) maps features to capabilities and indexes the step-by-step guides for [packages](./cookbook/adding-a-package.md), [tools](./cookbook/adding-a-tool.md), [LLM adapters](./cookbook/adding-an-llm-adapter.md), and [settings cards](./cookbook/adding-a-settings-card.md). The [Conversation subsystem](./subsystems/conversation.md) owns Chat-node assembly.
|