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
|
@@ -49,9 +49,9 @@ interface AgentHandle {
|
|
|
49
49
|
}
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
`CreateAgentOptions` carries the shared identity and everything a fresh agent needs before publication: session metadata (`meta` — validated `cwd`, fork lineage, the `isSeeded` marker, origin classification, delegation depth, and `agentPreset`), the exact fork cut in sibling field `inheritedEventCount`, an optional `seed` replay prefix, per-agent `AgentOptions`, a creation-only cancellation `signal`, and `setup`. `ResumeAgentOptions` is the persisted-identity counterpart: `resumeSessionId`, `agentOptions`, `signal`, and `setup`. The `setup` callback (`AgentSetup`)
|
|
52
|
+
`CreateAgentOptions` carries the shared identity and everything a fresh agent needs before publication: an optional live `parentAgent`, session metadata (`meta` — validated `cwd`, fork lineage, the `isSeeded` marker, origin classification, delegation depth, and `agentPreset`), the exact fork cut in sibling field `inheritedEventCount`, an optional `seed` replay prefix, per-agent `AgentOptions`, a creation-only cancellation `signal`, and `setup`. `ResumeAgentOptions` is the persisted-identity counterpart: `resumeSessionId`, `parentAgent`, `agentOptions`, `signal`, and `setup`. The `setup` callback (`AgentSetup`) receives `(agentCtx, agent)` while both ids are still unpublished: the context owns scoped registrations, while the explicit Agent supplies the exact child Session without a reverse property on the Context. Everything registered through `agentCtx` exists before `agent/created` and the first prompt assembly. Setup may return a synchronous commit invoked immediately before publication; a setup rejection, commit throw, or owner disposal rolls the transaction back without publishing either id.
|
|
53
53
|
|
|
54
|
-
`AgentFactory` is the creation interface behind the registry: the loop registers its factory via `ctx.agents.setFactory()`, so consumers use `ctx.agents` without depending on the concrete loop package. The exact `create`/`resume` signatures and rollback contracts are in the [generated section](#ctxagents--agentregistry) below.
|
|
54
|
+
`AgentFactory` is the creation interface behind the registry: the loop registers its factory via `ctx.agents.setFactory()`, so consumers use `ctx.agents` without depending on the concrete loop package. A runtime child creator sets `options.parentAgent`; the registry passes the options and caller Context to the factory without deriving one from the other. The exact `create`/`resume` signatures and rollback contracts are in the [generated section](#ctxagents--agentregistry) below.
|
|
55
55
|
|
|
56
56
|
## The agent handle
|
|
57
57
|
|
|
@@ -68,7 +68,7 @@ interface Agent {
|
|
|
68
68
|
readonly options: AgentOptions
|
|
69
69
|
/** The live session this agent drives; its log is the durable source of truth. */
|
|
70
70
|
readonly session: Session
|
|
71
|
-
/**
|
|
71
|
+
/** Agent-owned access to durable pending work. */
|
|
72
72
|
readonly inbox: Inbox
|
|
73
73
|
/** The current lifecycle state, mirrored on every `agent/status` transition. */
|
|
74
74
|
readonly status: AgentStatus
|
|
@@ -209,16 +209,73 @@ interface AgentOptions {
|
|
|
209
209
|
}
|
|
210
210
|
```
|
|
211
211
|
|
|
212
|
-
Dispatch requires `provider` and `model` after `agent/request`. An explicit `reasoningEffort` seeds the first request on that route; exact-model resolution validates it, while omission allows the adapter default to materialize. When present, `maxTokens` must be a positive safe integer and caps every conversation-model request; omission allows the exact-model adapter default to materialize before the request header, or otherwise leaves provider behavior unchanged. An agent-scoped `deployment:persona` prompt section may shadow the global default persona.
|
|
212
|
+
Dispatch requires `provider` and `model` after `agent/request`. An explicit `reasoningEffort` seeds the first request on that route; exact-model resolution validates it, while omission allows the adapter default to materialize. When present, `maxTokens` must be a positive safe integer and caps every conversation-model request; omission allows the exact-model adapter default to materialize before the request header, or otherwise leaves provider behavior unchanged. An agent-scoped `deployment:persona-prefix` prompt section may shadow the global default persona.
|
|
213
213
|
|
|
214
214
|
The inbox is the delivery vocabulary — two ordered pending-message lists the agent owns as a durable projection:
|
|
215
215
|
|
|
216
|
+
```ts type-equiv
|
|
217
|
+
/** Agent-owned access to pending work; concrete storage belongs to the driver. */
|
|
218
|
+
interface Inbox {
|
|
219
|
+
/** Prompts awaiting individual turns. */
|
|
220
|
+
readonly nextTurn: readonly UserMessage[]
|
|
221
|
+
/** Input awaiting the next step boundary. */
|
|
222
|
+
readonly nextStep: readonly UserMessage[]
|
|
223
|
+
|
|
224
|
+
/** Durably cancel all pending input, clearing next-step before next-turn. */
|
|
225
|
+
clear(): void
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Append one message to a pending list.
|
|
229
|
+
* @param target - pending list to extend.
|
|
230
|
+
* @param message - message to append.
|
|
231
|
+
*/
|
|
232
|
+
append(target: InboxTarget, message: UserMessage): void
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Prepend one message to a pending list.
|
|
236
|
+
* @param target - pending list to extend.
|
|
237
|
+
* @param message - message to prepend.
|
|
238
|
+
*/
|
|
239
|
+
prepend(target: InboxTarget, message: UserMessage): void
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Replace one pending message in place.
|
|
243
|
+
* @param messageId - identity of the pending message to replace.
|
|
244
|
+
* @param newMessage - replacement message.
|
|
245
|
+
* @returns whether the message was still pending.
|
|
246
|
+
*/
|
|
247
|
+
replace(messageId: MessageId, newMessage: UserMessage): boolean
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Remove one pending message.
|
|
251
|
+
* @param messageId - identity of the pending message to remove.
|
|
252
|
+
* @returns whether the message was still pending.
|
|
253
|
+
*/
|
|
254
|
+
remove(messageId: MessageId): boolean
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Apply standard splice semantics and durably record the normalized result.
|
|
258
|
+
* @param target - pending list to mutate.
|
|
259
|
+
* @param start - splice position.
|
|
260
|
+
* @param deleteCount - maximum number of messages to remove.
|
|
261
|
+
* @param inserted - messages to insert at the resolved position.
|
|
262
|
+
* @returns messages removed by the splice.
|
|
263
|
+
*/
|
|
264
|
+
splice(
|
|
265
|
+
target: InboxTarget,
|
|
266
|
+
start: number,
|
|
267
|
+
deleteCount: number,
|
|
268
|
+
inserted: UserMessage[],
|
|
269
|
+
): UserMessage[]
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
216
273
|
```ts type-equiv
|
|
217
274
|
/** One of the two ordered pending-message lists owned by an agent. */
|
|
218
275
|
type InboxTarget = 'next-turn' | 'next-step'
|
|
219
276
|
```
|
|
220
277
|
|
|
221
|
-
Every pending occurrence is its `UserMessage`; `MessageId` is the sole identity.
|
|
278
|
+
Every pending occurrence is its `UserMessage`; `MessageId` is the sole identity. The structural `Inbox` methods record normalized durable `agent/inbox/spliced` mutations and reject duplicate pending ids. `replace(messageId, newMessage)` and `remove(messageId)` locate the pending message across both lists; replacement may change identity and emits the old message as discarded followed by the new message as inserted. Ordinary removals and `clear()` are cancellations. At a step boundary, dsh-agent-loop's package-internal `ReactLoopInbox` removes the proposed batch — all `next-step` input plus, at a turn boundary, one `next-turn` message — through pure deletion splices without discarded notifications, then emits per-message claimed notifications. Loop-only pending detection and claiming are not part of `Agent.inbox`. Each `ReactLoopInbox` constructor contributes the standard `inbox` projection from its agent scope; the registry shares that definition across agents by reference count, and its cell is the sole live state while the same fold serves cold consumers. The fold rejects unsafe or out-of-range splice coordinates and duplicate identities across both lists, identifying malformed durable history by event seq. Consumers following one message use the exact `agent/inbox/inserted`, `claimed`, and `discarded` notifications.
|
|
222
279
|
|
|
223
280
|
Cancellation:
|
|
224
281
|
|
|
@@ -293,7 +350,7 @@ type SessionStartSource = 'startup' | 'resume' | 'clear' | 'compact'
|
|
|
293
350
|
|
|
294
351
|
A `Session` is an **append-only log** of typed `SessionEvent`s — the single source of truth. The LLM message history is *derived* from the log (`deriveMessages()`), not stored separately. Every entry carries a monotonic `seq`, a `time`, and a `type`-discriminated `data` payload; surface variants may also list cited earlier events in `sourceEventSeqs` and carry a `surfaceOp`.
|
|
295
352
|
|
|
296
|
-
The `SessionEvent` envelope's exact conditional fields, the
|
|
353
|
+
The `SessionEvent` envelope's exact conditional fields, the thirteen core event variants (`turn/start`, `turn/end`, `step/start`, `step/end`, `user/message`, `system/message`, `assistant/message`, `assistant/attempt`, `tool/call`, `tool/result`, `request/header`, `request/context`, `session/end-seed`), the `deriveMessages()` projection rules, the `TurnEndReason` reasons, and the execution-enclosure and standalone-event rules are on **[session.md](./session.md)**. How the log is made durable — the `SessionPersistence` interface, JSONL provider, `session/flush` checkpoint, crash recovery, and `SessionHeader` — is on **[persistence.md](./persistence.md)**.
|
|
297
354
|
|
|
298
355
|
## `ToolDefinition`
|
|
299
356
|
|
|
@@ -409,7 +466,7 @@ async create(id: SessionId, options: AgentOptions = {}, meta: Pick<SessionHeader
|
|
|
409
466
|
/**
|
|
410
467
|
* Create an owned agent on a caller-supplied session id.
|
|
411
468
|
* @param ownerCtx - caller context that structurally owns the lifecycle.
|
|
412
|
-
* @param options - identities, session seed/metadata, loop options, setup, and cancellation.
|
|
469
|
+
* @param options - identities, optional live parent, session seed/metadata, loop options, setup, and cancellation.
|
|
413
470
|
* @returns the published handle.
|
|
414
471
|
*/
|
|
415
472
|
async createAgent(ownerCtx: Context, options: CreateAgentOptions): Promise<AgentHandle>
|
|
@@ -417,7 +474,7 @@ async createAgent(ownerCtx: Context, options: CreateAgentOptions): Promise<Agent
|
|
|
417
474
|
/**
|
|
418
475
|
* Resume an owned agent from the configured persistence service.
|
|
419
476
|
* @param ownerCtx - caller context that owns load, setup, and the live lifecycle.
|
|
420
|
-
* @param options - persisted identity, loop options, setup, and cancellation.
|
|
477
|
+
* @param options - persisted identity, optional live parent, loop options, setup, and cancellation.
|
|
421
478
|
* @returns the published handle.
|
|
422
479
|
*/
|
|
423
480
|
async resume(ownerCtx: Context, options: ResumeAgentOptions): Promise<AgentHandle>
|
|
@@ -682,7 +739,8 @@ Initiator methods provide same-process causal attribution only. Ambient presence
|
|
|
682
739
|
* Read the Agent that initiated the inherited asynchronous driver chain.
|
|
683
740
|
* Use this optional form for logging, tracing, metrics, or host attribution
|
|
684
741
|
* that also supports agentless calls. When a parent creates a child, setup
|
|
685
|
-
* reports the causal parent while
|
|
742
|
+
* reports the causal parent while the setup callback's Agent parameter
|
|
743
|
+
* identifies the child.
|
|
686
744
|
* @returns the inherited Agent, or `undefined` outside an initiator boundary
|
|
687
745
|
* and inside an explicit clearing boundary.
|
|
688
746
|
* @throws when this service instance has been disposed.
|
|
@@ -747,7 +805,7 @@ setFactory(factory: AgentFactory): () => void
|
|
|
747
805
|
* agent): this constructs the agent and its session. Rejects if no factory is
|
|
748
806
|
* registered or creation/setup fails. The resolved {@link AgentHandle} lets
|
|
749
807
|
* the owner tear down exactly this agent.
|
|
750
|
-
* @param options - shared identity, session seed/metadata, and agent options.
|
|
808
|
+
* @param options - shared identity, optional live parent, session seed/metadata, and agent options.
|
|
751
809
|
* @returns the handle after setup, rollback-covered publication, and loop start complete.
|
|
752
810
|
*/
|
|
753
811
|
async create(options: CreateAgentOptions): Promise<AgentHandle>
|
|
@@ -756,7 +814,7 @@ async create(options: CreateAgentOptions): Promise<AgentHandle>
|
|
|
756
814
|
* Load a persisted session and resume an agent on it through the registered
|
|
757
815
|
* factory. Rejects if no factory is registered; the factory rejects if
|
|
758
816
|
* session persistence is not configured or persistence/setup fails.
|
|
759
|
-
* @param options - persisted identity, configuration, and
|
|
817
|
+
* @param options - persisted identity, optional live parent, configuration, and setup.
|
|
760
818
|
* @returns the handle after setup, rollback-covered publication, and loop start complete.
|
|
761
819
|
*/
|
|
762
820
|
async resume(options: ResumeAgentOptions): Promise<AgentHandle>
|
|
@@ -768,7 +826,8 @@ async resume(options: ResumeAgentOptions): Promise<AgentHandle>
|
|
|
768
826
|
* (`scopeTarget(agent, agent)`): the subject is the agent in hand, so the
|
|
769
827
|
* emits are scope-filtered regardless of which context invoked `register`
|
|
770
828
|
* (calling through `agent.ctx` scopes EFFECTS; dispatch scoping always
|
|
771
|
-
* requires passing the carrier).
|
|
829
|
+
* requires passing the carrier). The entry is a runtime root; factory-backed
|
|
830
|
+
* creation uses `options.parentAgent` for child ownership. Returns the disposer.
|
|
772
831
|
* @param agent - the already-constructed agent to record in the store.
|
|
773
832
|
* @returns the EXACT Cordis effect disposer (single-shot; a repeat call
|
|
774
833
|
* returns undefined without awaiting an in-flight teardown). Exact
|
|
@@ -788,7 +847,7 @@ register(agent: Agent): () => void
|
|
|
788
847
|
* returned detach closure into its pre-installed composite teardown before
|
|
789
848
|
* calling {@link announce}. Ordinary callers use {@link register}.
|
|
790
849
|
* @param agent - the prepared, unpublished agent.
|
|
791
|
-
* @param owner -
|
|
850
|
+
* @param owner - explicitly supplied live runtime owner, or
|
|
792
851
|
* undefined for a top-level runtime root. This is runtime ownership, not
|
|
793
852
|
* the resumed session's durable parent lineage.
|
|
794
853
|
* @returns an idempotent closure that removes this exact entry and emits
|
|
@@ -1033,14 +1092,18 @@ Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek
|
|
|
1033
1092
|
|
|
1034
1093
|
#### `agent/request` — waterfall
|
|
1035
1094
|
|
|
1036
|
-
Replace the frozen call configuration. `await next()` yields the config the machine would use (agent options on the first request, the logged header afterwards); return a replacement to switch. Model-visible content must use logged channels; this waterfall cannot mutate messages.
|
|
1095
|
+
Replace the frozen call configuration. `await next()` yields the config the machine would use (agent options on the first request, the logged header afterwards); return a replacement to switch. On step admission, this runs after assembly and `step/start`, before the system prompt and accepted user batch are committed. Cancellation here or during subsequent `prepareCall()` resolution commits neither. The prepared call capability governs prompt admission. Model-visible content must use logged channels; this waterfall cannot mutate messages.
|
|
1037
1096
|
|
|
1038
1097
|
```ts cordis-catalog
|
|
1039
1098
|
/**
|
|
1040
1099
|
* Replace the frozen call configuration. `await next()` yields the config
|
|
1041
1100
|
* the machine would use (agent options on the first request, the logged
|
|
1042
|
-
* header afterwards); return a replacement to switch.
|
|
1043
|
-
*
|
|
1101
|
+
* header afterwards); return a replacement to switch. On step admission,
|
|
1102
|
+
* this runs after assembly and `step/start`, before the system prompt and
|
|
1103
|
+
* accepted user batch are committed. Cancellation here or during subsequent
|
|
1104
|
+
* `prepareCall()` resolution commits neither. The prepared call capability
|
|
1105
|
+
* governs prompt admission. Model-visible content must use logged channels;
|
|
1106
|
+
* this waterfall cannot mutate messages.
|
|
1044
1107
|
* @param payload.agent - the agent making the model call.
|
|
1045
1108
|
* @param payload.turn - the open turn number.
|
|
1046
1109
|
* @param payload.step - the step whose request this is.
|
|
@@ -399,6 +399,21 @@ abstract streamText(target: FsTarget, signal?: AbortSignal): Promise<AsyncIterab
|
|
|
399
399
|
*/
|
|
400
400
|
abstract readBytes(target: FsTarget, signal: AbortSignal | undefined, maxBytes: number): Promise<Uint8Array>
|
|
401
401
|
|
|
402
|
+
/**
|
|
403
|
+
* Read one byte window of the regular file as raw bytes with no decoding or
|
|
404
|
+
* binary rejection: the bytes at `[offset, offset + length)`, shorter when
|
|
405
|
+
* the file ends inside the window and empty when `offset` lies at or past
|
|
406
|
+
* its end. The window is the bound here, not the file: a backend transfers
|
|
407
|
+
* at most `length` bytes of content beyond the prefix it skips to reach
|
|
408
|
+
* `offset` and never buffers the whole file, so the caller's cap on `length`
|
|
409
|
+
* is the guard against unbounded buffering.
|
|
410
|
+
* @param target - the resolved target to read.
|
|
411
|
+
* @param range - `offset`, the 0-based first byte, and `length`, the largest byte count; both non-negative integers.
|
|
412
|
+
* @param signal - aborts the read.
|
|
413
|
+
* @returns the window's bytes, at most `length` long.
|
|
414
|
+
*/
|
|
415
|
+
abstract readByteRange(target: FsTarget, range: { offset: number; length: number }, signal?: AbortSignal): Promise<Uint8Array>
|
|
416
|
+
|
|
402
417
|
/**
|
|
403
418
|
* List direct children of a directory in stable name order. Returns resolved
|
|
404
419
|
* child targets plus cheap metadata only; never reads file contents.
|
|
@@ -72,6 +72,25 @@ interface GoalView extends GoalSnapshot {
|
|
|
72
72
|
}
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
+
The service also publishes process-local activation edges without changing durable state; clients consume this event for live status.
|
|
76
|
+
|
|
77
|
+
```ts type-equiv
|
|
78
|
+
/** Live process-local activation update forwarded to UI clients. */
|
|
79
|
+
interface GoalActivationChanged {
|
|
80
|
+
/** Session whose live goal activation changed. */
|
|
81
|
+
readonly sessionId: SessionId
|
|
82
|
+
/** Current exact activation, absent when no goal is current. */
|
|
83
|
+
readonly goal?: {
|
|
84
|
+
/** Exact current goal identity. */
|
|
85
|
+
readonly id: GoalId
|
|
86
|
+
/** Exact current goal revision. */
|
|
87
|
+
readonly revision: number
|
|
88
|
+
/** Current process-local continuation state. */
|
|
89
|
+
readonly activation: GoalActivation
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
75
94
|
## Durable changes
|
|
76
95
|
|
|
77
96
|
Every mutation is a durable `goal/change` session event whose payload is either a complete post-mutation snapshot or a clear tombstone. The strict fold and persisted projection derive lifecycle state only from these events; inbox mutations do not affect goal state.
|
|
@@ -168,7 +187,7 @@ Goal service (`ctx.goals`) backed exclusively by the owning session log.
|
|
|
168
187
|
* @returns a fresh view or `undefined` when no goal is current.
|
|
169
188
|
* @throws {@link GoalError} when the agent is not the registry's live instance.
|
|
170
189
|
*/
|
|
171
|
-
get(agent: Agent): GoalView | undefined
|
|
190
|
+
@Remote('get') get(agent: Agent): GoalView | undefined
|
|
172
191
|
|
|
173
192
|
/**
|
|
174
193
|
* Remove process-local continuation authority without changing durable goal
|
|
@@ -256,6 +275,23 @@ Source: [`packages/goal/goal/src/index.ts`](https://github.com/deepseek-ai/deeps
|
|
|
256
275
|
|
|
257
276
|
### `goal/*` events
|
|
258
277
|
|
|
278
|
+
<a id="goalactivation-changed--emit"></a>
|
|
279
|
+
|
|
280
|
+
#### `goal/activation-changed` — emit
|
|
281
|
+
|
|
282
|
+
Process-local goal activation changed for one session.
|
|
283
|
+
|
|
284
|
+
```ts cordis-catalog
|
|
285
|
+
/**
|
|
286
|
+
* Process-local goal activation changed for one session.
|
|
287
|
+
* @mode emit
|
|
288
|
+
* @param payload - session id and the exact current goal activation, or no goal after a clear.
|
|
289
|
+
*/
|
|
290
|
+
'goal/activation-changed'(payload: GoalActivationChanged): void
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Source: [`packages/goal/goal/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/goal/goal/src/types.ts)
|
|
294
|
+
|
|
259
295
|
<a id="goalchanged--emit"></a>
|
|
260
296
|
|
|
261
297
|
#### `goal/changed` — emit
|
|
@@ -57,6 +57,8 @@ One page per subsystem of the DeepSeek Harness: what it is, the data structures
|
|
|
57
57
|
| [web-client.md](./web-client.md) | the browser architecture: boot, Remote communication, paired Client models, UI adapters, Conversation assembly, Slots, and reconnect semantics |
|
|
58
58
|
| [client-modules.md](./client-modules.md) | the web plugin table: `dsh.client` declarations, `WebBootGraph` wire composition, the bundle route and index tap |
|
|
59
59
|
| [slots.md](./slots.md) | typed Web UI composition: declaration ownership, cardinality and scope, framework and feature injection, props derivation, and the shipped hierarchy |
|
|
60
|
+
| [client-resources.md](./client-resources.md) | the client resource model: `dsh-resource://<type>/…` addresses, protocol providers and `ResourceProtocolMap`, the `useResource` global hook and its states, pins and release |
|
|
61
|
+
| [sidebar-right.md](./sidebar-right.md) | the right Sidebar: resource and navigation addresses, tab-type registration and routing, the `ctx.sidebarRight` navigation service, the pane-tab slots and owner props, the resource model, and the Workspace Files service |
|
|
60
62
|
| [conversation.md](./conversation.md) | target-neutral Session-event assembly: Context identity, Location data, replay paths, view builders, and target-owned render nodes |
|
|
61
63
|
| [session-projection.md](./session-projection.md) | the projection seam: `SessionProjectionMap`, the pure `ProjectionDefinition` unit, `ProjectionSnapshot`'s consistent cut, the change feed |
|
|
62
64
|
| [session-telemetry.md](./session-telemetry.md) | the outbound session-reporting capability seam: `SessionTelemetryRecord`/`SessionTelemetrySeverity`, the `SessionTelemetrySink` contract, and the `session-telemetry/record` redact waterfall |
|
|
@@ -5,7 +5,7 @@ outline: [2,3]
|
|
|
5
5
|
|
|
6
6
|
# Runtime Invariants
|
|
7
7
|
|
|
8
|
-
[dsh-invariants](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/runtime-diagnostics/invariants) is the configurable registry service (`ctx.invariants`) for package-owned runtime invariant checks. It is one support-group package, not a three-package capability seam, and not part of the agent-loop spine: the registry owns selection, name reservation, child-fiber lifecycle, and package-attributed failure, while every workspace package publishes a `./invariant` companion plugin that registers checks under its exact npm package name. What a check may assert — authoritative event streams or mutable data, never service or method presence — is the runtime-invariants convention in [AGENTS.md](https://github.com/deepseek-ai/deepseek-harness/blob/master/AGENTS.md#conventions)
|
|
8
|
+
[dsh-invariants](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/runtime-diagnostics/invariants) is the configurable registry service (`ctx.invariants`) for package-owned runtime invariant checks. It is one support-group package, not a three-package capability seam, and not part of the agent-loop spine: the registry owns selection, name reservation, child-fiber lifecycle, and package-attributed failure, while every workspace package publishes a `./invariant` companion plugin that registers checks under its exact npm package name. What a check may assert — authoritative event streams or mutable data, never service or method presence — is the runtime-invariants convention in [AGENTS.md](https://github.com/deepseek-ai/deepseek-harness/blob/master/AGENTS.md#conventions).
|
|
9
9
|
|
|
10
10
|
Source: [`packages/runtime-diagnostics/invariants/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/runtime-diagnostics/invariants/src/index.ts)
|
|
11
11
|
|
|
@@ -228,7 +228,7 @@ type StreamChunk =
|
|
|
228
228
|
|
|
229
229
|
`snapshot()` returns a detached immutable stream. `expandAssistantStream()` strictly checks record keys, member counts, indexes, timestamps, tool-call identity, and lossless JSON before recreating the exact timed chunk sequence. The Session log embeds this stream in `assistant/message` for a surface result or `assistant/attempt` for an attempt with no surface message.
|
|
230
230
|
|
|
231
|
-
Process-local `agent/assistant-stream` frames carry live presentation. Durable replay
|
|
231
|
+
Process-local `agent/assistant-stream` frames carry live presentation. Durable replay and restore validation still expand the embedded settlement; telemetry, token accounting, and Host folds read the compact records directly. Record-level readers (`assistantStreamFirstTokenTime`, `assistantStreamHasVisibleContent`, `assistantStreamHasVisibleText`, `lastAssistantStreamChunk`, `assistantStreamChunks`, `joinAssistantStreamText`, `assembleAssistantStream`, and the per-run `runFirstTokenTime` and `runFirstVisibleTime`) answer consumer questions in one pass over the records with early exit, so a large history costs O(records) per settlement instead of O(members) expansion ([fold decision](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-09-06-embedded-stream-record-readers.md)). `expandAssistantStream()` remains the validating path for records read at a durable boundary and for consumers that need every member.
|
|
232
232
|
|
|
233
233
|
## `LlmFailure`
|
|
234
234
|
|
|
@@ -298,7 +298,7 @@ Every adapter MUST obey these, and every consumer may rely on them:
|
|
|
298
298
|
- **One adapter call is one provider attempt.** Adapters disable library retries. Agent-level recovery opens another durable numbered turn; direct `ctx.llm.stream()` callers remain single-attempt.
|
|
299
299
|
- **Provider stalls are bounded at the transport.** Both shipping remote adapters expose positive finite `streamIdleTimeoutMs` with a five-minute default. The watchdog arms only while iterator `next()` is outstanding, uses one stable signal for the whole request, maps its own expiry to `TIMEOUT`, and keeps an earlier caller abort as `ABORTED`.
|
|
300
300
|
- **Context overflow has one canonical code.** Both DeepSeek adapters classify explicit provider detail through `isContextWindowExceededError()` and surface `CONTEXT_WINDOW_EXCEEDED`, whether the failure arrives as a thrown HTTP `LlmError` or an in-band finish error. Consumers route on the code, never provider text.
|
|
301
|
-
- **An empty completion is a retryable error, not a silent success.** Both adapters map a terminal `stop` finish that carried no content blocks to `finish {kind:'error'}` with the canonical `EMPTY_RESPONSE` code, and `dsh-llm-retry` retries it by default
|
|
301
|
+
- **An empty completion is a retryable error, not a silent success.** Both adapters map a terminal `stop` finish that carried no content blocks to `finish {kind:'error'}` with the canonical `EMPTY_RESPONSE` code, and `dsh-llm-retry` retries it by default.
|
|
302
302
|
- **Every provider HTTP request carries the app-attribution header.** Adapters send `attributionHeaders()` (below) - the `User-Agent` baseline - and prove it with a wire-level test.
|
|
303
303
|
- **Replay state is adapter-owned; its split is shared.** A successful `finish` may carry a `ReplayEnvelope`: opaque response-level metadata plus optional per-block entries aligned with the emitted block sequence. The alignment is the harness's vocabulary — when assembly drops a block it drops the entry at the same position, so stored metadata always describes stored content. The loop stores the pruned envelope with the assembled assistant message. On a later request, `LlmRuntime` passes the state only when the historical provider and target provider are currently registered to the exact same adapter instance. That adapter validates the state and owns any cross-model or cross-provider conversion; other adapters receive the provider-neutral content plus provider/model fields without the private state. Durable content stays authoritative: a stored state the reading adapter cannot use degrades that one message to provider-neutral conversion with a diagnostic instead of failing the request.
|
|
304
304
|
|
|
@@ -495,6 +495,8 @@ interface LlmConfigurableProvider {
|
|
|
495
495
|
* from outside.
|
|
496
496
|
*/
|
|
497
497
|
declared?: boolean
|
|
498
|
+
/** Configuration diagnostic for repair; unaffected models may remain serviceable. */
|
|
499
|
+
error?: string
|
|
498
500
|
}
|
|
499
501
|
```
|
|
500
502
|
|
|
@@ -514,7 +516,7 @@ interface LlmModelInfo {
|
|
|
514
516
|
}
|
|
515
517
|
```
|
|
516
518
|
|
|
517
|
-
Correctness-sensitive metadata is resolved separately from the advisory catalog and is owned by the adapter serving the exact route. Context capacity, adapter call defaults,
|
|
519
|
+
Correctness-sensitive metadata is resolved separately from the advisory catalog and is owned by the adapter serving the exact route. Context capacity, adapter call defaults, reasoning choices, and the system prompt update mode share one exact-model result so consumers do not repeat authoritative model resolution. `SystemPromptUpdate` has the single value `'in-history'`: the model reads the latest `system` message at any position of `messages` as the complete effective system prompt, so the agent loop can append a changed prompt after the cached history instead of rewriting message 0 ([decision rule](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent-loop/README.md#understand-the-implementation)); an absent mode means only a leading system message is read, and `normalizeModelInfo` rejects any other value with `INVALID_MODEL_INFO`.
|
|
518
520
|
|
|
519
521
|
```ts type-equiv
|
|
520
522
|
/** Provider-owned context capacity for one exact provider/model route. */
|
|
@@ -565,6 +567,8 @@ interface LlmResolvedModelInfo extends LlmModelInfo {
|
|
|
565
567
|
defaultMaxTokens?: number
|
|
566
568
|
/** Adapter-owned selectable reasoning levels when exposed. */
|
|
567
569
|
reasoning?: LlmModelReasoningInfo
|
|
570
|
+
/** Declared mid-conversation system prompt handling; absent means only a leading system message is read. */
|
|
571
|
+
systemPromptUpdate?: SystemPromptUpdate
|
|
568
572
|
}
|
|
569
573
|
```
|
|
570
574
|
|
|
@@ -577,12 +581,16 @@ interface GenerateOptions {
|
|
|
577
581
|
/** Adapter-owned reasoning effort selected for this exact model. */
|
|
578
582
|
reasoningEffort?: ReasoningEffortId
|
|
579
583
|
/**
|
|
580
|
-
* Ordered conversation messages, exactly as the provider sees them
|
|
581
|
-
*
|
|
582
|
-
* the
|
|
584
|
+
* Ordered conversation messages, exactly as the provider sees them. A
|
|
585
|
+
* loop-built request passes the derived history (dsh-agent-loop), whose
|
|
586
|
+
* leading system-role message carries the system prompt; a hand-built
|
|
587
|
+
* one-shot passes any list.
|
|
583
588
|
*/
|
|
584
589
|
messages: Message[]
|
|
585
|
-
/**
|
|
590
|
+
/**
|
|
591
|
+
* System prompt text for one-shot callers; adapters map it to the provider's
|
|
592
|
+
* system slot ahead of `messages`. Loop-built requests leave it undefined.
|
|
593
|
+
*/
|
|
586
594
|
system?: string
|
|
587
595
|
/** Tool schemas (adapters map to the provider's `tools` field). */
|
|
588
596
|
tools?: ToolSchema[]
|
|
@@ -696,11 +704,11 @@ interface LlmDiscoveredModel {
|
|
|
696
704
|
|
|
697
705
|
### The request envelope: `LlmCallConfig` and the logged header
|
|
698
706
|
|
|
699
|
-
The loop builds each request from logged state. `EpochHeader` records call config, marks the fields supplied by adapter defaults, and records the
|
|
707
|
+
The loop builds each request from logged state. `EpochHeader` records call config, marks the fields supplied by adapter defaults, and records the authoritative returned tool order (configured by `toolOrder`, or lexicographic when unset) through full `request/header` snapshots. The rendered prompt is derived history — the `system/message` at surface node 0, plus any later system node an `in-history` route appended — so the header and the derived history together make the request reconstructable from the session log. See [session.md](./session.md#the-request-header-event-requestheader) and the [reconstructability Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-07-05-reconstructable-requests.md).
|
|
700
708
|
|
|
701
|
-
`agent/request` receives a frozen call-config seed and may return a replacement to switch provider, model, reasoning effort, or sampling. Before the waterfall, the loop removes values marked as adapter defaults so exact-model preparation materializes the selected route's current values; unmarked explicit settings remain in the proposal. After the waterfall, preparation rejects unsupported explicit effort ids without clamping and logs the effective config plus the fields supplied by adapter defaults under the turn signal. The prepared call keeps one adapter registration through dispatch. Requests reaching `llm/stream` are deep-frozen, so mutation throws, and carry a process-local loop identity so observers do not confuse separately logged frozen auxiliary calls with conversation requests.
|
|
709
|
+
`agent/request` receives a frozen call-config seed and may return a replacement to switch provider, model, reasoning effort, or sampling. Before the waterfall, the loop removes values marked as adapter defaults so exact-model preparation materializes the selected route's current values; unmarked explicit settings remain in the proposal. After the waterfall, preparation rejects unsupported explicit effort ids without clamping and logs the effective config plus the fields supplied by adapter defaults under the turn signal. On step admission, this waterfall and preparation run after assembly and `step/start` but before the system prompt and accepted user batch are committed; cancellation during either commits neither. The prepared capability governs prompt reconciliation, and the call keeps one adapter registration through dispatch. Requests reaching `llm/stream` are deep-frozen, so mutation throws, and carry a process-local loop identity so observers do not confuse separately logged frozen auxiliary calls with conversation requests.
|
|
702
710
|
|
|
703
|
-
On the wire, a loop-built request
|
|
711
|
+
On the wire, a loop-built request is the derived history alone: the rendered prompt travels as the leading `system`-role message (surface node 0, a `system/message` event) and, when the prepared call declares `systemPromptUpdate: 'in-history'`, a non-empty changed prompt may follow the cached history as a later `system`-role message that the model reads as the effective prompt; the request's `system` field is unset — `GenerateOptions.system` serves direct one-shot callers such as title providers. An empty rendering leaves no system messages in derived history, even when earlier requests retained several prompt versions. The logged request ends with the newest `user/message` on a turn's first step and the previous step's tool results on later steps. The dev invariant recomputes exactly this equation against every loop-built request and rejects a loop request carrying a `system` field.
|
|
704
712
|
|
|
705
713
|
FIXME(call-config-shape): revisit which remaining fields are genuinely epoch-level for cache purposes (`model` and the model-owned reasoning effort are explicit; the sampling scalars sit here out of caution).
|
|
706
714
|
|
|
@@ -753,6 +761,8 @@ interface PreparedLlmCall {
|
|
|
753
761
|
readonly context?: LlmModelContext
|
|
754
762
|
/** Exact model modalities captured with the adapter dispatch generation. */
|
|
755
763
|
readonly inputModalities?: readonly ModelModality[]
|
|
764
|
+
/** Exact model system prompt update mode captured with the adapter dispatch generation. */
|
|
765
|
+
readonly systemPromptUpdate?: SystemPromptUpdate
|
|
756
766
|
/** Config fields materialized by the captured adapter rather than proposed by the caller. */
|
|
757
767
|
readonly adapterDefaults: LlmCallConfigAdapterDefaults
|
|
758
768
|
/**
|
|
@@ -5,7 +5,7 @@ outline: [2,3]
|
|
|
5
5
|
|
|
6
6
|
# LSP navigation
|
|
7
7
|
|
|
8
|
-
The LSP seam — a [capability seam](https://github.com/deepseek-ai/deepseek-harness/blob/master
|
|
8
|
+
The LSP seam — a [capability seam](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/glossary.md#capability-seam) exposing semantic code navigation on one `ctx.lsp` service, split across packages: Service Definition ([dsh-lsp](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/lsp/lsp), `ctx.lsp` + the provider registry), a generic Service Provider ([dsh-lsp-stdio](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/lsp/lsp-stdio), a configured stdio language-server host), and Consumer ([dsh-tool-lsp](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/lsp/tool-lsp), the `lsp` tool schema). LSP is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](./core.md). A provider swap does not change how the model asks for navigation.
|
|
9
9
|
|
|
10
10
|
Source: [`packages/lsp/lsp/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/lsp/lsp/src/types.ts)
|
|
11
11
|
|
|
@@ -11,7 +11,20 @@ The seam is a [capability seam](https://github.com/deepseek-ai/deepseek-harness/
|
|
|
11
11
|
|
|
12
12
|
## `SessionHandle` — one open channel onto a stored session
|
|
13
13
|
|
|
14
|
-
Every log read and write flows through a handle, never through id-addressed service methods: the handle is the single door the cross-process write lease guards. One handle type serves both accesses — a mutation on a `read` handle is a runtime `SessionReadOnlyError` rather than a typed split — and in-process single-writer ownership makes a second `open(id, 'write')` reject with `SessionAlreadyOwnedError` while an owner is active.
|
|
14
|
+
Every log read and write flows through a handle, never through id-addressed service methods: the handle is the single door the cross-process write lease guards. A read returns a caller-owned outer slice and the producer-established aliasing state of its event values. One handle type serves both accesses — a mutation on a `read` handle is a runtime `SessionReadOnlyError` rather than a typed split — and in-process single-writer ownership makes a second `open(id, 'write')` reject with `SessionAlreadyOwnedError` while an owner is active.
|
|
15
|
+
|
|
16
|
+
```ts type-equiv
|
|
17
|
+
/** One persistence event slice returned by {@link SessionHandle.read}. */
|
|
18
|
+
interface SessionHandleReadResult {
|
|
19
|
+
/**
|
|
20
|
+
* Whether event values are exclusively owned or shared only after deep
|
|
21
|
+
* freezing. Slicing preserves the producer's state even when no events remain.
|
|
22
|
+
*/
|
|
23
|
+
readonly eventState: SessionSeedEventState
|
|
24
|
+
/** Event values in a caller-owned outer array. */
|
|
25
|
+
readonly events: readonly SessionEvent[]
|
|
26
|
+
}
|
|
27
|
+
```
|
|
15
28
|
|
|
16
29
|
```ts type-equiv
|
|
17
30
|
/**
|
|
@@ -50,9 +63,9 @@ interface SessionHandle extends AsyncDisposable {
|
|
|
50
63
|
* @param length - maximum number of events to return; defaults to the rest
|
|
51
64
|
* of the log. An offset at or past the end returns an empty list.
|
|
52
65
|
* @param options - optional cancellation.
|
|
53
|
-
* @returns the
|
|
66
|
+
* @returns the caller-owned outer slice plus the ownership state of its event values.
|
|
54
67
|
*/
|
|
55
|
-
read(offset?: number, length?: number, options?: SessionHandleReadOptions): Promise<
|
|
68
|
+
read(offset?: number, length?: number, options?: SessionHandleReadOptions): Promise<SessionHandleReadResult>
|
|
56
69
|
|
|
57
70
|
/**
|
|
58
71
|
* Append a contiguous batch continuing the current logical end. The first
|
|
@@ -93,7 +106,7 @@ A created session is observable in this process from the moment `create` resolve
|
|
|
93
106
|
|
|
94
107
|
## The flush checkpoint
|
|
95
108
|
|
|
96
|
-
`session/event` is a *synchronous* notification; the mounted backend routes it by session id into the active write handle's bounded write-behind window without blocking the producer (the backend installs these listeners once, because persistence already enforces one active write handle per id). The first pending event starts a fixed internal batching window, and later events join without resetting its deadline. Expiry starts one durable `append` through the session's write handle; events admitted during that write receive their own deadline and form a follow-up batch. `session/flush` cancels the wait and drains through quiescence, so the loop still uses it as the ordering and error-observation checkpoint before claiming the next ordinary turn. A rejected background write retains its events in order, pauses the automatic path, and is reported through the logger; the next explicit flush retries and rejects loudly to its caller. `session/disposed` performs the same final drain and closes the handle, and `close()` itself drains the routed buffer through the still-open storage, so backend teardown's close sweep loses nothing. The window bounds only intentional batching wait, not event-loop scheduling or backend durability latency
|
|
109
|
+
`session/event` is a *synchronous* notification; the mounted backend routes it by session id into the active write handle's bounded write-behind window without blocking the producer (the backend installs these listeners once, because persistence already enforces one active write handle per id). The first pending event starts a fixed internal batching window, and later events join without resetting its deadline. Expiry starts one durable `append` through the session's write handle; events admitted during that write receive their own deadline and form a follow-up batch. `session/flush` cancels the wait and drains through quiescence, so the loop still uses it as the ordering and error-observation checkpoint before claiming the next ordinary turn. A rejected background write retains its events in order, pauses the automatic path, and is reported through the logger; the next explicit flush retries and rejects loudly to its caller. `session/disposed` performs the same final drain and closes the handle, and `close()` itself drains the routed buffer through the still-open storage, so backend teardown's close sweep loses nothing. The window bounds only intentional batching wait, not event-loop scheduling or backend durability latency.
|
|
97
110
|
|
|
98
111
|
## Crash recovery preserves an interrupted turn
|
|
99
112
|
|
|
@@ -101,7 +114,7 @@ A log crashed mid-turn ends with an open `turn/start` and no `turn/end`. Persist
|
|
|
101
114
|
|
|
102
115
|
Repair therefore writes only under write ownership: a live session's write handle is held by its lifecycle owner, so a concurrent `open(id, 'write')` rejects with `SessionAlreadyOwnedError` instead of racing repair against a live turn. Read-only observers (session-query) balance an interrupted cold log with the same closers in memory only, writing nothing back.
|
|
103
116
|
|
|
104
|
-
Read-only observation is `open(id, 'read')`: the handle serves validated contiguous prefix slices, never a torn tail, and repeated reads on one handle never observe an older state than a prior read. There is no persistence-side prepared-Session cache: session-query owns its cold-read cache, keying one balanced cold Session per id on the `stat().revision` change token and re-reading only when the token changes. The [handle-based persistence Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-27-handle-based-session-persistence.md) owns this lifecycle; the [Session preparation
|
|
117
|
+
Read-only observation is `open(id, 'read')`: the handle serves validated contiguous prefix slices, never a torn tail, and repeated reads on one handle never observe an older state than a prior read. There is no persistence-side prepared-Session cache: session-query owns its cold-read cache, keying one balanced cold Session per id on the `stat().revision` change token and re-reading only when the token changes. The [handle-based persistence Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-27-handle-based-session-persistence.md) owns this lifecycle; the archived [Session preparation record](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/archived/architecture/2026-08-05-session-preparation.md) documents the original publication-boundary `SessionPreparation` decision.
|
|
105
118
|
|
|
106
119
|
## `SessionLocation` — refusal-diagnostics artifact target
|
|
107
120
|
|
|
@@ -176,7 +189,7 @@ interface SessionHeader {
|
|
|
176
189
|
|
|
177
190
|
## Format refusal — logs a build cannot faithfully read
|
|
178
191
|
|
|
179
|
-
A backend refuses a log it cannot faithfully interpret with `SessionFormatUnsupportedError`, distinct from `SessionPersistenceCorruptionError` because nothing is damaged. `stat` and `list` classify the highest canonical generation and translate a supported historical header without reading or mutating its body. `open`
|
|
192
|
+
A backend refuses a log it cannot faithfully interpret with `SessionFormatUnsupportedError`, distinct from `SessionPersistenceCorruptionError` because nothing is damaged. `stat` and `list` classify the highest canonical generation and translate a supported historical header without reading or mutating its body. Historical `open` calls share one per-session migration preparation before returning current logical values and leave every source path, byte, and inode unchanged. The JSONL provider returns a read handle from that in-memory result without publishing; a write open holds its single-writer claim and file lease while it reuses the preparation, exclusively publishes the final current generation, and only then returns the writable handle. A future highest generation refuses even when an older readable generation remains. Current-format restoration retains installed extensions and unknown events carrying `ignorable: true`; historical v0/v1/v2 migration refuses an unknown type even when marked ignorable. The message appends the selected raw log path when the backend keeps one artifact per session. An out-of-tree backend must enforce equivalent current-only handle values and direction-aware refusals at its physical-format entry. The [released-format migration decision](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md) owns the chain and immutable-publication rules.
|
|
180
193
|
|
|
181
194
|
## `CreateSessionOptions` — seeding and metadata
|
|
182
195
|
|
|
@@ -192,7 +205,7 @@ interface CreateSessionOptions {
|
|
|
192
205
|
/** Initial replay or fork history supplied at construction. */
|
|
193
206
|
readonly seed?: readonly SessionEvent[]
|
|
194
207
|
/**
|
|
195
|
-
* Exact fork-inherited prefix length when `meta.isSeeded` is true.
|
|
208
|
+
* Exact fork-inherited prefix length when `meta.isSeeded` is true. The
|
|
196
209
|
* constructor seed is exactly this inherited prefix; the constructor
|
|
197
210
|
* appends the child-owned tagged marker at the cut.
|
|
198
211
|
*/
|
|
@@ -217,29 +230,37 @@ Replay/fork is therefore `ctx.agents.create({ sessionId, seed, meta })` — a fo
|
|
|
217
230
|
|
|
218
231
|
## Preparation and restoration ownership
|
|
219
232
|
|
|
220
|
-
`SessionStore.prepare()` accepts ordinary creation options or
|
|
233
|
+
`SessionStore.prepare()` accepts ordinary creation options or an adoptable seed through `RestoredSessionOptions`. Its `eventState` says whether event values are independently owned or shared only after deep freezing; the producer establishes that state, and slicing does not infer a different state from result length. Restoration validates and adopts those values without another copy or freeze pass. `SessionPreparation` then owns the exact unpublished Session until publication or rollback; disposal is synchronous and idempotent. agent-loop's resume reads this result through the session's write handle and appends independently owned `interruptedTurnClosers` before preparation.
|
|
234
|
+
|
|
235
|
+
```ts type-equiv
|
|
236
|
+
/**
|
|
237
|
+
* Aliasing state of an adoptable Session seed. `shared-frozen` permits deeply
|
|
238
|
+
* frozen aliases plus independently owned unfrozen values in the same seed.
|
|
239
|
+
*/
|
|
240
|
+
type SessionSeedEventState = 'detached' | 'shared-frozen'
|
|
241
|
+
```
|
|
221
242
|
|
|
222
243
|
```ts type-equiv
|
|
223
244
|
/**
|
|
224
|
-
*
|
|
225
|
-
*
|
|
245
|
+
* Adoptable storage values transferred to {@link SessionStore.prepare}
|
|
246
|
+
* without another copy or freeze pass.
|
|
226
247
|
*/
|
|
227
248
|
interface RestoredSessionOptions {
|
|
228
|
-
/**
|
|
249
|
+
/** Events that are independently owned or already deeply frozen. */
|
|
229
250
|
readonly seed: SessionEvent[]
|
|
230
|
-
/**
|
|
251
|
+
/** Independently owned storage metadata to validate and freeze in place. */
|
|
231
252
|
readonly meta: SessionHeader
|
|
232
253
|
/** Exact number of fork-inherited leading events decoded from storage. */
|
|
233
254
|
readonly inheritedEventCount: SessionLogOffset
|
|
234
|
-
/**
|
|
235
|
-
readonly
|
|
255
|
+
/** Aliasing state carried from the operation that produced the seed. */
|
|
256
|
+
readonly eventState: SessionSeedEventState
|
|
236
257
|
}
|
|
237
258
|
```
|
|
238
259
|
|
|
239
260
|
```ts type-equiv
|
|
240
261
|
/** Inputs accepted while constructing an unpublished Session. */
|
|
241
262
|
type PrepareSessionOptions =
|
|
242
|
-
| (CreateSessionOptions & { readonly
|
|
263
|
+
| (CreateSessionOptions & { readonly eventState?: undefined })
|
|
243
264
|
| RestoredSessionOptions
|
|
244
265
|
```
|
|
245
266
|
|
|
@@ -5,7 +5,7 @@ outline: [2,3]
|
|
|
5
5
|
|
|
6
6
|
# Session-local Schedule
|
|
7
7
|
|
|
8
|
-
Schedule owns durable reminders that return to the original live Session as ordinary later conversation turns. The [durable Schedule Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-08-05-durable-web-schedule.md) owns persistence, lifecycle, and active-state presentation,
|
|
8
|
+
Schedule owns durable reminders that return to the original live Session as ordinary later conversation turns. The [durable Schedule Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-08-05-durable-web-schedule.md) owns persistence, lifecycle, and active-state presentation, and the [explicit time-zone boundary](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/simplification/2026-08-09-explicit-schedule-time-zone.md) owns browser-local interpretation. This page records the durable and model-facing shapes from [`packages/schedule/schedule/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/schedule/schedule/src/types.ts); the [package README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/schedule/schedule/README.md) owns composition, tool behavior, and the exact reminder framing.
|
|
9
9
|
|
|
10
10
|
## Durable records
|
|
11
11
|
|
|
@@ -5,7 +5,7 @@ outline: [2,3]
|
|
|
5
5
|
|
|
6
6
|
# Scoped Registration
|
|
7
7
|
|
|
8
|
-
The [scope package](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/core/scope) supplies the identity, carrier, and scoped-layer vocabulary that makes one registration context mean both per-agent visibility and shared lifetime ownership. It is a library primitive rather than a Cordis service; the [agent-scope runtime-design Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#scope-routing-one-opaque-key-selects-one-layer) owns the lifecycle rationale,
|
|
8
|
+
The [scope package](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/core/scope) supplies the identity, carrier, and scoped-layer vocabulary that makes one registration context mean both per-agent visibility and shared lifetime ownership. It is a library primitive rather than a Cordis service; the [agent-scope runtime-design Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.md#scope-routing-one-opaque-key-selects-one-layer) owns the lifecycle rationale, and the package [README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/scope/README.md) owns the callable API and filtering semantics.
|
|
9
9
|
|
|
10
10
|
Sources: [`packages/core/scope/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/scope/src/index.ts) and [`packages/core/scope/src/store.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/scope/src/store.ts).
|
|
11
11
|
|
|
@@ -207,6 +207,10 @@ async listCandidates( agent: Agent, query: string = '', limit: number = this.con
|
|
|
207
207
|
|
|
208
208
|
/**
|
|
209
209
|
* Snapshot all references for one accepted direct message and return one aggregated durable context.
|
|
210
|
+
* Automatic budgets use the last assembled route, or agent options before any assembly.
|
|
211
|
+
* Missing model capacity or adapter uses 64 KiB; other metadata lookup failures and cancellation reject preparation.
|
|
212
|
+
* Truncated previews include omission facts and a full-snapshot spill locator, or an explicit unavailable notice.
|
|
213
|
+
* Cancellation prevents context publication, including when storage completes after cancellation.
|
|
210
214
|
* @param agent - target agent; references to it are rejected.
|
|
211
215
|
* @param content - already host-normalized readable message content.
|
|
212
216
|
* @param references - structured source sessions in mention order.
|