dsh-loop-engine 0.1.5-rc2 → 0.1.5-rc4
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/README.md +44 -177
- package/README.zh.md +48 -100
- package/lib/client.js +887 -266
- package/lib/index.js +2212 -914
- package/lib/invariant.js +43 -45
- package/lib/types/agent-preset-ids.d.ts +303 -0
- package/lib/types/client/LoopEngineBadge.d.ts +44 -17
- package/lib/types/client/LoopEngineComposerSelect.d.ts +79 -13
- package/lib/types/client/LoopEngineSection.d.ts +5 -4
- package/lib/types/client/locales.d.ts +133 -7
- package/lib/types/client/reload.d.ts +135 -0
- package/lib/types/client/session-engine.d.ts +474 -0
- package/lib/types/client/store.d.ts +1 -1
- package/lib/types/client/turn-status.d.ts +112 -10
- package/lib/types/client/use-session-engine.d.ts +66 -0
- package/lib/types/commands.d.ts +11 -3
- package/lib/types/driver-core/host-servers.d.ts +106 -0
- package/lib/types/driver-core/hosted-engine-runtime.d.ts +190 -0
- package/lib/types/driver-core/hosted-tool-vocabulary.d.ts +72 -0
- package/lib/types/driver-core/model-handover.d.ts +116 -0
- package/lib/types/driver-core/ownership.d.ts +6 -5
- package/lib/types/driver-core/prompt.d.ts +32 -0
- package/lib/types/driver-core/session-lifetime.d.ts +62 -0
- package/lib/types/driver-core/session-model.d.ts +82 -0
- package/lib/types/engine-claude/agent.d.ts +23 -3
- package/lib/types/engine-claude/loop.d.ts +16 -15
- package/lib/types/engine-codex/agent.d.ts +22 -3
- package/lib/types/engine-codex/appserver/client.d.ts +15 -2
- package/lib/types/engine-codex/loop.d.ts +13 -15
- package/lib/types/engine-codex/model-handover.d.ts +44 -0
- package/lib/types/engine-kimi/acp/client.d.ts +10 -0
- package/lib/types/engine-kimi/agent.d.ts +19 -2
- package/lib/types/engine-kimi/commands.d.ts +18 -14
- package/lib/types/engine-kimi/loop.d.ts +14 -16
- package/lib/types/engine-kimi/model-handover.d.ts +32 -0
- package/lib/types/engine-kimi/process.d.ts +2 -2
- package/lib/types/engine-kimi/types.d.ts +1 -1
- package/lib/types/engine-of-session.d.ts +97 -0
- package/lib/types/engine-pi/agent.d.ts +25 -23
- package/lib/types/engine-pi/loop.d.ts +13 -23
- package/lib/types/engine-pi/model-handover.d.ts +35 -0
- package/lib/types/engine-pi/types.d.ts +2 -2
- package/lib/types/engine-remote.d.ts +192 -0
- package/lib/types/engine-surface.d.ts +36 -0
- package/lib/types/index.d.ts +51 -50
- package/lib/types/invariant.d.ts +8 -5
- package/lib/types/model-selection-reset.d.ts +271 -0
- package/lib/types/patch-manager.d.ts +57 -39
- package/lib/types/preset.d.ts +39 -26
- package/lib/types/provider-route.d.ts +83 -36
- package/lib/types/router-loop.d.ts +406 -0
- package/lib/types/session-engine-store.d.ts +138 -0
- package/lib/types/settings.d.ts +12 -11
- package/package.json +109 -104
package/lib/types/index.d.ts
CHANGED
|
@@ -1,53 +1,54 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Per-session agent loop engines, node half.
|
|
3
3
|
*
|
|
4
4
|
* Hosts the non-default agent-loop engines (Claude Code, Codex, Pi, Kimi Code)
|
|
5
|
-
* and
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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.
|
|
12
14
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* and a committed settings change writes the block (only when it differs).
|
|
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; the block names no
|
|
19
|
+
* engine, because the engine is a per-session decision.
|
|
19
20
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
21
|
+
* The plugin authors one preset per hosted engine into the user preset root
|
|
22
|
+
* (`$DSH_HOME/.agent-presets/loop-engine-<engine>`, see `preset.ts`), each a
|
|
23
|
+
* copy of `standard` minus the dsh-native command and skill rows an external
|
|
24
|
+
* engine replaces, and it serves every hosted engine's provider route label in
|
|
25
|
+
* the llm registry (`provider-route.ts`): an engine logs its own label into
|
|
26
|
+
* each session's request/header, and the web host refuses a turn whose session
|
|
27
|
+
* selection names a provider no adapter serves. The preset is now only the
|
|
28
|
+
* session's agent-plane composition (and the engine's own default for a session
|
|
29
|
+
* with no record) — it is no longer the thing that decides a running session's
|
|
30
|
+
* engine.
|
|
27
31
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* `model-unavailable`.
|
|
32
|
+
* The `agent-loop-engine` settings section carries the DEFAULT engine for new
|
|
33
|
+
* sessions — which preset the roster's default points at — not a process-wide
|
|
34
|
+
* switch: existing sessions keep the engine they run, and nothing is torn down or
|
|
35
|
+
* reloaded by it. (A PER-SESSION switch is a different thing: it is made from the
|
|
36
|
+
* chat composer, and when it involves the harness loop it releases that session's
|
|
37
|
+
* agent and reloads the page — `router-loop.ts` `move`, `client/reload.ts`.)
|
|
35
38
|
*
|
|
36
39
|
* @module dsh-loop-engine
|
|
37
40
|
*/
|
|
38
|
-
import { Context } from '@deepseek-ai/cordis';
|
|
41
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
39
42
|
import z from '@deepseek-ai/schemastery';
|
|
40
43
|
import { type Config as ClaudeCodeConfig } from './engine-claude/loop.ts';
|
|
41
44
|
import type { CodexApprovalPolicy, CodexSandboxMode } from './engine-codex/types.ts';
|
|
42
|
-
import { type LoopEngineId } from './settings.ts';
|
|
43
45
|
export declare const name = "loop-engine";
|
|
44
46
|
/**
|
|
45
47
|
* Services the plugin's own fiber requires. The plugin declares none of its
|
|
46
|
-
* own: the optional host services it reads (`commands`, `skills`
|
|
47
|
-
* lazily via `ctx.get` and may be absent, and the
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* profile does not provide.
|
|
48
|
+
* own: the optional host services it reads (`commands`, `skills`, `agentPresets`,
|
|
49
|
+
* `llm`) are resolved lazily via `ctx.get` and may be absent, and the router
|
|
50
|
+
* declares the harness loop's own dependency set when it mounts. Empty keeps
|
|
51
|
+
* the plugin from demanding a service that a minimal profile does not provide.
|
|
51
52
|
*/
|
|
52
53
|
export declare const inject: never[];
|
|
53
54
|
/** Composition entry for the loop engine selection and the hosted engine drivers. */
|
|
@@ -77,9 +78,8 @@ export interface Config extends ClaudeCodeConfig {
|
|
|
77
78
|
* matching the permissive interface and read path (`resolvePatchPath` defaults
|
|
78
79
|
* the patch path; each engine driver resolves only the knobs it owns and
|
|
79
80
|
* omitted deployment tunables fall back to the session). The composition entry
|
|
80
|
-
* is an engine-agnostic superset:
|
|
81
|
-
*
|
|
82
|
-
* only the selected one is consumed.
|
|
81
|
+
* is an engine-agnostic superset: every hosted engine's knobs live here at
|
|
82
|
+
* once, because any session may select any engine.
|
|
83
83
|
*/
|
|
84
84
|
export declare const Config: z<Config>;
|
|
85
85
|
/** Resolve the managed patch file from configuration, defaulting to the web profile. */
|
|
@@ -87,28 +87,29 @@ export declare function resolvePatchPath(config: Config): string;
|
|
|
87
87
|
/** Atomically replace the patch file (same-directory temp + rename). */
|
|
88
88
|
export declare function writePatchFile(path: string, text: string): Promise<void>;
|
|
89
89
|
/**
|
|
90
|
-
* Synchronously atomically replace the patch file. The
|
|
91
|
-
*
|
|
92
|
-
* the caller is told the
|
|
93
|
-
* `dsh web` immediately reads the stale file
|
|
90
|
+
* Synchronously atomically replace the patch file. The settings onChange that
|
|
91
|
+
* commits a default-engine change is a synchronous hook with no await, and the
|
|
92
|
+
* write MUST land before the caller is told the change committed — otherwise a
|
|
93
|
+
* user who restarts `dsh web` immediately reads the stale file.
|
|
94
94
|
* @param path - the profile's patch file.
|
|
95
95
|
* @param text - the next file content.
|
|
96
96
|
*/
|
|
97
97
|
export declare function writePatchFileSync(path: string, text: string): void;
|
|
98
98
|
/**
|
|
99
|
-
*
|
|
100
|
-
*
|
|
99
|
+
* Ensure the profile's patch file carries the plugin's managed block, which
|
|
100
|
+
* disables the base bundle's `agent-loop` row so this plugin's router owns the
|
|
101
|
+
* single AgentFactory slot. Idempotent: a file already carrying a block and no
|
|
102
|
+
* legacy block is left untouched.
|
|
101
103
|
* @param path - the profile's patch file.
|
|
102
|
-
* @param engine - the target engine.
|
|
103
104
|
* @returns whether a write occurred.
|
|
104
105
|
*/
|
|
105
|
-
export declare function syncManagedBlock(path: string
|
|
106
|
+
export declare function syncManagedBlock(path: string): Promise<boolean>;
|
|
106
107
|
/**
|
|
107
|
-
* Apply the plugin:
|
|
108
|
-
* the
|
|
109
|
-
*
|
|
108
|
+
* Apply the plugin: own the profile's managed block, mount the routing factory,
|
|
109
|
+
* author the per-engine presets, and serve every hosted engine's provider
|
|
110
|
+
* route. The settings section carries the deployment's default engine.
|
|
110
111
|
* @param ctx - the composing context.
|
|
111
|
-
* @param config - composition entry for the managed patch file.
|
|
112
|
+
* @param config - composition entry for the managed patch file and engine knobs.
|
|
112
113
|
*/
|
|
113
114
|
export declare function apply(ctx: Context, config: Config): void;
|
|
114
115
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/types/invariant.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Package-owned invariant companion for the loop engine selection.
|
|
3
3
|
*
|
|
4
|
-
* The plugin's owned relationship is the patch-manager round trip:
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* The plugin's owned relationship is the patch-manager round trip: applying the
|
|
5
|
+
* managed block must be a fixed point, the block must be the one that frees the
|
|
6
|
+
* single AgentFactory slot for the router, a legacy block naming a single engine
|
|
7
|
+
* must be migrated to the engine-agnostic form while still being readable as a
|
|
8
|
+
* legacy pin, and a comment-only layer must be re-seeded to a loadable
|
|
9
|
+
* top-level array rather than left as `null`. The companion asserts those
|
|
10
|
+
* against the pure transform, binding the writer's inverse to the reader
|
|
11
|
+
* directly.
|
|
9
12
|
*
|
|
10
13
|
* @module dsh-loop-engine/invariant
|
|
11
14
|
*/
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keep a session's model selection on the seat the engine driving it owns.
|
|
3
|
+
*
|
|
4
|
+
* A session's model selection FOLLOWS ITS ENGINE, in both directions:
|
|
5
|
+
*
|
|
6
|
+
* - a HOSTED engine owns its model natively, and logs the one shared provider
|
|
7
|
+
* label (`external`, {@link HOSTED_ROUTE_LABEL}) into the session's
|
|
8
|
+
* `request/header`; the host derives the session's selection from the latest
|
|
9
|
+
* header (`packages/api/session-controller/src/agent.ts`, `selectionFor`), so
|
|
10
|
+
* a session a hosted engine drives selects `external`. That label is served
|
|
11
|
+
* only by this plugin's placeholder route (`provider-route.ts`), which
|
|
12
|
+
* advertises exactly one entry under it — {@link HOSTED_DEFAULT_MODEL}. So
|
|
13
|
+
* the seat of a hosted session is `external/default`, and this module is what
|
|
14
|
+
* puts that in the log BEFORE the engine's first request would. (A session
|
|
15
|
+
* whose log still carries an EARLIER build's per-engine label —
|
|
16
|
+
* `claude-code` / `codex` / `pi` / `kimi` — is recognized as hosted too,
|
|
17
|
+
* {@link isHostedProviderRoute}, and rewritten to `external/default` on its
|
|
18
|
+
* next build or switch: no adapter serves those labels any more, so leaving
|
|
19
|
+
* one in place would fail the host's own route check with
|
|
20
|
+
* `model-unavailable`.)
|
|
21
|
+
* - the HARNESS LOOP (`in-process`) DOES call a real model, so it must select
|
|
22
|
+
* something a real adapter serves, and the only selection this plugin can name
|
|
23
|
+
* honestly is the deployment's own default:
|
|
24
|
+
* `agentDefaultModel.currentSelection()`, the value the host's
|
|
25
|
+
* `agentOptions()` gives every session it creates without one
|
|
26
|
+
* (`packages/core/agent-default-model/src/index.ts`,
|
|
27
|
+
* `packages/api/session-controller/src/agent.ts`). That default can name one of
|
|
28
|
+
* these routes ITSELF — `session.selectModel` saves whatever the model menu
|
|
29
|
+
* submitted as the deployment default, and the menu carries the hosted route
|
|
30
|
+
* as an entry — so the deployment's COMPOSED default model (the settings
|
|
31
|
+
* descriptor's `base` layer, what `packages/bundle/base/cordis.patch.yml`
|
|
32
|
+
* configures) is what this plugin names instead, and says so once. See
|
|
33
|
+
* {@link defaultSelection}.
|
|
34
|
+
*
|
|
35
|
+
* The write is the harness's own `model/selection` event: log-only, already a
|
|
36
|
+
* known session event type (`packages/core/session/src/known-event-types.ts`),
|
|
37
|
+
* and exactly what the host's own model picker appends
|
|
38
|
+
* (`ApiSessionAgentController.selectForNextRequest`). That is what makes it the
|
|
39
|
+
* one way a plugin can say "this session's next build selects X" without owning
|
|
40
|
+
* the host's in-memory selection: the event folds into the `modelSelection`
|
|
41
|
+
* projection, and the selection the host installs for the session's next agent
|
|
42
|
+
* reads it back (`selectionFor` prefers the projection's `pending` over the
|
|
43
|
+
* logged header).
|
|
44
|
+
*
|
|
45
|
+
* TWO triggers ask for it, and both answer through the same write:
|
|
46
|
+
*
|
|
47
|
+
* - {@link ModelSelectionReset.resetFor} — a session SWITCHED to another
|
|
48
|
+
* engine. The host reads a session's selection from its log and the change is
|
|
49
|
+
* about to land on that session's next build, so the write has to happen at
|
|
50
|
+
* the switch rather than at the next request.
|
|
51
|
+
* - {@link ModelSelectionReset.guardFor} — a session being BUILT. The router
|
|
52
|
+
* wraps the caller's `setup` for it, which is the one moment the plugin holds
|
|
53
|
+
* the session before the host installs the selection for it
|
|
54
|
+
* (`composeAgent`'s `setup` → `installSelection`), so the write still lands
|
|
55
|
+
* before the first request — and it is what gives a NEW session on a hosted
|
|
56
|
+
* engine its seat. For the harness loop this trigger also settles a defect the
|
|
57
|
+
* build path owns: `session.selectModel` saves the pick it was given as the
|
|
58
|
+
* DEPLOYMENT default (`packages/api/session-controller/src/commands.ts`
|
|
59
|
+
* `selectModel` → `AgentDefaultModelConfig.saveSelection`), that default is
|
|
60
|
+
* the selection of every session with nothing in its log, and the menu now
|
|
61
|
+
* carries the hosted route as an entry — so ONE pick made while a hosted
|
|
62
|
+
* session was open would otherwise hand every session built on the harness
|
|
63
|
+
* loop a route no adapter serves.
|
|
64
|
+
*
|
|
65
|
+
* THREE judgements keep those writes honest, and both triggers share them
|
|
66
|
+
* ({@link ModelSelectionReset.appendSeat}):
|
|
67
|
+
*
|
|
68
|
+
* - a REAL model selection is never overwritten. The test is the provider
|
|
69
|
+
* ({@link isHostedProviderRoute}): only a label some hosted engine logs is a
|
|
70
|
+
* seat this module owns. An explicit pick — the model menu's own event, which
|
|
71
|
+
* also becomes the deployment default — survives every engine change, which is
|
|
72
|
+
* what the browser half's model notice tells the user: under a hosted engine a
|
|
73
|
+
* dsh model is inert, not forbidden.
|
|
74
|
+
* - a session that already selects the target (provider and model) is left
|
|
75
|
+
* alone, so repeated switches never grow the log.
|
|
76
|
+
* - an engine SWITCH has nothing to write for a session whose log names no
|
|
77
|
+
* selection at all: there is no seat to rewrite, and naming a session's first
|
|
78
|
+
* seat is the BUILD trigger's job ({@link ModelSelectionReset.guardFor}), not
|
|
79
|
+
* a switch's. Such a session still selects the deployment default — the host's
|
|
80
|
+
* own fallback — so nothing is broken while the seat shows it.
|
|
81
|
+
*
|
|
82
|
+
* A deployment that composes no `agentDefaultModel` service, or one whose
|
|
83
|
+
* service cannot name a usable selection, is not an error here: the trigger is
|
|
84
|
+
* either the user's own action or a session about to run, and neither must fail
|
|
85
|
+
* over a selection this plugin cannot name. The write is skipped with ONE
|
|
86
|
+
* warning, and the session keeps whatever its log records.
|
|
87
|
+
*
|
|
88
|
+
* @module dsh-loop-engine/model-selection-reset
|
|
89
|
+
*/
|
|
90
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
91
|
+
import type { Session } from '@deepseek-ai/dsh-session';
|
|
92
|
+
import type { SessionModelSelection } from './driver-core/host-servers.ts';
|
|
93
|
+
import type { LoopEngineId } from './settings.ts';
|
|
94
|
+
declare module '@deepseek-ai/dsh-session/types' {
|
|
95
|
+
interface SessionEventMap {
|
|
96
|
+
/**
|
|
97
|
+
* Complete validated model selection requested for subsequent prompt
|
|
98
|
+
* assembly. Log-only: it never enters derived model history.
|
|
99
|
+
*/
|
|
100
|
+
'model/selection': {
|
|
101
|
+
/** Registered provider route. */
|
|
102
|
+
readonly provider: string;
|
|
103
|
+
/** Provider-owned model id. */
|
|
104
|
+
readonly model: string;
|
|
105
|
+
/** Adapter-owned reasoning effort, or provider/default behavior when absent. */
|
|
106
|
+
readonly reasoningEffort?: string;
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/** The host's `agentDefaultModel` service (`packages/core/agent-default-model`), as this read needs it. */
|
|
111
|
+
export interface AgentDefaultModelService {
|
|
112
|
+
/**
|
|
113
|
+
* The selection the host gives an Agent created without one. Read live on
|
|
114
|
+
* every call, because the settings layer it reads may change at any time.
|
|
115
|
+
* @returns the deployment's default provider, model, and optional effort.
|
|
116
|
+
*/
|
|
117
|
+
currentSelection(): SessionModelSelection;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Keeps a session's model selection on the seat the engine driving it owns — the
|
|
121
|
+
* shared `external/default` of a hosted engine, or a real model for the harness
|
|
122
|
+
* loop.
|
|
123
|
+
*
|
|
124
|
+
* One instance per router: the "cannot name a default" and "the default itself
|
|
125
|
+
* names a hosted route" warnings are each owed once per process, not once per
|
|
126
|
+
* session.
|
|
127
|
+
*/
|
|
128
|
+
export declare class ModelSelectionReset {
|
|
129
|
+
private readonly ctx;
|
|
130
|
+
private readonly warn;
|
|
131
|
+
/** Whether the one warning this deployment is owed has been reported. */
|
|
132
|
+
private warned;
|
|
133
|
+
/** Whether the one report that the deployment default names a hosted route has been made. */
|
|
134
|
+
private reportedHostedDefault;
|
|
135
|
+
/**
|
|
136
|
+
* @param ctx - context carrying the host's default-model service, its settings
|
|
137
|
+
* (for the configured default), and the session-projection registry.
|
|
138
|
+
* @param warn - diagnostic sink, used at most once per problem.
|
|
139
|
+
*/
|
|
140
|
+
constructor(ctx: Context, warn: (message: string) => void);
|
|
141
|
+
/**
|
|
142
|
+
* Give one session the selection the engine it is being SWITCHED TO owns,
|
|
143
|
+
* unless its log already names a real model of its own.
|
|
144
|
+
*
|
|
145
|
+
* The switch trigger. A session whose log names no selection at all is left
|
|
146
|
+
* alone: a switch rewrites a seat an engine already put there, and naming a
|
|
147
|
+
* session's first seat belongs to the build of a session being created
|
|
148
|
+
* ({@link guardFor}) rather than to a change of engine.
|
|
149
|
+
* @param session - the live Session the engine switch is being recorded for.
|
|
150
|
+
* @param engine - the engine the session is being moved to.
|
|
151
|
+
* @returns whether a `model/selection` event was appended.
|
|
152
|
+
*/
|
|
153
|
+
resetFor(session: Session, engine: LoopEngineId): boolean;
|
|
154
|
+
/**
|
|
155
|
+
* Give one session the selection the engine BUILDING it owns, inside the
|
|
156
|
+
* router's wrapped `setup` — before the caller's own setup installs the
|
|
157
|
+
* session's selection — so a selection written here is the one the host reads
|
|
158
|
+
* back for the agent being built.
|
|
159
|
+
*
|
|
160
|
+
* The harness loop's own build keeps its narrower precondition: it makes real
|
|
161
|
+
* model calls, so it is the one build that must not be left selecting a
|
|
162
|
+
* placeholder route, and a session whose own log already names a real model
|
|
163
|
+
* needs nothing written for it. A hosted engine is being given its seat here,
|
|
164
|
+
* which is what a new session on it starts from.
|
|
165
|
+
* @param session - the session whose agent is being composed.
|
|
166
|
+
* @param engine - the engine composing it.
|
|
167
|
+
* @returns whether a `model/selection` event was appended.
|
|
168
|
+
*/
|
|
169
|
+
guardFor(session: Session, engine: LoopEngineId): boolean;
|
|
170
|
+
/**
|
|
171
|
+
* Whether the selection this session's next request would use names one of
|
|
172
|
+
* the hosted engines' provider routes — a label this plugin serves as a
|
|
173
|
+
* placeholder and cannot answer a real model call on.
|
|
174
|
+
*
|
|
175
|
+
* The read is the host's own (`selectionFor`): a pending selection, else the
|
|
176
|
+
* logged header, else the deployment's default. A session with nothing in its
|
|
177
|
+
* log is therefore judged on the deployment default — the value the model menu
|
|
178
|
+
* can write a hosted label into — and that default is read AS IT IS, never as
|
|
179
|
+
* {@link defaultSelection} would substitute it: the substitution only exists
|
|
180
|
+
* once it is written into the session, so judging the substitute would skip
|
|
181
|
+
* the write that makes it real.
|
|
182
|
+
* @param session - the session whose selection is being judged.
|
|
183
|
+
* @returns whether that selection names a hosted engine route.
|
|
184
|
+
*/
|
|
185
|
+
private selectsHostedRoute;
|
|
186
|
+
/**
|
|
187
|
+
* Append the selection one engine's seat carries, by the judgements both
|
|
188
|
+
* triggers share.
|
|
189
|
+
*
|
|
190
|
+
* A real model selection is never overwritten — the provider is the test,
|
|
191
|
+
* because only a label some hosted engine logs is a seat this module owns — and
|
|
192
|
+
* a session that already selects the target route is left alone. Provider and
|
|
193
|
+
* model are the comparison: a reasoning effort the target carries is not a
|
|
194
|
+
* reason to log a second event for a session that already selects the same
|
|
195
|
+
* route, and re-appending would only grow the log on every switch.
|
|
196
|
+
* @param session - the session whose selection is being written.
|
|
197
|
+
* @param engine - the engine whose seat the session should select.
|
|
198
|
+
* @returns whether a `model/selection` event was appended.
|
|
199
|
+
*/
|
|
200
|
+
private appendSeat;
|
|
201
|
+
/**
|
|
202
|
+
* The selection one engine's seat carries: a hosted engine's shared
|
|
203
|
+
* `external/default`, or — for the harness loop — the deployment's default,
|
|
204
|
+
* with the substitution {@link defaultSelection} documents.
|
|
205
|
+
* @param engine - the engine a session runs, or is being moved to.
|
|
206
|
+
* @returns the selection to write, or undefined when this process cannot name
|
|
207
|
+
* one for that engine.
|
|
208
|
+
*/
|
|
209
|
+
private seatOf;
|
|
210
|
+
/**
|
|
211
|
+
* The selection the host will use for this session, by the host's own read —
|
|
212
|
+
* the shared read in `driver-core/session-model.ts` (`currentSelection`),
|
|
213
|
+
* which the four hosted drivers also use to resolve the model they hand over.
|
|
214
|
+
* @param session - the session whose selection is being read.
|
|
215
|
+
* @returns the current selection, or undefined when the log records none.
|
|
216
|
+
*/
|
|
217
|
+
private currentSelection;
|
|
218
|
+
/**
|
|
219
|
+
* The selection the deployment's own `agentDefaultModel` service answers, or
|
|
220
|
+
* undefined when this process cannot read one (reported once).
|
|
221
|
+
*
|
|
222
|
+
* Read twice for two different questions — as the selection a session with
|
|
223
|
+
* nothing in its log would use ({@link selectsHostedRoute}), and as the value
|
|
224
|
+
* this plugin restores ({@link defaultSelection}) — so the substitution below
|
|
225
|
+
* never hides the fact that the saved default itself is unusable.
|
|
226
|
+
* @returns the validated default, or undefined when it cannot be named.
|
|
227
|
+
*/
|
|
228
|
+
private deploymentDefault;
|
|
229
|
+
/**
|
|
230
|
+
* The selection this plugin restores: the deployment's default, or — when that
|
|
231
|
+
* default names a hosted engine ROUTE — the model the deployment's own
|
|
232
|
+
* composition declares instead.
|
|
233
|
+
*
|
|
234
|
+
* The route case is not hypothetical: `session.selectModel` saves whatever the
|
|
235
|
+
* model menu submitted as the deployment default, and the menu carries the
|
|
236
|
+
* hosted route as an entry, so one pick made while a hosted session was open
|
|
237
|
+
* puts a label there that no adapter serves a real model on — handing it to a
|
|
238
|
+
* session the harness loop drives would fail that session's first request
|
|
239
|
+
* loud. The composed default is a real model the deployment itself asked for,
|
|
240
|
+
* so nothing is guessed on its behalf.
|
|
241
|
+
* @returns the restored selection, or undefined to skip the write.
|
|
242
|
+
*/
|
|
243
|
+
private defaultSelection;
|
|
244
|
+
/**
|
|
245
|
+
* The model the DEPLOYMENT's own composition declares as its default, read
|
|
246
|
+
* from the settings descriptor's `base` layer — the value a saved (user-layer)
|
|
247
|
+
* default overrode.
|
|
248
|
+
*
|
|
249
|
+
* This is what replaces a default that names a hosted route, and it is read
|
|
250
|
+
* live because the composition is what the deployment itself configured:
|
|
251
|
+
* `packages/bundle/base/cordis.patch.yml` gives the `agent-default-model` row
|
|
252
|
+
* a real provider and model, and only the user layer can hold a pick made from
|
|
253
|
+
* the model menu.
|
|
254
|
+
* @returns the configured default, or undefined when this deployment composes
|
|
255
|
+
* no default-model section, cannot enumerate settings, configured no usable
|
|
256
|
+
* provider/model, or configured a hosted route there too.
|
|
257
|
+
*/
|
|
258
|
+
private configuredDefault;
|
|
259
|
+
/** Read the host session-projection registry, structurally. */
|
|
260
|
+
private projections;
|
|
261
|
+
/**
|
|
262
|
+
* Report the one thing this read could not answer, once per plugin lifetime.
|
|
263
|
+
*
|
|
264
|
+
* Repeated triggers must not repeat it: a deployment without the service would
|
|
265
|
+
* otherwise log a line per session built for as long as it runs.
|
|
266
|
+
* @param problem - what this process cannot read, with the reason.
|
|
267
|
+
* @returns undefined, so callers can `return this.unavailable(…)` to skip.
|
|
268
|
+
*/
|
|
269
|
+
private unavailable;
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=model-selection-reset.d.ts.map
|
|
@@ -2,65 +2,83 @@
|
|
|
2
2
|
* Managed-block editing for a profile's `cordis.patch.yml`.
|
|
3
3
|
*
|
|
4
4
|
* The plugin owns one contiguous block inside the user's patch file, delimited
|
|
5
|
-
* by a begin/end marker pair, and rewrites only that span
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* by a begin/end marker pair, and rewrites only that span — everything else the
|
|
6
|
+
* user wrote (other patches, their comments) survives byte for byte. The block
|
|
7
|
+
* is what hands the process-wide AgentFactory slot to this plugin's router: it
|
|
8
|
+
* disables the base bundle's `agent-loop` row, because the harness admits
|
|
9
|
+
* exactly one AgentFactory and the router (which extends the harness loop, and
|
|
10
|
+
* therefore serves `in-process` sessions too) registers itself as that one.
|
|
11
11
|
*
|
|
12
|
-
* # -- dsh-loop-engine managed block
|
|
12
|
+
* # -- dsh-loop-engine managed block --
|
|
13
13
|
* - id: agent-loop
|
|
14
14
|
* disabled: true
|
|
15
15
|
* - id: command-goal
|
|
16
16
|
* disabled: true
|
|
17
17
|
* # -- /dsh-loop-engine managed block --
|
|
18
18
|
*
|
|
19
|
-
* The
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
19
|
+
* The block names no engine. Which engine a session runs is a PER-SESSION
|
|
20
|
+
* decision carried by its agent preset, so it cannot live in a process-wide
|
|
21
|
+
* configuration file; the block's only job is to free the slot for the router.
|
|
22
|
+
* The `command-goal` row goes down with the loop: it is the host-plane copy of
|
|
23
|
+
* dsh's goal command, and a goal service nothing drives has no business being
|
|
24
|
+
* mounted for a profile whose loop is decided per session. The remaining
|
|
25
|
+
* dsh-native commands (`/export`, `/feedback`, `/permission`) are
|
|
26
|
+
* engine-agnostic session and settings controls that keep working under every
|
|
27
|
+
* engine. Per-session command surfaces are the preset's business — a hosted
|
|
28
|
+
* session joins an engine preset that strips `command-goal` itself, which is the
|
|
29
|
+
* only place that reaches the preset-layer registration.
|
|
25
30
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
31
|
+
* Blocks written before the plugin routed per session carried the single
|
|
32
|
+
* engine's id in the begin marker (`# -- dsh-loop-engine managed block:
|
|
33
|
+
* claude-code --`). {@link legacyBlockEngineOf} reads that form so an upgrade
|
|
34
|
+
* can carry the pinned engine into the settings seed before the block is
|
|
35
|
+
* rewritten to the engine-agnostic form; a legacy block is otherwise treated as
|
|
36
|
+
* a present block by {@link hasManagedBlock}.
|
|
37
|
+
*
|
|
38
|
+
* All functions here are pure string transforms — file I/O and durability live
|
|
39
|
+
* in the plugin's apply.
|
|
33
40
|
*
|
|
34
41
|
* @module dsh-loop-engine/patch-manager
|
|
35
42
|
*/
|
|
36
43
|
import type { LoopEngineId } from './settings.ts';
|
|
37
44
|
/** Begin marker of the plugin-managed span inside a profile patch file. */
|
|
38
|
-
export declare const MANAGED_BLOCK_BEGIN = "# -- dsh-loop-engine managed block
|
|
45
|
+
export declare const MANAGED_BLOCK_BEGIN = "# -- dsh-loop-engine managed block --";
|
|
46
|
+
/**
|
|
47
|
+
* Begin-marker prefix of the pre-routing block form, which named the one engine
|
|
48
|
+
* the profile was pinned to.
|
|
49
|
+
*/
|
|
50
|
+
export declare const LEGACY_MANAGED_BLOCK_BEGIN = "# -- dsh-loop-engine managed block: ";
|
|
39
51
|
/** End marker of the plugin-managed span inside a profile patch file. */
|
|
40
52
|
export declare const MANAGED_BLOCK_END = "# -- /dsh-loop-engine managed block --";
|
|
41
|
-
/**
|
|
42
|
-
export declare function renderManagedBlock(
|
|
43
|
-
/**
|
|
53
|
+
/** The loader patch that frees the single AgentFactory slot for the router. */
|
|
54
|
+
export declare function renderManagedBlock(): string;
|
|
55
|
+
/**
|
|
56
|
+
* Whether a patch-file text contains the LEGACY managed block span, which
|
|
57
|
+
* named the single engine the profile used to be pinned to.
|
|
58
|
+
*/
|
|
59
|
+
export declare function hasLegacyManagedBlock(text: string): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Whether a patch-file text contains the managed block span, in either the
|
|
62
|
+
* current or the legacy form.
|
|
63
|
+
*/
|
|
44
64
|
export declare function hasManagedBlock(text: string): boolean;
|
|
45
65
|
/**
|
|
46
|
-
* The engine
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
66
|
+
* The engine a LEGACY managed block pinned the profile to, when the block has
|
|
67
|
+
* that form and names an engine this build knows. `undefined` covers the
|
|
68
|
+
* current engine-agnostic block, no block at all, and a legacy block naming an
|
|
69
|
+
* engine this build does not recognize.
|
|
50
70
|
*/
|
|
51
|
-
export declare function
|
|
52
|
-
/** Derive the current engine from a patch-file text by the managed block's begin marker. */
|
|
53
|
-
export declare function currentEngineOf(text: string): LoopEngineId;
|
|
71
|
+
export declare function legacyBlockEngineOf(text: string): LoopEngineId | undefined;
|
|
54
72
|
/**
|
|
55
|
-
* Produce the next patch-file text
|
|
56
|
-
* outside the managed span. Appends the span when absent
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
73
|
+
* Produce the next patch-file text carrying the managed block, preserving every
|
|
74
|
+
* byte outside the managed span. Appends the span when absent and replaces it
|
|
75
|
+
* when present — including a legacy span, which is rewritten to the current
|
|
76
|
+
* form. The managed block is a root-level collection, so a leftover seed `[]`
|
|
77
|
+
* is dropped with it, leaving the file a single valid top-level array the
|
|
78
|
+
* harness can boot: the block's own `- id: agent-loop` is a column-0 entry, so
|
|
79
|
+
* a file carrying it never needs a re-seed.
|
|
61
80
|
* @param text - current patch-file text.
|
|
62
|
-
* @param engine - target engine.
|
|
63
81
|
* @returns the rewritten patch-file text.
|
|
64
82
|
*/
|
|
65
|
-
export declare function applyManagedBlock(text: string
|
|
83
|
+
export declare function applyManagedBlock(text: string): string;
|
|
66
84
|
//# sourceMappingURL=patch-manager.d.ts.map
|