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.
- package/CHANGELOG.md +100 -0
- package/CONTRIBUTING.md +78 -0
- package/LICENSE +23 -0
- package/NOTICE +45 -0
- package/README.md +221 -2
- package/README.zh.md +89 -0
- package/SECURITY.md +39 -0
- package/cordis.patch.yml +3 -0
- package/lib/client.js +2166 -0
- package/lib/index.js +11621 -0
- package/lib/invariant.js +453 -0
- package/lib/types/agent-preset-ids.d.ts +276 -0
- package/lib/types/client/LoopEngineBadge.d.ts +71 -0
- package/lib/types/client/LoopEngineComposerSelect.d.ts +126 -0
- package/lib/types/client/LoopEngineSection.d.ts +35 -0
- package/lib/types/client/engine-marks.d.ts +87 -0
- package/lib/types/client/index.d.ts +39 -0
- package/lib/types/client/locales.d.ts +182 -0
- package/lib/types/client/reload.d.ts +135 -0
- package/lib/types/client/session-engine.d.ts +508 -0
- package/lib/types/client/store.d.ts +103 -0
- package/lib/types/client/turn-status.d.ts +234 -0
- package/lib/types/client/use-session-engine.d.ts +74 -0
- package/lib/types/commands.d.ts +77 -0
- package/lib/types/compat.d.ts +25 -0
- package/lib/types/driver-acp/agent.d.ts +289 -0
- package/lib/types/driver-acp/approval.d.ts +27 -0
- package/lib/types/driver-acp/capabilities.d.ts +200 -0
- package/lib/types/driver-acp/client.d.ts +297 -0
- package/lib/types/driver-acp/executable.d.ts +53 -0
- package/lib/types/driver-acp/mapping.d.ts +76 -0
- package/lib/types/driver-acp/profile.d.ts +126 -0
- package/lib/types/driver-acp/runtime.d.ts +45 -0
- package/lib/types/driver-acp/subprocess.d.ts +19 -0
- package/lib/types/driver-acp/terminal.d.ts +98 -0
- package/lib/types/driver-acp/transport.d.ts +43 -0
- package/lib/types/driver-acp/types.d.ts +152 -0
- package/lib/types/driver-cli/capability.d.ts +42 -0
- package/lib/types/driver-cli/cli-agent.d.ts +258 -0
- package/lib/types/driver-cli/cli-loop.d.ts +46 -0
- package/lib/types/driver-cli/flatten.d.ts +35 -0
- package/lib/types/driver-cli/frames.d.ts +128 -0
- package/lib/types/driver-cli/ndjson.d.ts +106 -0
- package/lib/types/driver-cli/session-sink.d.ts +333 -0
- package/lib/types/driver-cli/stream-json.d.ts +61 -0
- package/lib/types/driver-cli/text.d.ts +66 -0
- package/lib/types/driver-cli/transport.d.ts +84 -0
- package/lib/types/driver-core/agents-md-skill-provider.d.ts +72 -0
- package/lib/types/driver-core/assistant-stream.d.ts +68 -0
- package/lib/types/driver-core/context-files.d.ts +62 -0
- package/lib/types/driver-core/host-servers.d.ts +119 -0
- package/lib/types/driver-core/hosted-engine-runtime.d.ts +190 -0
- package/lib/types/driver-core/hosted-tool-vocabulary.d.ts +78 -0
- package/lib/types/driver-core/idle-child.d.ts +57 -0
- package/lib/types/driver-core/image-access.d.ts +25 -0
- package/lib/types/driver-core/inbox.d.ts +104 -0
- package/lib/types/driver-core/model-handover.d.ts +134 -0
- package/lib/types/driver-core/ownership.d.ts +41 -0
- package/lib/types/driver-core/permission-knobs.d.ts +26 -0
- package/lib/types/driver-core/prompt.d.ts +64 -0
- package/lib/types/driver-core/session-lifetime.d.ts +62 -0
- package/lib/types/driver-core/session-model.d.ts +128 -0
- package/lib/types/driver-core/skill-inject.d.ts +59 -0
- package/lib/types/driver-core/step-close.d.ts +49 -0
- package/lib/types/driver-core/step-images.d.ts +62 -0
- package/lib/types/driver-core/step-tools.d.ts +43 -0
- package/lib/types/driver-core/system-head.d.ts +43 -0
- package/lib/types/engine-agy/agent.d.ts +67 -0
- package/lib/types/engine-agy/frames.d.ts +90 -0
- package/lib/types/engine-agy/loop.d.ts +64 -0
- package/lib/types/engine-agy/process.d.ts +173 -0
- package/lib/types/engine-claude/agent.d.ts +186 -0
- package/lib/types/engine-claude/loop.d.ts +73 -0
- package/lib/types/engine-claude/mapping.d.ts +108 -0
- package/lib/types/engine-claude/permission.d.ts +41 -0
- package/lib/types/engine-claude/process.d.ts +59 -0
- package/lib/types/engine-claude/sdk.d.ts +67 -0
- package/lib/types/engine-claude/types.d.ts +28 -0
- package/lib/types/engine-codex/agent.d.ts +216 -0
- package/lib/types/engine-codex/appserver/client.d.ts +80 -0
- package/lib/types/engine-codex/appserver/mapping.d.ts +67 -0
- package/lib/types/engine-codex/appserver/thread.d.ts +66 -0
- package/lib/types/engine-codex/appserver/types.d.ts +225 -0
- package/lib/types/engine-codex/loop.d.ts +75 -0
- package/lib/types/engine-codex/model-handover.d.ts +56 -0
- package/lib/types/engine-codex/permission.d.ts +126 -0
- package/lib/types/engine-codex/skills.d.ts +28 -0
- package/lib/types/engine-codex/types.d.ts +36 -0
- package/lib/types/engine-drivers.d.ts +132 -0
- package/lib/types/engine-grok/agent.d.ts +24 -0
- package/lib/types/engine-grok/loop.d.ts +61 -0
- package/lib/types/engine-grok/process.d.ts +46 -0
- package/lib/types/engine-grok/profile.d.ts +82 -0
- package/lib/types/engine-hermes/agent.d.ts +47 -0
- package/lib/types/engine-hermes/loop.d.ts +56 -0
- package/lib/types/engine-hermes/process.d.ts +92 -0
- package/lib/types/engine-kimi/acp/client.d.ts +123 -0
- package/lib/types/engine-kimi/acp/mapping.d.ts +73 -0
- package/lib/types/engine-kimi/acp/types.d.ts +143 -0
- package/lib/types/engine-kimi/agent.d.ts +24 -0
- package/lib/types/engine-kimi/commands.d.ts +44 -0
- package/lib/types/engine-kimi/loop.d.ts +62 -0
- package/lib/types/engine-kimi/model-handover.d.ts +32 -0
- package/lib/types/engine-kimi/permission.d.ts +28 -0
- package/lib/types/engine-kimi/process.d.ts +47 -0
- package/lib/types/engine-kimi/profile.d.ts +19 -0
- package/lib/types/engine-kimi/skills.d.ts +52 -0
- package/lib/types/engine-kimi/types.d.ts +25 -0
- package/lib/types/engine-minimaxcode/agent.d.ts +24 -0
- package/lib/types/engine-minimaxcode/loop.d.ts +83 -0
- package/lib/types/engine-minimaxcode/process.d.ts +53 -0
- package/lib/types/engine-minimaxcode/profile.d.ts +72 -0
- package/lib/types/engine-of-session.d.ts +97 -0
- package/lib/types/engine-pi/agent.d.ts +230 -0
- package/lib/types/engine-pi/loop.d.ts +72 -0
- package/lib/types/engine-pi/model-handover.d.ts +84 -0
- package/lib/types/engine-pi/permission.d.ts +47 -0
- package/lib/types/engine-pi/rpc/client.d.ts +107 -0
- package/lib/types/engine-pi/rpc/mapping.d.ts +37 -0
- package/lib/types/engine-pi/rpc/types.d.ts +249 -0
- package/lib/types/engine-pi/skills.d.ts +47 -0
- package/lib/types/engine-pi/types.d.ts +36 -0
- package/lib/types/engine-qoderclicn/agent.d.ts +59 -0
- package/lib/types/engine-qoderclicn/loop.d.ts +51 -0
- package/lib/types/engine-qoderclicn/process.d.ts +113 -0
- package/lib/types/engine-registry.d.ts +584 -0
- package/lib/types/engine-remote.d.ts +192 -0
- package/lib/types/engine-surface.d.ts +36 -0
- package/lib/types/engine-zcode/agent.d.ts +50 -0
- package/lib/types/engine-zcode/loop.d.ts +47 -0
- package/lib/types/engine-zcode/process.d.ts +111 -0
- package/lib/types/index.d.ts +205 -0
- package/lib/types/invariant.d.ts +26 -0
- package/lib/types/model-selection-reset.d.ts +271 -0
- package/lib/types/namespace.d.ts +25 -0
- package/lib/types/patch-manager.d.ts +104 -0
- package/lib/types/preset.d.ts +254 -0
- package/lib/types/provider-route.d.ts +245 -0
- package/lib/types/router-loop.d.ts +458 -0
- package/lib/types/session-engine-store.d.ts +138 -0
- package/lib/types/settings.d.ts +60 -0
- package/lib/types/skills.d.ts +85 -0
- package/package.json +150 -4
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The plugin's own Remote: "which engine does this session run?" and "move this
|
|
3
|
+
* session to another engine", both answered from the plugin's own per-session
|
|
4
|
+
* record, the session's live agent, and the durable log through one shared read.
|
|
5
|
+
*
|
|
6
|
+
* The browser half cannot answer the first question honestly from what the
|
|
7
|
+
* harness hands a page. The client Session list carries `projectionValues`
|
|
8
|
+
* computed by `@deepseek-ai/dsh-api-session-controller`'s `projectionsFor()`,
|
|
9
|
+
* which returns a `SessionProjectionHints` snapshot — "every currently cached
|
|
10
|
+
* wire value", and partial by its own documentation: a cell the page's cache has
|
|
11
|
+
* not folded yet is simply absent. The engine a session ACTUALLY runs is not a
|
|
12
|
+
* cache fact at all, so the plugin becomes its own authority:
|
|
13
|
+
*
|
|
14
|
+
* - node half (here): a Typert Remote service, discovered by the host Gateway
|
|
15
|
+
* through its visible `typertRemote` binding and its `@Remote` method marks
|
|
16
|
+
* (`bindTypertRemote` / `@Remote` in `@deepseek-ai/dsh-typert-protocol`, the
|
|
17
|
+
* same mechanism `@deepseek-ai/dsh-agent-presets` uses for its own roster).
|
|
18
|
+
* Both endpoints go through {@link engineReportOfSession} /
|
|
19
|
+
* {@link RouterLoop.reportEngine} / {@link RouterLoop.selectEngine} — the very
|
|
20
|
+
* reads the router routes on — so what a session is driven by and what a
|
|
21
|
+
* session is shown as running cannot disagree, because there is one answer.
|
|
22
|
+
* The report carries the ONE case in which a session has two facts (a live
|
|
23
|
+
* agent and a record that did not displace it) as two fields rather than
|
|
24
|
+
* blending them; see {@link SessionEngineReport}.
|
|
25
|
+
* - browser half (`src/client/session-engine.ts`): mounts these endpoints as
|
|
26
|
+
* `remote.loopEngine.engine({ sessionId })` and
|
|
27
|
+
* `remote.loopEngine.select({ sessionId, engine })`, and renders only what
|
|
28
|
+
* they answer.
|
|
29
|
+
*
|
|
30
|
+
* Both methods take a PLAIN object parameter rather than an identity the Gateway
|
|
31
|
+
* resolves: typert resolves a parameter named `agent`/`session` into a LIVE
|
|
32
|
+
* object through its lookup providers, and these endpoints must answer for any
|
|
33
|
+
* PERSISTED session — including one no process has loaded.
|
|
34
|
+
*
|
|
35
|
+
* Wire contract (no codegen is involved; the Gateway derives the signature from
|
|
36
|
+
* the live method):
|
|
37
|
+
*
|
|
38
|
+
* - endpoint `loopEngine/engine`;
|
|
39
|
+
* - endpoint `loopEngine/select`;
|
|
40
|
+
* - one `src-json` argument per endpoint whose wire name is the method's own
|
|
41
|
+
* parameter name (`request`) — REQUIRED for the browser half to be
|
|
42
|
+
* understood, so the parameter name is part of the contract and must not be
|
|
43
|
+
* renamed or destructured (see the Gateway's `methodParameterNames`);
|
|
44
|
+
* - `engine` results in the plain-JSON {@link SessionEngineReport} — the engine
|
|
45
|
+
* the session ACTUALLY runs, plus (only while a live agent the record did not
|
|
46
|
+
* displace keeps running) the one the record names; `select` results in the
|
|
47
|
+
* plain-JSON {@link LoopEngineSelectResult} — a refusal is a VALUE, so a
|
|
48
|
+
* predictable "no" travels as data the surface can render (a
|
|
49
|
+
* {@link LoopEngineRefusalCode} plus the host's own sentence as detail, which
|
|
50
|
+
* is what lets the browser half show localized copy instead of a raw English
|
|
51
|
+
* one-liner), while only a malformed request is a `RemoteError`, and an
|
|
52
|
+
* outcome carrying `reload` tells the browser half to reload the page, because
|
|
53
|
+
* the switch was made to land by releasing the session's agent.
|
|
54
|
+
*
|
|
55
|
+
* @module dsh-loop-engine-allinone/engine-remote
|
|
56
|
+
*/
|
|
57
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
58
|
+
import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
59
|
+
import { SessionId } from '@deepseek-ai/dsh-session';
|
|
60
|
+
import { type LoopEngineId, type SessionEngine, type SessionEngineReport, type LoopEngineSelectResult } from './agent-preset-ids.ts';
|
|
61
|
+
/** Cordis service key AND wire namespace of the plugin's own Remote. */
|
|
62
|
+
export declare const LOOP_ENGINE_REMOTE_KEY = "loopEngine";
|
|
63
|
+
/** Endpoint method reporting one session's engine. */
|
|
64
|
+
export declare const LOOP_ENGINE_REMOTE_METHOD = "engine";
|
|
65
|
+
/** Endpoint method moving one session to another engine. */
|
|
66
|
+
export declare const LOOP_ENGINE_REMOTE_SELECT_METHOD = "select";
|
|
67
|
+
/** The wire request the reporting endpoint accepts. */
|
|
68
|
+
export interface LoopEngineRequest {
|
|
69
|
+
/** The session to report on. A plain string, never a resolved live object. */
|
|
70
|
+
readonly sessionId: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The wire request the switching endpoint accepts. The engine is typed as a
|
|
74
|
+
* string because that is what the wire carries; the endpoint validates it
|
|
75
|
+
* against {@link LOOP_ENGINE_IDS} before anything acts on it.
|
|
76
|
+
*/
|
|
77
|
+
export interface LoopEngineSelectRequest {
|
|
78
|
+
/** The session to move. A plain string, never a resolved live object. */
|
|
79
|
+
readonly sessionId: string;
|
|
80
|
+
/** The engine that session should run. */
|
|
81
|
+
readonly engine: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The engine one session runs, read from the plugin's own record and the durable
|
|
85
|
+
* log (`engineOfSession`).
|
|
86
|
+
*
|
|
87
|
+
* The FALLBACK answer, not the whole one: it knows nothing about a live agent, so
|
|
88
|
+
* the endpoint uses it only while no router is mounted
|
|
89
|
+
* ({@link RouterSurfaceHolder}) — the mount window, in which no session is driven
|
|
90
|
+
* by this plugin anyway.
|
|
91
|
+
*/
|
|
92
|
+
export type SessionEngineResolver = (sessionId: SessionId) => Promise<SessionEngine>;
|
|
93
|
+
/** Move one session to another engine, refusing with a reason rather than throwing. */
|
|
94
|
+
export type SessionEngineSelector = (sessionId: SessionId, engine: LoopEngineId) => Promise<LoopEngineSelectResult>;
|
|
95
|
+
/**
|
|
96
|
+
* The mounted loop router, as these two endpoints need it: the reporting read
|
|
97
|
+
* and the move, both of which only a live router can make.
|
|
98
|
+
*
|
|
99
|
+
* Structural rather than the class itself, so this module takes no build-time
|
|
100
|
+
* dependency on `./router-loop.ts` (which drags in the harness loop and every
|
|
101
|
+
* engine driver) and a test can stand in for it.
|
|
102
|
+
*/
|
|
103
|
+
export interface RouterSurface {
|
|
104
|
+
/** Report what one session actually runs, plus the recorded engine when the two differ. */
|
|
105
|
+
reportEngine(sessionId: SessionId): Promise<SessionEngineReport>;
|
|
106
|
+
/** Move one session to another engine, or answer why it was not moved. */
|
|
107
|
+
selectEngine(sessionId: SessionId, engine: LoopEngineId): Promise<LoopEngineSelectResult>;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Where the two endpoints find the mounted router.
|
|
111
|
+
*
|
|
112
|
+
* A holder rather than a fixed reference because the router is mounted
|
|
113
|
+
* asynchronously — and not at all until the harness's live patch reload drops the
|
|
114
|
+
* base bundle's `agent-loop` row (`src/index.ts` `mountRouter`). Until then both
|
|
115
|
+
* endpoints answer from what a router-less process still knows: the record and
|
|
116
|
+
* the log. A session that is not driven by this plugin has no live agent to
|
|
117
|
+
* report anyway, so the answers agree.
|
|
118
|
+
*/
|
|
119
|
+
export interface RouterSurfaceHolder {
|
|
120
|
+
/** The mounted router, or undefined while there is no router. */
|
|
121
|
+
current: RouterSurface | undefined;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* `remote.loopEngine`: report one session's engine, and move it to another.
|
|
125
|
+
*
|
|
126
|
+
* Registered as a Cordis service under {@link LOOP_ENGINE_REMOTE_KEY} on the
|
|
127
|
+
* plugin's own fiber, so the binding and the method marks disappear with the
|
|
128
|
+
* plugin: a profile that mounts no Gateway never discovers it, and unmounting
|
|
129
|
+
* the plugin withdraws both.
|
|
130
|
+
*/
|
|
131
|
+
export declare class LoopEngineRemote extends TypertRemoteService {
|
|
132
|
+
private readonly resolve;
|
|
133
|
+
private readonly router;
|
|
134
|
+
private readonly warn;
|
|
135
|
+
/**
|
|
136
|
+
* @param ctx - the context the service (and its lifetime) belongs to.
|
|
137
|
+
* @param resolve - the router-less read; normally
|
|
138
|
+
* `engineOfSession(ctx, sessionId, records)`.
|
|
139
|
+
* @param router - where both endpoints find the mounted loop router.
|
|
140
|
+
* @param warn - diagnostic sink for a session that could not be read.
|
|
141
|
+
*/
|
|
142
|
+
constructor(ctx: Context, resolve: SessionEngineResolver, router: RouterSurfaceHolder, warn: (message: string) => void);
|
|
143
|
+
/**
|
|
144
|
+
* Report what one session runs — and, when its own record names a different
|
|
145
|
+
* engine than the live agent, that fact separately.
|
|
146
|
+
*
|
|
147
|
+
* The router answers when it is mounted, because the live agent outranks every
|
|
148
|
+
* record: only the router knows which engine built the agent driving this
|
|
149
|
+
* session now, and only the router can tell a record whose release did not take
|
|
150
|
+
* from one that already landed. Without a router (the mount-retry window) no
|
|
151
|
+
* session is driven by this plugin, so the record — i.e.
|
|
152
|
+
* {@link SessionEngineResolver} — is the whole answer.
|
|
153
|
+
*
|
|
154
|
+
* A session that cannot be read answers `unset` rather than throwing: a
|
|
155
|
+
* surface that asked about a session the durable log does not know must render
|
|
156
|
+
* "engine not recorded", not break the page it is rendered in. Failures are
|
|
157
|
+
* reported once on the host's log instead.
|
|
158
|
+
*
|
|
159
|
+
* A malformed REQUEST is a caller fault, not an unreadable session, and is
|
|
160
|
+
* refused the way every typert endpoint refuses one.
|
|
161
|
+
* @param request - the wire request carrying the session id.
|
|
162
|
+
* @returns the engine driving that session, plus the recorded engine it is not
|
|
163
|
+
* running when the two differ.
|
|
164
|
+
* @throws {RemoteError} with `gateway/bad-request` when no session id was sent.
|
|
165
|
+
*/
|
|
166
|
+
engine(request: LoopEngineRequest): Promise<SessionEngineReport>;
|
|
167
|
+
/**
|
|
168
|
+
* Move one session to another engine.
|
|
169
|
+
*
|
|
170
|
+
* The move owns no policy of its own: the router decides whether this session
|
|
171
|
+
* can be moved right now and answers with a reason when it cannot, because
|
|
172
|
+
* only it knows the session's live agent, its turn state, and the teardown it
|
|
173
|
+
* would have to perform. This endpoint's job is the boundary — reject a
|
|
174
|
+
* malformed request the way every typert endpoint does, and hand a well-formed
|
|
175
|
+
* one to the selector.
|
|
176
|
+
* @param request - the wire request carrying the session id and target engine.
|
|
177
|
+
* @returns the engine now recorded for the session — with `reload: true` when
|
|
178
|
+
* its agent had to be released for the change to land, which the browser half
|
|
179
|
+
* acts on by reloading the page — or, as `ok: false`, the
|
|
180
|
+
* {@link LoopEngineRefusalCode} of the branch that refused it together with the
|
|
181
|
+
* host's own sentence about this session (`router-unmounted` is this
|
|
182
|
+
* endpoint's own, `session-closed` / `turn-running` / `subagent-session` /
|
|
183
|
+
* `not-driven` / `record-failed` / `rebuild-failed` come from the router's
|
|
184
|
+
* checks). The browser half localizes from the code and keeps the sentence as
|
|
185
|
+
* detail, so the code is part of this endpoint's contract even though the
|
|
186
|
+
* shape allows it to be absent.
|
|
187
|
+
* @throws {RemoteError} with `gateway/bad-request` when the session id is not
|
|
188
|
+
* a non-empty string or the engine is not an installed engine id.
|
|
189
|
+
*/
|
|
190
|
+
select(request: LoopEngineSelectRequest): Promise<LoopEngineSelectResult>;
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=engine-remote.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-session command and skill surface of the hosted engines.
|
|
3
|
+
*
|
|
4
|
+
* A hosted engine owns its session's slash-command menu and skill catalog: the
|
|
5
|
+
* engine expands `/name` itself and reads its own instruction files, so the
|
|
6
|
+
* plugin bridges both into the session the engine serves and nothing more.
|
|
7
|
+
*
|
|
8
|
+
* The registrations are made through the AGENT's own context, which is what
|
|
9
|
+
* makes them session-scoped: `commands.register` and
|
|
10
|
+
* `skills.registerProvider` file a definition into the layer of the calling
|
|
11
|
+
* context's scope (`packages/core/scope/src/store.ts` `effect()` keys the layer
|
|
12
|
+
* by `scopeOf(ctx)`), and an agent's scope key is the agent itself
|
|
13
|
+
* (`createScope(loopCtx, this)` in the default loop; the hosted drivers do the
|
|
14
|
+
* same). Two sessions running different engines therefore never see each
|
|
15
|
+
* other's menus, and the whole surface disappears with the agent's scope — no
|
|
16
|
+
* plugin-side bookkeeping, no leak across an engine switch.
|
|
17
|
+
*
|
|
18
|
+
* @module dsh-loop-engine-allinone/engine-surface
|
|
19
|
+
*/
|
|
20
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
21
|
+
import type { HostedEngineId } from './settings.ts';
|
|
22
|
+
/**
|
|
23
|
+
* Bridge one hosted engine's commands and skills into the session it serves.
|
|
24
|
+
*
|
|
25
|
+
* Best-effort like the rest of the plugin's host-service use: a profile without
|
|
26
|
+
* the commands or skills registry simply has no surface to extend. A name that
|
|
27
|
+
* collides with an already-registered command in the same layer is skipped with
|
|
28
|
+
* a warning rather than failing the agent: the engine expands the raw `/name`
|
|
29
|
+
* line itself, so a shyer menu beats an agent that refuses to start.
|
|
30
|
+
*
|
|
31
|
+
* @param agent - the freshly built agent whose scope owns the registrations.
|
|
32
|
+
* @param engine - the hosted engine driving that agent.
|
|
33
|
+
* @param warn - sink for the skip diagnostics.
|
|
34
|
+
*/
|
|
35
|
+
export declare function registerEngineSurface(agent: Agent, engine: HostedEngineId, warn: (message: string) => void): void;
|
|
36
|
+
//# sourceMappingURL=engine-surface.d.ts.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ZCode agent: one `zcode -p "prompt"` child per dsh step, with the durable
|
|
3
|
+
* session log as the sole source of model context.
|
|
4
|
+
*
|
|
5
|
+
* Like the Hermes driver this reads stdout as a finished answer, and the reason
|
|
6
|
+
* is the same shape of fact recorded in `./process.ts`: the structured
|
|
7
|
+
* app-server surface exists but its request parameter shape could not be probed,
|
|
8
|
+
* so the driver uses the surface that is verified to reach the model rather than
|
|
9
|
+
* guessing a protocol.
|
|
10
|
+
*
|
|
11
|
+
* ZCode additionally needs its provider catalog located: run outside the desktop
|
|
12
|
+
* app the bundled CLI refuses to start a turn until
|
|
13
|
+
* `ZCODE_BUILTIN_PROVIDER_CONFIG_FILE` points at the app's own copy. The driver
|
|
14
|
+
* supplies the discovered default; a deployment's explicit `env` wins.
|
|
15
|
+
*
|
|
16
|
+
* @module dsh-loop-engine-allinone/engine-zcode/agent
|
|
17
|
+
*/
|
|
18
|
+
import type { AgentOptions } from '@deepseek-ai/dsh-agent';
|
|
19
|
+
import type { Session, SessionId, UserMessage } from '@deepseek-ai/dsh-session';
|
|
20
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
21
|
+
import type { HostedEngineId } from '../engine-registry.ts';
|
|
22
|
+
import { CliHostedAgent } from '../driver-cli/cli-agent.ts';
|
|
23
|
+
import type { SinkPosition } from '../driver-cli/session-sink.ts';
|
|
24
|
+
import type { CliSpawnCapability } from '../driver-cli/transport.ts';
|
|
25
|
+
import { zcodeArgvPrefix, zcodeBuiltinProviderConfig } from './process.ts';
|
|
26
|
+
/** Deployment-resolved configuration for the ZCode engine. */
|
|
27
|
+
export interface ResolvedZcodeConfig {
|
|
28
|
+
/** The argv prefix ending in the entrypoint. */
|
|
29
|
+
readonly prefix: readonly string[];
|
|
30
|
+
/** Explicit environment entries layered over the scrubbed parent environment. */
|
|
31
|
+
readonly env: Record<string, string>;
|
|
32
|
+
/** Pinned model. */
|
|
33
|
+
readonly model: string | undefined;
|
|
34
|
+
/** The discovered bundled provider catalog, when present. */
|
|
35
|
+
readonly providerConfig: string | undefined;
|
|
36
|
+
}
|
|
37
|
+
/** The engine id this driver registers under. */
|
|
38
|
+
export declare const ZCODE_ENGINE: HostedEngineId;
|
|
39
|
+
/** Drives one session through turn and step boundaries on ZCode. */
|
|
40
|
+
export declare class ZcodeAgent extends CliHostedAgent {
|
|
41
|
+
private readonly config;
|
|
42
|
+
private readonly spawn;
|
|
43
|
+
constructor(loopCtx: Context, id: SessionId, options: AgentOptions, session: Session, config: ResolvedZcodeConfig, spawn: CliSpawnCapability);
|
|
44
|
+
protected runStep(messages: readonly UserMessage[], position: SinkPosition, signal: AbortSignal): Promise<{
|
|
45
|
+
kind: 'completed';
|
|
46
|
+
} | null>;
|
|
47
|
+
}
|
|
48
|
+
/** Re-exported so `./loop.ts` does not have to know how the prefix is built. */
|
|
49
|
+
export { zcodeArgvPrefix, zcodeBuiltinProviderConfig };
|
|
50
|
+
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ZCode loop engine module: drives every session it is handed through one
|
|
3
|
+
* `zcode -p "prompt"` child per dsh step, with the durable session log as the
|
|
4
|
+
* sole source of model context. The router routes a session here on the plugin's
|
|
5
|
+
* own engine record, else its agent preset; this module is a library, not a
|
|
6
|
+
* Cordis plugin entry.
|
|
7
|
+
*
|
|
8
|
+
* See `./process.ts` for why this driver uses ZCode's one-shot print surface
|
|
9
|
+
* rather than its JSON-RPC app-server, and what was and was not verified.
|
|
10
|
+
*
|
|
11
|
+
* @module dsh-loop-engine-allinone/engine-zcode
|
|
12
|
+
*/
|
|
13
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
14
|
+
import z from '@deepseek-ai/schemastery';
|
|
15
|
+
import type { AgentOptions } from '@deepseek-ai/dsh-agent';
|
|
16
|
+
import type { Session, SessionId } from '@deepseek-ai/dsh-session';
|
|
17
|
+
import { CliEngineRuntime } from '../driver-cli/cli-loop.ts';
|
|
18
|
+
import { ZcodeAgent, type ResolvedZcodeConfig } from './agent.ts';
|
|
19
|
+
/** Deployment-owned configuration for the ZCode engine. */
|
|
20
|
+
export interface Config {
|
|
21
|
+
/** Model label (`--model`); ZCode's own settings own the model when omitted. */
|
|
22
|
+
model?: string;
|
|
23
|
+
/** Explicit environment entries passed to the child; these win over the discovered ones. */
|
|
24
|
+
env?: Record<string, string>;
|
|
25
|
+
/** The `zcode` entrypoint (a `.cjs` bundle or a native binary); auto-discovered when not pinned. */
|
|
26
|
+
bin?: string;
|
|
27
|
+
}
|
|
28
|
+
/** Schema of the ZCode engine configuration. */
|
|
29
|
+
export declare const Config: z<Config>;
|
|
30
|
+
/** Host-face ctx key this engine's runtime is registered under. */
|
|
31
|
+
export declare const ZCODE_ENGINE_LABEL = "agentLoopZcode";
|
|
32
|
+
declare module '@deepseek-ai/cordis' {
|
|
33
|
+
interface Context {
|
|
34
|
+
agentLoopZcode: ZcodeLoop;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Creation/resume machinery for the ZCode engine. The process-wide AgentFactory
|
|
39
|
+
* slot belongs to the router, which delegates each session to the engine its
|
|
40
|
+
* preset names; this class is that engine's driver, not a plugin.
|
|
41
|
+
*/
|
|
42
|
+
export declare class ZcodeLoop extends CliEngineRuntime<ResolvedZcodeConfig, ZcodeAgent> {
|
|
43
|
+
constructor(ctx: Context, config: Config);
|
|
44
|
+
/** Construct the ZCode driver for one prepared session. */
|
|
45
|
+
protected buildAgent(loopCtx: Context, id: SessionId, options: AgentOptions, session: Session): ZcodeAgent;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=loop.d.ts.map
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ZCode CLI process projection.
|
|
3
|
+
*
|
|
4
|
+
* ZCode is the Z.AI (GLM) coding CLI. It ships as a Node bundle at
|
|
5
|
+
* `resources/glm/zcode.cjs` inside the ZCode desktop app, so `argv[0]` is
|
|
6
|
+
* usually `process.execPath` and `argv[1]` the script — which is why the
|
|
7
|
+
* resolver returns an argv PREFIX rather than a single path.
|
|
8
|
+
*
|
|
9
|
+
* ## Why this driver uses the one-shot `-p` surface
|
|
10
|
+
*
|
|
11
|
+
* ZCode advertises two machine-facing surfaces, and they are not equally ready:
|
|
12
|
+
*
|
|
13
|
+
* 1. **`zcode app-server`** — a JSON-RPC stdio server. The probe
|
|
14
|
+
* (`docs/probes/zcode.md`) confirmed the transport and captured its method
|
|
15
|
+
* surface (`startup/*`, `session/create`, `session/send`,
|
|
16
|
+
* `session/subscribe`, `session/events`, `session/event`, `session/stop`,
|
|
17
|
+
* `session/setModel`, `session/setMode`, `session/resume`, `session/list`,
|
|
18
|
+
* `session/compact`, `session/messages`, `session/read`, …) and its
|
|
19
|
+
* server-initiated `startup/storageState` notifications. What the probe could
|
|
20
|
+
* NOT obtain is the REQUEST parameter shape: `initialize` drew no response
|
|
21
|
+
* frame at all, and every `session/create` attempt ended the run before a
|
|
22
|
+
* reply. Writing a request shape from the method names alone would be
|
|
23
|
+
* guessing, which the probe-first rule forbids.
|
|
24
|
+
* 2. **`zcode -p "prompt"`** — the documented one-shot print mode. The probe
|
|
25
|
+
* confirmed it runs and produces a result, but every run stopped at
|
|
26
|
+
* `ProviderBusinessError [1309] … GLM Coding Plan 已到期` (the machine's GLM
|
|
27
|
+
* Coding Plan subscription has lapsed), so the SUCCESS output shape is also
|
|
28
|
+
* unverified.
|
|
29
|
+
*
|
|
30
|
+
* So this driver takes the surface that is verified to at least reach the model,
|
|
31
|
+
* treats stdout as the answer, and declares `protocol: 'text'` /
|
|
32
|
+
* `streaming: false` in the registry — an honest statement of what the DRIVER
|
|
33
|
+
* does, not of what the CLI could do. Upgrading it to the app-server protocol is
|
|
34
|
+
* the recorded next step (`docs/engine-registry.md` §6, TODO).
|
|
35
|
+
*
|
|
36
|
+
* @module dsh-loop-engine-allinone/engine-zcode/process
|
|
37
|
+
*/
|
|
38
|
+
import type { CliSpawnRequest } from '../driver-cli/transport.ts';
|
|
39
|
+
/** Grace in milliseconds for ZCode process-tree termination. */
|
|
40
|
+
export declare const ZCODE_DISPOSE_GRACE_MS = 3000;
|
|
41
|
+
/** The `--mode` values the CLI accepts. */
|
|
42
|
+
export declare const ZCODE_MODES: readonly ["build", "edit", "plan", "yolo"];
|
|
43
|
+
/** One ZCode permission mode. */
|
|
44
|
+
export type ZcodeMode = (typeof ZCODE_MODES)[number];
|
|
45
|
+
/**
|
|
46
|
+
* Resolve the argv prefix that launches ZCode.
|
|
47
|
+
*
|
|
48
|
+
* Three shapes, and the difference is why this returns an array: a pinned `.cjs`
|
|
49
|
+
* path runs under the current node (the bundled form), a pinned native binary is
|
|
50
|
+
* spawned directly, and with nothing pinned the well-known bundle is used before
|
|
51
|
+
* falling back to a `zcode` on PATH.
|
|
52
|
+
* @param configBin - an operator-pinned executable or script, if any.
|
|
53
|
+
* @returns the argv prefix ending in the ZCode entrypoint.
|
|
54
|
+
*/
|
|
55
|
+
export declare function zcodeArgvPrefix(configBin?: string): string[];
|
|
56
|
+
/**
|
|
57
|
+
* The environment entry the bundled ZCode needs to find its own provider
|
|
58
|
+
* catalog.
|
|
59
|
+
*
|
|
60
|
+
* Discovered by the probe: run outside the desktop app, the bundle reports
|
|
61
|
+
* `无法定位 CLI ZCode Built-in Provider Config` and refuses to start a turn until
|
|
62
|
+
* this variable points at the app's own `zcode-builtin.json`. The driver sets it
|
|
63
|
+
* only when the deployment has not — an explicit deployment value always wins.
|
|
64
|
+
*/
|
|
65
|
+
export declare const ZCODE_PROVIDER_CONFIG_ENV = "ZCODE_BUILTIN_PROVIDER_CONFIG_FILE";
|
|
66
|
+
/** The bundled provider catalog inside the desktop app, when it exists. */
|
|
67
|
+
export declare function zcodeBuiltinProviderConfig(): string | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* Map the session's dsh knobs onto ZCode's `--mode`.
|
|
70
|
+
*
|
|
71
|
+
* Fail-closed like the other engines: full access is the only thing that earns
|
|
72
|
+
* `yolo`; everything else, including "no knobs at all", gets the CLI's own
|
|
73
|
+
* `build` mode, and the subprocess sandbox remains the real boundary.
|
|
74
|
+
* @param sandbox - the session's durable sandbox mode, if any.
|
|
75
|
+
* @returns the mode to pass.
|
|
76
|
+
*/
|
|
77
|
+
export declare function zcodeMode(dangerFullAccess: boolean): ZcodeMode;
|
|
78
|
+
/** Everything one step's ZCode child needs. */
|
|
79
|
+
export interface ZcodeSpawnSpec {
|
|
80
|
+
/** The argv prefix ending in the entrypoint. */
|
|
81
|
+
readonly prefix: readonly string[];
|
|
82
|
+
/** The prompt, passed as an argv argument. */
|
|
83
|
+
readonly prompt: string;
|
|
84
|
+
/** The session's working directory. */
|
|
85
|
+
readonly cwd: string;
|
|
86
|
+
/** Explicit environment entries layered over the scrubbed parent environment. */
|
|
87
|
+
readonly env: Record<string, string>;
|
|
88
|
+
/** Pinned model (`--model` is not a flag; ZCode selects a model per session). */
|
|
89
|
+
readonly model: string | undefined;
|
|
90
|
+
/** Resolved permission mode. */
|
|
91
|
+
readonly mode: ZcodeMode;
|
|
92
|
+
/** Cancellation. */
|
|
93
|
+
readonly signal: AbortSignal;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Build the argv for one non-interactive ZCode step.
|
|
97
|
+
* @param spec - the step's spawn spec.
|
|
98
|
+
* @returns the argv.
|
|
99
|
+
*/
|
|
100
|
+
export declare function zcodeArgv(spec: ZcodeSpawnSpec): string[];
|
|
101
|
+
/**
|
|
102
|
+
* Project one step's spawn spec onto the transport request.
|
|
103
|
+
*
|
|
104
|
+
* The provider-catalog variable is merged UNDER the deployment's own entries, so
|
|
105
|
+
* an explicit `env` always wins over the discovered default.
|
|
106
|
+
* @param spec - the step's spawn spec.
|
|
107
|
+
* @param providerConfig - the discovered catalog path, if any.
|
|
108
|
+
* @returns the transport's request shape.
|
|
109
|
+
*/
|
|
110
|
+
export declare function zcodeSpawnRequest(spec: ZcodeSpawnSpec, providerConfig: string | undefined): CliSpawnRequest;
|
|
111
|
+
//# sourceMappingURL=process.d.ts.map
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-session agent loop engines, node half.
|
|
3
|
+
*
|
|
4
|
+
* Hosts the non-default agent-loop engines (Claude Code, Codex, Pi, Kimi Code)
|
|
5
|
+
* and routes each session to the engine it runs. The engine is the PLUGIN's own
|
|
6
|
+
* per-session fact (`session-engine-store.ts`), read first and over the recorded
|
|
7
|
+
* agent preset; a session the plugin has no record for keeps the preset answer,
|
|
8
|
+
* which is what makes every pre-existing session behave exactly as before.
|
|
9
|
+
* The harness admits exactly one AgentFactory per process, so "session A on
|
|
10
|
+
* Codex while session B runs Kimi" is realized by a single router factory
|
|
11
|
+
* ({@link RouterLoop}, which extends the harness's own `AgentLoop`) dispatching
|
|
12
|
+
* to one driver runtime per engine; `in-process` sessions keep the harness loop
|
|
13
|
+
* through that same router.
|
|
14
|
+
*
|
|
15
|
+
* Because the router owns the slot, the plugin keeps the base bundle's
|
|
16
|
+
* `agent-loop` row disabled for as long as it is composed. That managed block
|
|
17
|
+
* lives in the profile's `cordis.patch.yml` (see `patch-manager.ts`) and is the
|
|
18
|
+
* plugin's only footprint in the harness's configuration alongside the preset
|
|
19
|
+
* rows below; the block names no engine, because the engine is a per-session
|
|
20
|
+
* decision.
|
|
21
|
+
*
|
|
22
|
+
* The plugin authors one preset per hosted engine — each a copy of `standard`
|
|
23
|
+
* minus the dsh-native command and skill rows an external engine replaces — and
|
|
24
|
+
* it serves every hosted engine's provider route label in the llm registry
|
|
25
|
+
* (`provider-route.ts`): an engine logs its own label into each session's
|
|
26
|
+
* request/header, and the web host refuses a turn whose session selection names
|
|
27
|
+
* a provider no adapter serves. WHERE that copy lives depends on the harness
|
|
28
|
+
* generation — a directory under `$DSH_HOME/.agent-presets/loop-engine-<engine>`
|
|
29
|
+
* on the 0.1.5 line, a `@deepseek-ai/dsh-agent-preset` insert row in the profile
|
|
30
|
+
* patch on the 0.1.7 line, which stopped reading the directory (see
|
|
31
|
+
* `preset.ts`, {@link authorHostedPresets}). The preset is now only the
|
|
32
|
+
* session's agent-plane composition (and the engine's own default for a session
|
|
33
|
+
* with no record) — it is no longer the thing that decides a running session's
|
|
34
|
+
* engine.
|
|
35
|
+
*
|
|
36
|
+
* The plugin's own live `engine` Config field carries the DEFAULT engine for new
|
|
37
|
+
* sessions — which preset the roster's default points at — not a process-wide
|
|
38
|
+
* switch: existing sessions keep the engine they run, and nothing is torn down or
|
|
39
|
+
* reloaded by it. (A PER-SESSION switch is a different thing: it is made from the
|
|
40
|
+
* chat composer, and when it involves the harness loop it releases that session's
|
|
41
|
+
* agent and reloads the page — `router-loop.ts` `move`, `client/reload.ts`.)
|
|
42
|
+
*
|
|
43
|
+
* @module dsh-loop-engine-allinone
|
|
44
|
+
*/
|
|
45
|
+
import type { Context, Volatile } from '@deepseek-ai/cordis';
|
|
46
|
+
import z from '@deepseek-ai/schemastery';
|
|
47
|
+
import type { EngineDriverConfig } from './engine-drivers.ts';
|
|
48
|
+
import type { CodexApprovalPolicy, CodexSandboxMode } from './engine-codex/types.ts';
|
|
49
|
+
import type { SummarizerTarget } from './preset.ts';
|
|
50
|
+
import { type LoopEngineId } from './settings.ts';
|
|
51
|
+
export declare const name = "loop-engine";
|
|
52
|
+
/**
|
|
53
|
+
* Services the plugin's own fiber requires. The plugin declares none of its
|
|
54
|
+
* own: the optional host services it reads (`commands`, `skills`, `agentPresets`,
|
|
55
|
+
* `llm`) are resolved lazily via `ctx.get` and may be absent, and the router
|
|
56
|
+
* declares the harness loop's own dependency set when it mounts. Empty keeps
|
|
57
|
+
* the plugin from demanding a service that a minimal profile does not provide.
|
|
58
|
+
*/
|
|
59
|
+
export declare const inject: never[];
|
|
60
|
+
/** Composition entry for the loop engine selection and the hosted engine drivers. */
|
|
61
|
+
export interface Config extends EngineDriverConfig {
|
|
62
|
+
/** Profile whose `cordis.patch.yml` carries the managed block; defaults to `web`. */
|
|
63
|
+
profile?: string;
|
|
64
|
+
/** Patch file name inside the profile; defaults to `cordis.patch.yml`. */
|
|
65
|
+
patchFilename?: string;
|
|
66
|
+
/** Explicit absolute path to the patch file, overriding profile + filename. */
|
|
67
|
+
patchPath?: string;
|
|
68
|
+
/** Pinned sandbox mode for the Codex and Pi children; falls back to the session's dsh permission knobs. */
|
|
69
|
+
sandboxMode?: CodexSandboxMode;
|
|
70
|
+
/** Pinned Codex approval policy; falls back to the session's dsh permission knobs. */
|
|
71
|
+
approvalPolicy?: CodexApprovalPolicy;
|
|
72
|
+
/**
|
|
73
|
+
* Idle window in milliseconds after which a hosted session's PERSISTENT child
|
|
74
|
+
* process (Kimi's `kimi acp`, Codex's app-server) is shut down and spawned
|
|
75
|
+
* again by the next step. Zero or omitted keeps the child for the session's
|
|
76
|
+
* whole life. Only these two engines hold a child between steps: the Pi and
|
|
77
|
+
* Claude Code drivers spawn per step, so the knob does not reach them.
|
|
78
|
+
*/
|
|
79
|
+
childIdleMs?: number;
|
|
80
|
+
/**
|
|
81
|
+
* Context window (in tokens) dsh assumes for the hosted provider route.
|
|
82
|
+
*
|
|
83
|
+
* A hosted engine reports no capacity to dsh — each owns its model inside its
|
|
84
|
+
* own child process — so this is the number dsh's auto-compaction sizes its
|
|
85
|
+
* pressure threshold from (default threshold ratio `0.8` of it, so compaction
|
|
86
|
+
* fires once a hosted session's replayed transcript crosses 80% of this). It
|
|
87
|
+
* is declared on the placeholder route (`src/provider-route.ts`
|
|
88
|
+
* `resolveModel`); without it the pressure path warns once and compaction
|
|
89
|
+
* never fires. A deployment running several engines should set it to the
|
|
90
|
+
* SMALLEST engine window in use, so the threshold that fires is safe for
|
|
91
|
+
* every engine. Defaults to
|
|
92
|
+
* {@link DEFAULT_ENGINE_CONTEXT_WINDOW} (262144).
|
|
93
|
+
*/
|
|
94
|
+
engineContextWindow?: number;
|
|
95
|
+
/**
|
|
96
|
+
* Dsh provider route a hosted session's compaction SUMMARIZES through; set
|
|
97
|
+
* together with {@link Config.summarizerModel}, or not at all.
|
|
98
|
+
*
|
|
99
|
+
* The pair is only needed because a hosted engine's own model cannot serve
|
|
100
|
+
* that call: compaction summarizes with an ordinary llm request, and a hosted
|
|
101
|
+
* session's routed model is this plugin's placeholder route
|
|
102
|
+
* (`external/default`), whose `stream()` fails loud. Without the pair the
|
|
103
|
+
* plugin leaves the composition it authors untouched, and every compaction
|
|
104
|
+
* attempt logs a warning and lets the turn continue — the safe degraded mode,
|
|
105
|
+
* in which the session log is never folded. The plugin writes the pair into
|
|
106
|
+
* its own hosted presets (`src/preset.ts` `applySummarizerTarget`) because a
|
|
107
|
+
* profile-patch row replaces its target's whole `config`, and the patch index
|
|
108
|
+
* does not descend into a preset's `config.plugins` — the nested
|
|
109
|
+
* `compaction-basic` row is reachable only from the composition the plugin
|
|
110
|
+
* authors, never from the deployment's profile patch.
|
|
111
|
+
*/
|
|
112
|
+
summarizerProvider?: string;
|
|
113
|
+
/**
|
|
114
|
+
* Dsh model id on {@link Config.summarizerProvider} that hosted sessions
|
|
115
|
+
* summarize through; must be set together with it.
|
|
116
|
+
*/
|
|
117
|
+
summarizerModel?: string;
|
|
118
|
+
/**
|
|
119
|
+
* Default engine NEW sessions are created on. A live, profile-backed field:
|
|
120
|
+
* the settings shell edits it and the running plugin reads it through this
|
|
121
|
+
* volatile reference (`config.engine.get()`).
|
|
122
|
+
*/
|
|
123
|
+
engine: Volatile<LoopEngineId>;
|
|
124
|
+
/** Whether the chat composer shows the engine picker; a live, profile-backed field. */
|
|
125
|
+
showInComposer: Volatile<boolean>;
|
|
126
|
+
/** Whether the conversation header shows the engine badge; a live, profile-backed field. */
|
|
127
|
+
showEngineBadge: Volatile<boolean>;
|
|
128
|
+
}
|
|
129
|
+
/** Rejected input of the composition entry: live fields arrive as plain values and resolve to references. */
|
|
130
|
+
type ConfigInput = Omit<Config, 'engine' | 'showInComposer' | 'showEngineBadge'> & {
|
|
131
|
+
engine?: LoopEngineId;
|
|
132
|
+
showInComposer?: boolean;
|
|
133
|
+
showEngineBadge?: boolean;
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Schema of the loop engine composition entry.
|
|
137
|
+
*
|
|
138
|
+
* A schemastery object validates each field only when it is present and lets
|
|
139
|
+
* an absent key fall through as `undefined`, so omitted knobs are accepted —
|
|
140
|
+
* matching the permissive interface and read path (`resolvePatchPath` defaults
|
|
141
|
+
* the patch path; each engine driver resolves only the knobs it owns and
|
|
142
|
+
* omitted deployment tunables fall back to the session). The composition entry
|
|
143
|
+
* is an engine-agnostic superset: every hosted engine's knobs live here at
|
|
144
|
+
* once, because any session may select any engine.
|
|
145
|
+
*
|
|
146
|
+
* On the 0.1.7 line `engine`, `showInComposer`, and `showEngineBadge` are the
|
|
147
|
+
* entry's live fields: `.volatile()` makes them profile-backed settings the
|
|
148
|
+
* settings shell projects as form fields, and the runtime reads each one through
|
|
149
|
+
* its reference (`config.engine.get()`). On the 0.1.5 line there are no live
|
|
150
|
+
* Config fields — the selection is a settings section
|
|
151
|
+
* (`LOOP_ENGINE_SETTINGS_SCHEMA`), whose provider owns the storage — so the
|
|
152
|
+
* entry is the engine knobs alone.
|
|
153
|
+
*/
|
|
154
|
+
export declare const Config: z<ConfigInput, Config>;
|
|
155
|
+
/** Resolve the managed patch file from configuration, defaulting to the web profile. */
|
|
156
|
+
export declare function resolvePatchPath(config: Config): string;
|
|
157
|
+
/**
|
|
158
|
+
* Resolve the summarization model the plugin writes into every hosted preset,
|
|
159
|
+
* or `undefined` when the deployment names none.
|
|
160
|
+
*
|
|
161
|
+
* The two knobs are one decision — a provider route without a model (or the
|
|
162
|
+
* reverse) cannot be resolved to a call — so a half-set pair is a
|
|
163
|
+
* misconfiguration rather than a usable half, and it fails loud here instead of
|
|
164
|
+
* being dropped on the floor. This runs as the plugin applies, i.e. at compose
|
|
165
|
+
* time, and it runs before anything is written, so a bad profile never leaves a
|
|
166
|
+
* half-authored patch file behind.
|
|
167
|
+
*
|
|
168
|
+
* Schemastery has no cross-field check, so the schema keeps the two fields
|
|
169
|
+
* permissive and the rule is enforced here (the same compose-time posture the
|
|
170
|
+
* engine loops take for their own resolved config).
|
|
171
|
+
* @param config - the composition entry's static knobs.
|
|
172
|
+
* @returns the summarization target, or undefined when neither field is set.
|
|
173
|
+
* @throws when exactly one field is set, or either one is an empty string.
|
|
174
|
+
*/
|
|
175
|
+
export declare function resolveSummarizerTarget(config: Config): SummarizerTarget | undefined;
|
|
176
|
+
/** Atomically replace the patch file (same-directory temp + rename). */
|
|
177
|
+
export declare function writePatchFile(path: string, text: string): Promise<void>;
|
|
178
|
+
/**
|
|
179
|
+
* Synchronously atomically replace the patch file. The settings onChange that
|
|
180
|
+
* commits a default-engine change is a synchronous hook with no await, and the
|
|
181
|
+
* write MUST land before the caller is told the change committed — otherwise a
|
|
182
|
+
* user who restarts `dsh web` immediately reads the stale file.
|
|
183
|
+
* @param path - the profile's patch file.
|
|
184
|
+
* @param text - the next file content.
|
|
185
|
+
*/
|
|
186
|
+
export declare function writePatchFileSync(path: string, text: string): void;
|
|
187
|
+
/**
|
|
188
|
+
* Ensure the profile's patch file carries the plugin's managed block, which
|
|
189
|
+
* disables the base bundle's `agent-loop` row so this plugin's router owns the
|
|
190
|
+
* single AgentFactory slot. Idempotent: a file already carrying a block and no
|
|
191
|
+
* legacy block is left untouched.
|
|
192
|
+
* @param path - the profile's patch file.
|
|
193
|
+
* @returns whether a write occurred.
|
|
194
|
+
*/
|
|
195
|
+
export declare function syncManagedBlock(path: string): Promise<boolean>;
|
|
196
|
+
/**
|
|
197
|
+
* Apply the plugin: own the profile's managed block, mount the routing factory,
|
|
198
|
+
* author the per-engine presets, and serve every hosted engine's provider
|
|
199
|
+
* route. The settings section carries the deployment's default engine.
|
|
200
|
+
* @param ctx - the composing context.
|
|
201
|
+
* @param config - composition entry for the managed patch file and engine knobs.
|
|
202
|
+
*/
|
|
203
|
+
export declare function apply(ctx: Context, config: Config): void;
|
|
204
|
+
export {};
|
|
205
|
+
//# sourceMappingURL=index.d.ts.map
|