dsh-loop-engine-allinone 0.0.0-stage → 0.4.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.
Files changed (143) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/CONTRIBUTING.md +78 -0
  3. package/LICENSE +23 -0
  4. package/NOTICE +45 -0
  5. package/README.md +221 -2
  6. package/README.zh.md +89 -0
  7. package/SECURITY.md +39 -0
  8. package/cordis.patch.yml +3 -0
  9. package/lib/client.js +2166 -0
  10. package/lib/index.js +11621 -0
  11. package/lib/invariant.js +453 -0
  12. package/lib/types/agent-preset-ids.d.ts +276 -0
  13. package/lib/types/client/LoopEngineBadge.d.ts +71 -0
  14. package/lib/types/client/LoopEngineComposerSelect.d.ts +126 -0
  15. package/lib/types/client/LoopEngineSection.d.ts +35 -0
  16. package/lib/types/client/engine-marks.d.ts +87 -0
  17. package/lib/types/client/index.d.ts +39 -0
  18. package/lib/types/client/locales.d.ts +182 -0
  19. package/lib/types/client/reload.d.ts +135 -0
  20. package/lib/types/client/session-engine.d.ts +508 -0
  21. package/lib/types/client/store.d.ts +103 -0
  22. package/lib/types/client/turn-status.d.ts +234 -0
  23. package/lib/types/client/use-session-engine.d.ts +74 -0
  24. package/lib/types/commands.d.ts +77 -0
  25. package/lib/types/compat.d.ts +25 -0
  26. package/lib/types/driver-acp/agent.d.ts +289 -0
  27. package/lib/types/driver-acp/approval.d.ts +27 -0
  28. package/lib/types/driver-acp/capabilities.d.ts +200 -0
  29. package/lib/types/driver-acp/client.d.ts +297 -0
  30. package/lib/types/driver-acp/executable.d.ts +53 -0
  31. package/lib/types/driver-acp/mapping.d.ts +76 -0
  32. package/lib/types/driver-acp/profile.d.ts +126 -0
  33. package/lib/types/driver-acp/runtime.d.ts +45 -0
  34. package/lib/types/driver-acp/subprocess.d.ts +19 -0
  35. package/lib/types/driver-acp/terminal.d.ts +98 -0
  36. package/lib/types/driver-acp/transport.d.ts +43 -0
  37. package/lib/types/driver-acp/types.d.ts +152 -0
  38. package/lib/types/driver-cli/capability.d.ts +42 -0
  39. package/lib/types/driver-cli/cli-agent.d.ts +258 -0
  40. package/lib/types/driver-cli/cli-loop.d.ts +46 -0
  41. package/lib/types/driver-cli/flatten.d.ts +35 -0
  42. package/lib/types/driver-cli/frames.d.ts +128 -0
  43. package/lib/types/driver-cli/ndjson.d.ts +106 -0
  44. package/lib/types/driver-cli/session-sink.d.ts +333 -0
  45. package/lib/types/driver-cli/stream-json.d.ts +61 -0
  46. package/lib/types/driver-cli/text.d.ts +66 -0
  47. package/lib/types/driver-cli/transport.d.ts +84 -0
  48. package/lib/types/driver-core/agents-md-skill-provider.d.ts +72 -0
  49. package/lib/types/driver-core/assistant-stream.d.ts +68 -0
  50. package/lib/types/driver-core/context-files.d.ts +62 -0
  51. package/lib/types/driver-core/host-servers.d.ts +119 -0
  52. package/lib/types/driver-core/hosted-engine-runtime.d.ts +190 -0
  53. package/lib/types/driver-core/hosted-tool-vocabulary.d.ts +78 -0
  54. package/lib/types/driver-core/idle-child.d.ts +57 -0
  55. package/lib/types/driver-core/image-access.d.ts +25 -0
  56. package/lib/types/driver-core/inbox.d.ts +104 -0
  57. package/lib/types/driver-core/model-handover.d.ts +134 -0
  58. package/lib/types/driver-core/ownership.d.ts +41 -0
  59. package/lib/types/driver-core/permission-knobs.d.ts +26 -0
  60. package/lib/types/driver-core/prompt.d.ts +64 -0
  61. package/lib/types/driver-core/session-lifetime.d.ts +62 -0
  62. package/lib/types/driver-core/session-model.d.ts +128 -0
  63. package/lib/types/driver-core/skill-inject.d.ts +59 -0
  64. package/lib/types/driver-core/step-close.d.ts +49 -0
  65. package/lib/types/driver-core/step-images.d.ts +62 -0
  66. package/lib/types/driver-core/step-tools.d.ts +43 -0
  67. package/lib/types/driver-core/system-head.d.ts +43 -0
  68. package/lib/types/engine-agy/agent.d.ts +67 -0
  69. package/lib/types/engine-agy/frames.d.ts +90 -0
  70. package/lib/types/engine-agy/loop.d.ts +64 -0
  71. package/lib/types/engine-agy/process.d.ts +173 -0
  72. package/lib/types/engine-claude/agent.d.ts +186 -0
  73. package/lib/types/engine-claude/loop.d.ts +73 -0
  74. package/lib/types/engine-claude/mapping.d.ts +108 -0
  75. package/lib/types/engine-claude/permission.d.ts +41 -0
  76. package/lib/types/engine-claude/process.d.ts +59 -0
  77. package/lib/types/engine-claude/sdk.d.ts +67 -0
  78. package/lib/types/engine-claude/types.d.ts +28 -0
  79. package/lib/types/engine-codex/agent.d.ts +216 -0
  80. package/lib/types/engine-codex/appserver/client.d.ts +80 -0
  81. package/lib/types/engine-codex/appserver/mapping.d.ts +67 -0
  82. package/lib/types/engine-codex/appserver/thread.d.ts +66 -0
  83. package/lib/types/engine-codex/appserver/types.d.ts +225 -0
  84. package/lib/types/engine-codex/loop.d.ts +75 -0
  85. package/lib/types/engine-codex/model-handover.d.ts +56 -0
  86. package/lib/types/engine-codex/permission.d.ts +126 -0
  87. package/lib/types/engine-codex/skills.d.ts +28 -0
  88. package/lib/types/engine-codex/types.d.ts +36 -0
  89. package/lib/types/engine-drivers.d.ts +132 -0
  90. package/lib/types/engine-grok/agent.d.ts +24 -0
  91. package/lib/types/engine-grok/loop.d.ts +61 -0
  92. package/lib/types/engine-grok/process.d.ts +46 -0
  93. package/lib/types/engine-grok/profile.d.ts +82 -0
  94. package/lib/types/engine-hermes/agent.d.ts +47 -0
  95. package/lib/types/engine-hermes/loop.d.ts +56 -0
  96. package/lib/types/engine-hermes/process.d.ts +92 -0
  97. package/lib/types/engine-kimi/acp/client.d.ts +123 -0
  98. package/lib/types/engine-kimi/acp/mapping.d.ts +73 -0
  99. package/lib/types/engine-kimi/acp/types.d.ts +143 -0
  100. package/lib/types/engine-kimi/agent.d.ts +24 -0
  101. package/lib/types/engine-kimi/commands.d.ts +44 -0
  102. package/lib/types/engine-kimi/loop.d.ts +62 -0
  103. package/lib/types/engine-kimi/model-handover.d.ts +32 -0
  104. package/lib/types/engine-kimi/permission.d.ts +28 -0
  105. package/lib/types/engine-kimi/process.d.ts +47 -0
  106. package/lib/types/engine-kimi/profile.d.ts +19 -0
  107. package/lib/types/engine-kimi/skills.d.ts +52 -0
  108. package/lib/types/engine-kimi/types.d.ts +25 -0
  109. package/lib/types/engine-minimaxcode/agent.d.ts +24 -0
  110. package/lib/types/engine-minimaxcode/loop.d.ts +83 -0
  111. package/lib/types/engine-minimaxcode/process.d.ts +53 -0
  112. package/lib/types/engine-minimaxcode/profile.d.ts +72 -0
  113. package/lib/types/engine-of-session.d.ts +97 -0
  114. package/lib/types/engine-pi/agent.d.ts +230 -0
  115. package/lib/types/engine-pi/loop.d.ts +72 -0
  116. package/lib/types/engine-pi/model-handover.d.ts +84 -0
  117. package/lib/types/engine-pi/permission.d.ts +47 -0
  118. package/lib/types/engine-pi/rpc/client.d.ts +107 -0
  119. package/lib/types/engine-pi/rpc/mapping.d.ts +37 -0
  120. package/lib/types/engine-pi/rpc/types.d.ts +249 -0
  121. package/lib/types/engine-pi/skills.d.ts +47 -0
  122. package/lib/types/engine-pi/types.d.ts +36 -0
  123. package/lib/types/engine-qoderclicn/agent.d.ts +59 -0
  124. package/lib/types/engine-qoderclicn/loop.d.ts +51 -0
  125. package/lib/types/engine-qoderclicn/process.d.ts +113 -0
  126. package/lib/types/engine-registry.d.ts +584 -0
  127. package/lib/types/engine-remote.d.ts +192 -0
  128. package/lib/types/engine-surface.d.ts +36 -0
  129. package/lib/types/engine-zcode/agent.d.ts +50 -0
  130. package/lib/types/engine-zcode/loop.d.ts +47 -0
  131. package/lib/types/engine-zcode/process.d.ts +111 -0
  132. package/lib/types/index.d.ts +205 -0
  133. package/lib/types/invariant.d.ts +26 -0
  134. package/lib/types/model-selection-reset.d.ts +271 -0
  135. package/lib/types/namespace.d.ts +25 -0
  136. package/lib/types/patch-manager.d.ts +104 -0
  137. package/lib/types/preset.d.ts +254 -0
  138. package/lib/types/provider-route.d.ts +245 -0
  139. package/lib/types/router-loop.d.ts +458 -0
  140. package/lib/types/session-engine-store.d.ts +138 -0
  141. package/lib/types/settings.d.ts +60 -0
  142. package/lib/types/skills.d.ts +85 -0
  143. package/package.json +150 -4
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Projection of a hosted engine's tool vocabulary onto dsh's, plus the plan
3
+ * snapshot a hosted plan tool carries.
4
+ *
5
+ * The durable `tool/call` event is what the Web client's tool rows
6
+ * (`@deepseek-ai/dsh-client-ui-chat`'s tool Definition), the produced-files row
7
+ * and inline file links (`@deepseek-ai/dsh-client-ui-deliverables`'
8
+ * `mutationPath`), and the trajectory view read. Those consumers recognize only
9
+ * dsh's own tool names and argument shapes, while a hosted engine names its
10
+ * tools differently: Claude's `Write`/`Edit`/`Read`/`Bash`, Codex's
11
+ * `apply_patch`/`command_execution`, Kimi's title-cased `Bash`, Pi's
12
+ * `path`-keyed arguments. This module projects a hosted call onto dsh's
13
+ * vocabulary, and each driver feeds the projected values to BOTH writers — the
14
+ * durable `tool/call` event and the matching `tool-call` block in the assistant
15
+ * message that advertised it. Session V4 pairs the two by `id` and rejects a
16
+ * log whose block and event disagree on `name` or `arguments`, so the two sides
17
+ * must be byte-identical and both carry dsh's spelling. That spelling also lets
18
+ * an assistant message replayed into an in-process turn name a tool dsh's
19
+ * registry actually has (`bash`, not `Bash`).
20
+ *
21
+ * Only lossless projections are applied. A call whose arguments do not carry
22
+ * the dsh fields is passed through unchanged and simply renders as a generic
23
+ * row, so a new engine-side tool degrades instead of mis-rendering.
24
+ *
25
+ * Plan extraction is separate: dsh's todo panel is driven by the `todo/write`
26
+ * session event, not by the tool row, so a driver appends that event for the
27
+ * plan tool it recognizes.
28
+ *
29
+ * @module dsh-loop-engine-allinone/driver-core/hosted-tool-vocabulary
30
+ */
31
+ /** A hosted loop engine id — the settings engine union without `in-process`. */
32
+ export type { HostedEngineId } from '../engine-registry.ts';
33
+ import type { HostedEngineId } from '../engine-registry.ts';
34
+ /** One tool call projected into dsh's vocabulary for the durable `tool/call` event. */
35
+ export interface NormalizedHostedToolCall {
36
+ /** dsh tool name when the projection recognizes the call, else the engine's own spelling. */
37
+ readonly name: string;
38
+ /** dsh-shaped arguments JSON when the projection rewrites them, else the engine's own string. */
39
+ readonly arguments: string;
40
+ }
41
+ /** One plan entry in the shape the `todo/write` event and the todo panel consume. */
42
+ export interface HostedPlanTodo {
43
+ /** The task line, verbatim. */
44
+ readonly content: string;
45
+ /** Lifecycle state, restricted to dsh's three-state union. */
46
+ readonly status: 'pending' | 'in_progress' | 'completed';
47
+ }
48
+ declare module '@deepseek-ai/dsh-session/types' {
49
+ interface SessionEventMap {
50
+ 'todo/write': {
51
+ todos: {
52
+ content: string;
53
+ status: 'pending' | 'in_progress' | 'completed';
54
+ }[];
55
+ };
56
+ }
57
+ }
58
+ /**
59
+ * Project one hosted tool call onto dsh's `tool/call` vocabulary. A driver
60
+ * calls this once per call and writes the SAME name and arguments to both the
61
+ * assistant message's `tool-call` block and the durable `tool/call` event, so
62
+ * Session V4's id-and-payload pairing holds.
63
+ * @param engine - the hosted engine the call came from.
64
+ * @param name - the engine's own tool name.
65
+ * @param argumentsJson - the engine's arguments JSON, verbatim.
66
+ * @returns the dsh name and (when reshaped) dsh-shaped arguments.
67
+ */
68
+ export declare function normalizeHostedToolCall(engine: HostedEngineId, name: string, argumentsJson: string): NormalizedHostedToolCall;
69
+ /**
70
+ * Read the whole todo list a hosted plan tool wrote, in the shape the
71
+ * `todo/write` session event carries.
72
+ * @param engine - the hosted engine the call came from.
73
+ * @param name - the engine's own tool name.
74
+ * @param argumentsJson - the engine's arguments JSON, verbatim.
75
+ * @returns the plan entries (possibly empty) when the call is a plan write, else `undefined`.
76
+ */
77
+ export declare function planTodosOfHostedTool(engine: HostedEngineId, name: string, argumentsJson: string): readonly HostedPlanTodo[] | undefined;
78
+ //# sourceMappingURL=hosted-tool-vocabulary.d.ts.map
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Idle shutdown for a driver's persistent child process.
3
+ *
4
+ * Two engines keep one child alive per session so a step never pays a spawn:
5
+ * Kimi's `kimi acp` and Codex's app-server. Nothing in the harness releases an
6
+ * agent when a turn ends — an agent lives as long as its session's scope — so
7
+ * that child outlives the work that needed it and an idle session keeps
8
+ * costing what its child costs (tens to hundreds of MB for a Node CLI). The
9
+ * closer arms a countdown whenever its owner goes idle and runs the owner's
10
+ * close when the countdown expires, so the next step's own lazy accessor
11
+ * spawns a fresh child.
12
+ *
13
+ * The closer is inert unless `idleMs` is positive: a deployment that does not
14
+ * configure idle shutdown keeps every child for the process's lifetime, which
15
+ * is the behaviour that predates this reasoner.
16
+ *
17
+ * This is deliberately NOT an agent release: disposing the agent emits
18
+ * `session/disposed`, which the browser half reads as "this session is gone"
19
+ * with no way back in that page's lifetime (`router-loop.ts` `move`). Closing
20
+ * the child leaves the agent, the session, and the page exactly where they are.
21
+ *
22
+ * @module dsh-loop-engine-allinone/driver-core/idle-child
23
+ */
24
+ /** An armed-on-idle countdown that closes one child process. */
25
+ export interface IdleChildCloser {
26
+ /**
27
+ * (Re)start the countdown. Called when the owner settles into an idle phase;
28
+ * a no-op while idle shutdown is disabled.
29
+ */
30
+ arm(): void;
31
+ /**
32
+ * Cancel a pending countdown, for the moment the child is needed again.
33
+ * Cancelling a countdown that never armed is a no-op.
34
+ */
35
+ cancel(): void;
36
+ /**
37
+ * Cancel the countdown and drop the timer. Called from the owner's teardown,
38
+ * so a disposed agent never closes a child through a stale callback.
39
+ */
40
+ dispose(): void;
41
+ }
42
+ /** Input of {@link createIdleChildCloser}. */
43
+ export interface IdleChildCloserOptions {
44
+ /** Idle window in milliseconds; zero or less leaves the child alone forever. */
45
+ readonly idleMs: number;
46
+ /** Close the child; the owner's next accessor call spawns a fresh one. */
47
+ readonly close: () => void;
48
+ /** Report a failing close without letting it escape the countdown. */
49
+ readonly warn: (message: string) => void;
50
+ }
51
+ /**
52
+ * Build one owner's idle countdown.
53
+ * @param options - the idle window, the close to run, and a diagnostic sink.
54
+ * @returns the closer, inert while the idle window is not positive.
55
+ */
56
+ export declare function createIdleChildCloser(options: IdleChildCloserOptions): IdleChildCloser;
57
+ //# sourceMappingURL=idle-child.d.ts.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Image access for the hosted transcript. The transcript is text, so an image
3
+ * block of the durable log reaches an engine through it only as placeholder
4
+ * text — engines whose own protocol takes image bytes receive those bytes
5
+ * separately. The host's attachment service owns the normalized bytes and can
6
+ * name the read-only path they live at; this module turns that service into the
7
+ * resolver the transcript renders placeholders with.
8
+ *
9
+ * @module dsh-loop-engine-allinone/driver-core/image-access
10
+ */
11
+ import type { Context } from '@deepseek-ai/cordis';
12
+ import type { ImageAttachmentAccessResolver } from '@deepseek-ai/dsh-llm';
13
+ /**
14
+ * Build the resolver a hosted agent hands to `serializeHistory`, so a
15
+ * transcript can name the file behind each image the log carries.
16
+ *
17
+ * The service is read on every call — the pattern this plugin uses for every
18
+ * optional host service — so a resolver built before the attachment service
19
+ * mounts still answers once it has, and no path is ever cached across steps:
20
+ * the transcript stays a pure function of the durable log.
21
+ * @param ctx - the loop context whose host may compose the attachment service.
22
+ * @returns a resolver answering `{ readonlyPath }`, or `undefined` when the service or the path is absent.
23
+ */
24
+ export declare function createImageAccessResolver(ctx: Context): ImageAttachmentAccessResolver;
25
+ //# sourceMappingURL=image-access.d.ts.map
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Driver-owned durable inbox for the hosted engines.
3
+ *
4
+ * Harness 0.1.5 turned `Inbox` from a concrete class into an interface the
5
+ * driver owns, so this module carries the projection the plugin used to
6
+ * construct from `dsh-agent`: pending input is folded from the session's own
7
+ * `agent/inbox/spliced` events and every mutation commits a normalized splice
8
+ * back into that log before the live lists change. The durable event stream is
9
+ * what the web client's conversation reducer and session resume both read, so
10
+ * the semantics match the removed class exactly.
11
+ *
12
+ * @module dsh-loop-engine-allinone/driver-core/inbox
13
+ */
14
+ import type { Inbox, InboxTarget } from '@deepseek-ai/dsh-agent';
15
+ import type { MessageId } from '@deepseek-ai/dsh-llm';
16
+ import type { Session, UserMessage } from '@deepseek-ai/dsh-session';
17
+ /** Live notifications committed by inbox mutations. */
18
+ export interface InboxNotifications {
19
+ /** Publish one inserted message. */
20
+ inserted(message: UserMessage): void;
21
+ /** Publish one discarded message. */
22
+ discarded(message: UserMessage): void;
23
+ /** Publish one claimed message inside its owning turn. */
24
+ claimed(message: UserMessage, turn: number): void;
25
+ }
26
+ /**
27
+ * A replay-once projection of the session's durable inbox splices. Unlike the
28
+ * harness's driver inbox, this one keeps its own fold instead of registering a
29
+ * session projection, because the hosted engines drive sessions whose preset
30
+ * context is not the agent-loop's.
31
+ */
32
+ export declare class DriverInbox implements Inbox {
33
+ private readonly session;
34
+ private readonly notifications;
35
+ private readonly state;
36
+ constructor(session: Session, notifications: InboxNotifications);
37
+ /** Prompts awaiting individual turns. */
38
+ get nextTurn(): readonly UserMessage[];
39
+ /** Input awaiting the next step boundary. */
40
+ get nextStep(): readonly UserMessage[];
41
+ /** Whether either pending-message list contains work. */
42
+ get hasPending(): boolean;
43
+ /** Durably cancel all pending input, clearing next-step before next-turn. */
44
+ clear(): void;
45
+ /**
46
+ * Remove and return the complete batch proposed for one step, publishing
47
+ * each claimed message. The durable splices are pure deletions.
48
+ * @param target - whether this boundary also consumes one queued turn.
49
+ * @param turn - turn that will own the claimed batch.
50
+ * @returns next-step input followed by the queued turn, when requested.
51
+ */
52
+ claim(target: InboxTarget, turn: number): UserMessage[];
53
+ /**
54
+ * Append one message to a pending list and durably record the insertion.
55
+ * @param target - pending list to extend.
56
+ * @param message - message to append.
57
+ * @throws if the message identity is already pending.
58
+ */
59
+ append(target: InboxTarget, message: UserMessage): void;
60
+ /**
61
+ * Prepend one message to a pending list and durably record the insertion.
62
+ * @param target - pending list to extend.
63
+ * @param message - message to prepend.
64
+ * @throws if the message identity is already pending.
65
+ */
66
+ prepend(target: InboxTarget, message: UserMessage): void;
67
+ /**
68
+ * Replace one pending message in place, possibly changing its identity. A
69
+ * successful replacement publishes the old message as discarded and the new
70
+ * message as inserted.
71
+ * @param messageId - identity of the pending message to replace.
72
+ * @param newMessage - replacement message.
73
+ * @returns whether the message was still pending.
74
+ * @throws if the replacement duplicates another pending message identity.
75
+ */
76
+ replace(messageId: MessageId, newMessage: UserMessage): boolean;
77
+ /**
78
+ * Remove one pending message and durably record its cancellation.
79
+ * @param messageId - identity of the pending message to remove.
80
+ * @returns whether the message was still pending.
81
+ */
82
+ remove(messageId: MessageId): boolean;
83
+ /**
84
+ * Apply standard splice semantics and durably record the normalized result.
85
+ * The durable event commits before the live projection mutates, so
86
+ * synchronous `session/event` observers see the pre-splice lists and can
87
+ * reconstruct the removed messages from the normalized coordinates.
88
+ * @param target - pending list to mutate.
89
+ * @param start - splice position.
90
+ * @param deleteCount - maximum number of messages to remove.
91
+ * @param inserted - messages to insert at the resolved position.
92
+ * @returns messages removed by the splice.
93
+ */
94
+ splice(target: InboxTarget, start: number, deleteCount: number, inserted: UserMessage[]): UserMessage[];
95
+ /** Locate one pending identity across both owned lists. */
96
+ private locate;
97
+ /** Commit one normalized mutation and publish its live notifications. */
98
+ private mutate;
99
+ /** Apply one normalized durable splice to the projection. */
100
+ private apply;
101
+ /** Validate one normalized splice against the current projection. */
102
+ private validate;
103
+ }
104
+ //# sourceMappingURL=inbox.d.ts.map
@@ -0,0 +1,134 @@
1
+ /**
2
+ * The dsh endpoint, protocol, and credential a hosted engine is handed when a
3
+ * session selects a REAL dsh model — the second half of the model handover
4
+ * whose first half (`session-model.ts`) only carries the model name.
5
+ *
6
+ * A hosted engine owns its model natively, and today it also owns the endpoint
7
+ * and the credential: each CLI keeps its own provider table. That is why
8
+ * "handing over a dsh model" used to mean "the engine can find that model name
9
+ * in its own configuration". This module answers the other question — what
10
+ * `baseURL`, wire protocol, and credential does the session's selection name in
11
+ * dsh's own settings — so each driver can point its engine at dsh's endpoint.
12
+ *
13
+ * The two reads are the host's own seams, deliberately:
14
+ *
15
+ * - the provider → settings address mapping comes from the llm registry's
16
+ * configurable-provider directory (`LlmRuntime.listConfigurableProviders`,
17
+ * `packages/llm/llm/src/types.ts` `LlmConfigurableProvider`). That directory
18
+ * is the authoritative answer to "which namespace, at which path, configures
19
+ * provider X": `llm-pi-ai` maps a route to `['providers', route]` under
20
+ * `llm-pi-ai`, `llm-deepseek` maps its one route to the whole `llm-deepseek`
21
+ * section. Reading the directory rather than hardcoding namespaces is what
22
+ * keeps this plugin from inventing a mapping the deployment did not make.
23
+ * - the credential is resolved through the credentials seam, because the
24
+ * profile stores an `apiKeyEnv` NAME and its value lives in the harness's
25
+ * credential store, never in the process environment
26
+ * (`packages/bundle/base/cordis.patch.yml`).
27
+ *
28
+ * Both reads are reads of ANOTHER plugin's private namespace, and no contract in
29
+ * the harness guarantees their shape. Every step is therefore defensive: a shape
30
+ * this module does not recognize resolves to `undefined` (the engine keeps its
31
+ * own configuration, exactly today's behavior) and one warning, never a throw
32
+ * and never a guess. The warning names the provider and the model, never a
33
+ * credential.
34
+ *
35
+ * What counts as "recognized" is deliberately narrow: a non-empty `baseURL` and
36
+ * a resolvable credential. The wire protocol is handed over when the deployment
37
+ * declares one, but its absence does NOT refuse the handover — see
38
+ * {@link resolveModelHandover} and {@link SHIPPED_ROUTE_APIS}.
39
+ *
40
+ * @module dsh-loop-engine-allinone/driver-core/model-handover
41
+ */
42
+ import type { Context } from '@deepseek-ai/cordis';
43
+ import type { SessionModelOverride } from './session-model.ts';
44
+ /**
45
+ * The endpoint facts one hosted engine needs to speak to the dsh model a session
46
+ * selected: the model id, the base URL, dsh's wire protocol name for it, and the
47
+ * resolved credential value.
48
+ *
49
+ * The protocol is carried verbatim (`llm-pi-ai` values such as
50
+ * `anthropic-messages`, `openai-completions`, `openai-responses`), because each
51
+ * engine translates it into its own vocabulary — and an engine whose protocol
52
+ * the endpoint does not speak is left to fail loud on its own request rather
53
+ * than being silently given a different endpoint.
54
+ */
55
+ export interface DshModelHandover {
56
+ /** Provider route the selection named (the engine's provider key). */
57
+ readonly provider: string;
58
+ /** Provider-owned model id the selection named. */
59
+ readonly model: string;
60
+ /** Endpoint base as dsh configured it. */
61
+ readonly baseURL: string;
62
+ /**
63
+ * dsh's wire protocol name for this endpoint, when the deployment declares
64
+ * one (or {@link SHIPPED_ROUTE_APIS} knows it for a shipped route). `undefined`
65
+ * is a normal answer, not a failure: engines that need a protocol degrade the
66
+ * way each one documents, and engines that do not (`claude-code`) ignore it.
67
+ */
68
+ readonly api: string | undefined;
69
+ /** The resolved credential value; never logged, never evented. */
70
+ readonly apiKey: string;
71
+ }
72
+ /**
73
+ * One entry of the host llm registry's configurable-provider directory
74
+ * (`LlmConfigurableProvider`), narrowed to the address fields this module reads.
75
+ */
76
+ export interface ConfigurableProviderAddress {
77
+ /** Provider route key the entry activates when configured. */
78
+ readonly provider: string;
79
+ /** User-settings namespace whose section configures this provider. */
80
+ readonly settingsNs: string;
81
+ /** Path from that section root to this provider's profile; empty when the section IS the profile. */
82
+ readonly settingsPath: readonly string[];
83
+ }
84
+ /**
85
+ * The host llm registry (`ctx.llm`), as this module uses it.
86
+ *
87
+ * `listConfigurableProviders` is optional: a minimal profile may serve the
88
+ * registry without the directory, and an older harness may predate it. A
89
+ * missing directory is "cannot map", not an error — the engine keeps its own
90
+ * configuration.
91
+ */
92
+ export interface LlmDirectoryService {
93
+ /** Every provider route an adapter can activate through configuration. */
94
+ listConfigurableProviders?(): readonly ConfigurableProviderAddress[];
95
+ }
96
+ /** The host settings service (`ctx.settings`), as this module uses it. */
97
+ export interface SettingsReader {
98
+ /** Read one registered namespace's resolved value. */
99
+ get?(ns: string): unknown;
100
+ }
101
+ /** The host credentials seam (`ctx.credentials`), as this module uses it. */
102
+ export interface CredentialsService {
103
+ /** Resolve one reference (an environment-variable NAME) to its current value. */
104
+ resolve(ref: string): Promise<{
105
+ readonly value: string;
106
+ } | undefined>;
107
+ }
108
+ /**
109
+ * Resolve the session's own model selection into the endpoint triple a hosted
110
+ * engine can dial, or `undefined` to leave the engine to its own configuration.
111
+ *
112
+ * `undefined` is the answer in exactly two situations: the selection names no
113
+ * real dsh model ({@link SessionModelOverride} is already `undefined` for the
114
+ * hosted seat), or a real model whose endpoint/credential dsh does not disclose
115
+ * to this read — no `baseURL`, or no credential. Both warn once: they are
116
+ * deployment-shape gaps the operator can see and fix, not a silent downgrade.
117
+ *
118
+ * The wire protocol is NOT such a gate. A profile that names no `api` still
119
+ * hands over its endpoint (with `api: undefined`), because refusing would let
120
+ * the engine send dsh's model id to the engine's OWN endpoint — a failure that
121
+ * reads like an auth or model problem while the real one is "wrong endpoint".
122
+ * Shipped routes whose adapter owns the wire are named in
123
+ * {@link SHIPPED_ROUTE_APIS} so they hand over a real protocol; anything still
124
+ * unknown degrades per engine, which is the engine's call to make.
125
+ *
126
+ * Called fresh on every step by each driver, so a model or provider picked
127
+ * mid-conversation reaches the engine's next request rather than being frozen
128
+ * when the agent was built.
129
+ * @param ctx - the driver's context, carrying the llm/settings/credentials seams.
130
+ * @param override - the session's dsh model selection, already judged by `sessionModelOverrideOf`.
131
+ * @returns the resolvable endpoint triple, or undefined to inject nothing.
132
+ */
133
+ export declare function resolveModelHandover(ctx: Context, override: SessionModelOverride | undefined): Promise<DshModelHandover | undefined>;
134
+ //# sourceMappingURL=model-handover.d.ts.map
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Shared engine ownership and abort-race machinery for the hosted engines.
3
+ * All four loop drivers (Claude Code, Codex, Pi, Kimi Code) run the same
4
+ * lifecycle: one runtime per engine owns that engine's live agents, every
5
+ * live agent's teardown is tracked until it settles, and setup awaits are
6
+ * raced against a fused abort signal. The process-wide AgentFactory slot is
7
+ * the router's, not any engine's; these helpers are engine-free — they only
8
+ * touch the fiber state, the session id type, and an AbortController — so the
9
+ * engine modules share them verbatim.
10
+ *
11
+ * @module dsh-loop-engine-allinone/driver-core/ownership
12
+ */
13
+ import type { Context } from '@deepseek-ai/cordis';
14
+ import type { SessionId } from '@deepseek-ai/dsh-session';
15
+ /** Fiber states that cannot own or serve a new lifecycle. */
16
+ export declare const INACTIVE_STATES: ReadonlySet<number>;
17
+ /** Factory-level ownership: live agent teardowns plus load-time tracking. */
18
+ export declare class FactoryOwnership {
19
+ private readonly fiber;
20
+ private accepting;
21
+ private readonly teardown;
22
+ private readonly inactive;
23
+ private readonly liveAgents;
24
+ private startupTasks;
25
+ constructor(fiber: Context['fiber']);
26
+ /** Aborts (reason: `agent loop is not active` error) when factory teardown begins. */
27
+ get signal(): AbortSignal;
28
+ isActive(): boolean;
29
+ /** Track one live agent's shared teardown until it has run. */
30
+ track(dispose: () => Promise<void>): () => void;
31
+ /** Join config startup work that begins before an agent exists. */
32
+ trackStartup(job: Promise<void>): void;
33
+ /** Join one public create/resume continuation; factory dispose awaits its settlement. */
34
+ trackWrapper(job: Promise<unknown>): void;
35
+ dispose(): Promise<void>;
36
+ }
37
+ /** Await `operation`, or throw the signal's reason as soon as it aborts. */
38
+ export declare function raceAbort<T>(operation: PromiseLike<T> | T, signal: AbortSignal, id: SessionId): Promise<T>;
39
+ /** Start an abortable operation and release a value that arrives after cancellation. */
40
+ export declare function raceAbortCall<T>(operation: () => PromiseLike<T> | T, signal: AbortSignal, id: SessionId, releaseAbandoned?: (value: T) => void): Promise<T>;
41
+ //# sourceMappingURL=ownership.d.ts.map
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Reading the dsh session's durable permission knobs from the session log.
3
+ * Every hosted driver folds the same `sandbox/mode` and
4
+ * `approval/policy` events (pinned at creation, re-recorded on every switch)
5
+ * into per-query permission decisions; the knob readers are engine-free.
6
+ *
7
+ * @module dsh-loop-engine-allinone/driver-core/permission-knobs
8
+ */
9
+ import type { SessionEvent } from '@deepseek-ai/dsh-session';
10
+ /**
11
+ * Minimal structural shape of one session log event. The base `SessionEvent`
12
+ * union in this compilation does not carry the sandbox/approval packages'
13
+ * augmentation keys, so the fold reads the wire shape directly.
14
+ */
15
+ export type PermissionEvent = Pick<SessionEvent, 'data'> & {
16
+ readonly type: string;
17
+ };
18
+ /** dsh sandbox modes, mirrored inline to avoid a peer dep on @deepseek-ai/dsh-sandbox-policy. */
19
+ export type DshSandboxMode = 'read-only' | 'workspace-write' | 'danger-full-access';
20
+ /** dsh approval policies, mirrored inline to avoid a peer dep on @deepseek-ai/dsh-user-approval. */
21
+ export type DshApprovalPolicy = 'ask' | 'never';
22
+ /** The session's sandbox-mode override: the last `sandbox/mode` event, if any. */
23
+ export declare function sessionSandboxMode(events: readonly PermissionEvent[]): DshSandboxMode | undefined;
24
+ /** The session's approval-policy override: the last `approval/policy` event, if any. */
25
+ export declare function sessionApprovalPolicy(events: readonly PermissionEvent[]): DshApprovalPolicy | undefined;
26
+ //# sourceMappingURL=permission-knobs.d.ts.map
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Serialization of the durable session history into the prompt text of one
3
+ * hosted-engine query. Every hosted driver builds its
4
+ * per-step input from the durable session log: the transcript is the log's
5
+ * exact projection, so a later replay of the same log derives the identical
6
+ * prompt (Model-visible ⟺ logged bridge).
7
+ *
8
+ * A step whose live request is an engine slash command is the one exception to
9
+ * the transcript framing: {@link engineSlashPrompt} sends that command line
10
+ * verbatim, because the engines only recognize their own commands at the head
11
+ * of the prompt. It is still derived from the log alone, so the guarantee
12
+ * holds.
13
+ *
14
+ * An image block has no bytes in this output — the transcript is text — so it
15
+ * renders as placeholder text naming the image and the read-only path
16
+ * {@link createImageAccessResolver} resolves for it. The reference is the
17
+ * log's own, so the placeholder keeps the replay guarantee too, and it stays
18
+ * the invariant every engine keeps even when the engine's own protocol also
19
+ * receives the bytes ({@link stepImages}).
20
+ *
21
+ * @module dsh-loop-engine-allinone/driver-core/prompt
22
+ */
23
+ import type { ImageAttachmentAccessResolver, Message } from '@deepseek-ai/dsh-llm';
24
+ /** The one fact every omitted image placeholder states: a hosted engine takes text, never image bytes. */
25
+ export declare const OMITTED_IMAGE_TEXT = "this engine receives text, not image bytes";
26
+ /**
27
+ * The engine's own slash-command line to send as this step's entire prompt, or
28
+ * `undefined` when the step is an ordinary conversational step.
29
+ *
30
+ * Every hosted engine expands a slash command only when the text handed to it
31
+ * *starts* with `/` — Kimi's ACP adapter parses the first prompt block, Claude
32
+ * Code's local-command dispatch and Pi's input expansion both test the leading
33
+ * character of the message string. The serialized transcript never satisfies
34
+ * that (it opens with `<user>`), so a forwarded `/status` reaches the model as
35
+ * prose instead of the engine's own command surface. This helper lets a driver
36
+ * recognize the case and send the command line verbatim, with no transcript
37
+ * framing and no replay history: a slash command is a control line for the
38
+ * engine, not conversation for the model.
39
+ *
40
+ * The live request is the last derived message, so a step whose trailing
41
+ * message is a bare command line is a command step. A trailing skill-injection
42
+ * message (the `/name` skill gesture the drivers materialize as its own user
43
+ * message) displaces it and keeps the step on the transcript path.
44
+ *
45
+ * The returned line is a pure function of the log prefix, so the step stays
46
+ * replayable: the same log derives the same prompt.
47
+ * @param messages - derived history, oldest first, as returned by
48
+ * `Session.deriveMessages()` at step time.
49
+ * @returns the raw command line, or `undefined` for an ordinary step.
50
+ */
51
+ export declare function engineSlashPrompt(messages: readonly Message[]): string | undefined;
52
+ /**
53
+ * Serialize a derived conversation history into the prompt text of one hosted
54
+ * query. The last message is the live user request that triggered the step;
55
+ * every earlier message is durable replay context. The output is a pure
56
+ * function of the log prefix.
57
+ * @param messages - derived history, oldest first, as returned by
58
+ * `Session.deriveMessages()` at step time.
59
+ * @param imageAccess - resolves the read-only path of an image block's
60
+ * attachment; without one, an image renders as the no-path placeholder.
61
+ * @returns the prompt text to pass to the engine.
62
+ */
63
+ export declare function serializeHistory(messages: readonly Message[], imageAccess?: ImageAttachmentAccessResolver): string;
64
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1,62 @@
1
+ /**
2
+ * The session-scoped half of one published hosted transaction: the session's
3
+ * entry in the store, and the write handle that stores its events.
4
+ *
5
+ * Ownership is ONE object rather than two closure variables because an engine
6
+ * swap MOVES it. A hot swap replaces a session's agent while the session itself
7
+ * stays live: the retiring machine hands its lifetime to the successor instead
8
+ * of releasing it, and the successor releases it later exactly as the agent that
9
+ * entered the session would have. Releasing it at the handover point would emit
10
+ * `session/disposed`, which the browser half reads as the session being gone —
11
+ * its session list drops the row, its composer renders "session unavailable",
12
+ * and the conversation view falls back to the workspace picker — so a live
13
+ * session would be torn out from under the page attached to it.
14
+ *
15
+ * The two release steps are separate operations because their ORDER around the
16
+ * agent registry's own release is load-bearing: `agent/disposed` is published
17
+ * after driver quiescence and BEFORE the session is detached (the event's
18
+ * contract in `@deepseek-ai/dsh-agent`), and the write handle closes before the
19
+ * store attachment is released so its buffered closing events are drained
20
+ * durably. Users of this type therefore close the handle, detach the agent, then
21
+ * leave the store.
22
+ *
23
+ * Neither step needs a memo of its own: `SessionHandle.close()` is idempotent by
24
+ * contract, and the detacher `SessionsService.enter` returns is single-shot.
25
+ *
26
+ * @module dsh-loop-engine-allinone/driver-core/session-lifetime
27
+ */
28
+ import type { Session } from '@deepseek-ai/dsh-session';
29
+ import type { SessionHandle } from '@deepseek-ai/dsh-session-persistence';
30
+ /**
31
+ * One live session's lifetime resources, owned by whichever agent drives it.
32
+ */
33
+ export declare class SessionLifetime {
34
+ /** The live session these resources belong to. */
35
+ readonly session: Session;
36
+ /** The write handle this lifetime owns, or `undefined` when no persistence backend is mounted. */
37
+ private readonly handle;
38
+ /** The store's detacher; `undefined` until the entry is bound by the transaction that entered the session. */
39
+ private detach;
40
+ /**
41
+ * @param session - the live session whose entry and write handle these are.
42
+ * @param handle - the write handle the transaction acquired, if a backend is mounted.
43
+ */
44
+ constructor(session: Session, handle: SessionHandle | undefined);
45
+ /**
46
+ * Whether the session's store entry is already held: true for a lifetime a
47
+ * retiring machine handed over, false for one whose transaction still has to
48
+ * enter the session it prepared.
49
+ */
50
+ get entered(): boolean;
51
+ /**
52
+ * Bind the store entry this lifetime owns. Called once, by the transaction
53
+ * that enters the session; a joined session's entry is already bound.
54
+ * @param detach - the detacher the session's own `enter` returned.
55
+ */
56
+ bind(detach: () => void): void;
57
+ /** Drain and close the write handle — the durability barrier that precedes leaving the store. */
58
+ closeHandle(): Promise<void>;
59
+ /** Remove the session from the store, publishing its paired disposal exactly once. */
60
+ leaveStore(): void;
61
+ }
62
+ //# sourceMappingURL=session-lifetime.d.ts.map