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.
Files changed (54) hide show
  1. package/README.md +44 -177
  2. package/README.zh.md +48 -100
  3. package/lib/client.js +887 -266
  4. package/lib/index.js +2212 -914
  5. package/lib/invariant.js +43 -45
  6. package/lib/types/agent-preset-ids.d.ts +303 -0
  7. package/lib/types/client/LoopEngineBadge.d.ts +44 -17
  8. package/lib/types/client/LoopEngineComposerSelect.d.ts +79 -13
  9. package/lib/types/client/LoopEngineSection.d.ts +5 -4
  10. package/lib/types/client/locales.d.ts +133 -7
  11. package/lib/types/client/reload.d.ts +135 -0
  12. package/lib/types/client/session-engine.d.ts +474 -0
  13. package/lib/types/client/store.d.ts +1 -1
  14. package/lib/types/client/turn-status.d.ts +112 -10
  15. package/lib/types/client/use-session-engine.d.ts +66 -0
  16. package/lib/types/commands.d.ts +11 -3
  17. package/lib/types/driver-core/host-servers.d.ts +106 -0
  18. package/lib/types/driver-core/hosted-engine-runtime.d.ts +190 -0
  19. package/lib/types/driver-core/hosted-tool-vocabulary.d.ts +72 -0
  20. package/lib/types/driver-core/model-handover.d.ts +116 -0
  21. package/lib/types/driver-core/ownership.d.ts +6 -5
  22. package/lib/types/driver-core/prompt.d.ts +32 -0
  23. package/lib/types/driver-core/session-lifetime.d.ts +62 -0
  24. package/lib/types/driver-core/session-model.d.ts +82 -0
  25. package/lib/types/engine-claude/agent.d.ts +23 -3
  26. package/lib/types/engine-claude/loop.d.ts +16 -15
  27. package/lib/types/engine-codex/agent.d.ts +22 -3
  28. package/lib/types/engine-codex/appserver/client.d.ts +15 -2
  29. package/lib/types/engine-codex/loop.d.ts +13 -15
  30. package/lib/types/engine-codex/model-handover.d.ts +44 -0
  31. package/lib/types/engine-kimi/acp/client.d.ts +10 -0
  32. package/lib/types/engine-kimi/agent.d.ts +19 -2
  33. package/lib/types/engine-kimi/commands.d.ts +18 -14
  34. package/lib/types/engine-kimi/loop.d.ts +14 -16
  35. package/lib/types/engine-kimi/model-handover.d.ts +32 -0
  36. package/lib/types/engine-kimi/process.d.ts +2 -2
  37. package/lib/types/engine-kimi/types.d.ts +1 -1
  38. package/lib/types/engine-of-session.d.ts +97 -0
  39. package/lib/types/engine-pi/agent.d.ts +25 -23
  40. package/lib/types/engine-pi/loop.d.ts +13 -23
  41. package/lib/types/engine-pi/model-handover.d.ts +35 -0
  42. package/lib/types/engine-pi/types.d.ts +2 -2
  43. package/lib/types/engine-remote.d.ts +192 -0
  44. package/lib/types/engine-surface.d.ts +36 -0
  45. package/lib/types/index.d.ts +51 -50
  46. package/lib/types/invariant.d.ts +8 -5
  47. package/lib/types/model-selection-reset.d.ts +271 -0
  48. package/lib/types/patch-manager.d.ts +57 -39
  49. package/lib/types/preset.d.ts +39 -26
  50. package/lib/types/provider-route.d.ts +83 -36
  51. package/lib/types/router-loop.d.ts +406 -0
  52. package/lib/types/session-engine-store.d.ts +138 -0
  53. package/lib/types/settings.d.ts +12 -11
  54. package/package.json +109 -104
@@ -1,48 +1,61 @@
1
1
  /**
2
- * Hosted-engine agent preset: a managed copy of the deployment's `standard`
3
- * preset with the dsh-native command and skill rows stripped.
2
+ * Hosted-engine agent presets: one managed copy of the deployment's `standard`
3
+ * preset per hosted engine, with the dsh-native command and skill rows
4
+ * stripped.
4
5
  *
5
6
  * A hosted engine (Claude Code, Codex, Pi, Kimi) owns its session's command
6
- * and skill surface: the engine's own slash commands and skill providers are
7
- * registered globally by the plugin, and the dsh-native equivalents would only
8
- * duplicate or mislead — dsh `/plan` is advisory prompt text an external
9
- * engine never assembles, dsh `/compact` cannot shrink a context the engine's
10
- * child process holds, and dsh skills would sit next to the engine's own
11
- * catalog. Those rows live inside the agent-preset composition, which a
12
- * profile patch cannot reach, so the plugin authors a stripped preset into the
13
- * user preset root (`$DSH_HOME/.agent-presets/<id>`) and steers the roster's
14
- * default at runtime (see the plugin's apply).
7
+ * and skill surface: the plugin bridges the engine's own slash commands and
8
+ * skill providers into the session (see `engine-surface.ts`), and the
9
+ * dsh-native equivalents would only duplicate or mislead — dsh `/plan` is
10
+ * advisory prompt text an external engine never assembles, dsh `/compact`
11
+ * cannot shrink a context the engine's child process holds, and dsh skills
12
+ * would sit next to the engine's own catalog. Those rows live inside the
13
+ * agent-preset composition, which a profile patch cannot reach, so the plugin
14
+ * authors a stripped preset per engine into the user preset root
15
+ * (`$DSH_HOME/.agent-presets/<id>`).
15
16
  *
16
- * The preset is REGENERATED from the current `standard` composition on every
17
- * boot that needs it: text on disk is never authoritative, so a harness
18
- * upgrade that changes `standard` flows through. The file is plain YAML the
19
- * loader already accepts — the strip is a line transform that preserves
20
- * everything it does not drop byte for byte, comments included.
17
+ * The preset id is ALSO the per-session engine selector: the harness resolves
18
+ * one preset per session and hands its id to the agent factory at create time
19
+ * (`CreateAgentOptions.meta.agentPreset`), which is the only per-session
20
+ * channel that reaches agent creation. One preset per engine is therefore what
21
+ * makes "session A on Codex, session B on Kimi, concurrently" expressible in a
22
+ * harness that admits exactly one AgentFactory.
23
+ *
24
+ * The presets are REGENERATED from the current `standard` composition on every
25
+ * boot: text on disk is never authoritative, so a harness upgrade that changes
26
+ * `standard` flows through. The file is plain YAML the loader already accepts —
27
+ * the strip is a line transform that preserves everything it does not drop byte
28
+ * for byte, comments included.
21
29
  *
22
30
  * @module dsh-loop-engine/preset
23
31
  */
24
- /** Preset id the plugin authors into the user preset root. */
25
- export declare const HOSTED_PRESET_ID = "loop-engine";
32
+ export { HOSTED_PRESET_PREFIX, SOURCE_PRESET_ID, engineOfPreset, enginePresetId, hostedEngineOf, sessionEngineOf, } from './agent-preset-ids.ts';
33
+ export type { SessionEngine } from './agent-preset-ids.ts';
26
34
  /** Harness-home-relative directory of locally authored presets (mirrors `USER_PRESET_DIR` in `dsh-agent-presets`). */
27
35
  export declare const USER_PRESET_DIR = ".agent-presets";
28
36
  /** The composition file that makes a directory a preset. */
29
37
  export declare const COMPOSITION_FILE = "agent.cordis.yml";
30
38
  /** The display-metadata file beside a preset's composition. */
31
39
  export declare const METADATA_FILE = "preset.yml";
32
- /** Source preset the hosted preset derives from. */
33
- export declare const SOURCE_PRESET_ID = "standard";
40
+ /** Every preset id this plugin owns, whether or not it is currently authored. */
41
+ export declare const HOSTED_PRESET_IDS: readonly string[];
34
42
  /**
35
43
  * Top-level rows stripped from the source preset for hosted engines:
36
44
  * - `skill-filesystem` / `tool-skill`: the dsh skill surface — each engine
37
- * registers its own skill provider globally;
38
- * - `tool-goal`: the model-facing goal tool — the managed block already
39
- * disables dsh's `/goal` command for hosted engines;
45
+ * registers its own skill provider in the session's agent scope;
46
+ * - `tool-goal` / `command-goal`: dsh's goal mode. The model-facing tool only
47
+ * works while an in-process loop drives the session, and the human command
48
+ * would sit in the menu with nothing behind it — no hosted engine here
49
+ * implements `/goal`, so there is nothing for it to hand over to. The
50
+ * `command-goal` row lives HERE, in the preset layer, because that is where
51
+ * the human command is registered; disabling the host-plane row from the
52
+ * profile patch does not reach it (`standard` carries its own row);
40
53
  * - `planning`: dsh plan mode — its only model-visible effect is a system
41
54
  * prompt section an external engine never assembles;
42
55
  * - `compaction`: dsh `/compact` and auto-compaction — a hosted engine owns
43
56
  * its context and its own `/compact` (Claude, Kimi).
44
57
  */
45
- export declare const STRIPPED_ROWS: readonly ["skill-filesystem", "tool-skill", "tool-goal", "planning", "compaction"];
58
+ export declare const STRIPPED_ROWS: readonly ["skill-filesystem", "tool-skill", "tool-goal", "command-goal", "planning", "compaction"];
46
59
  /**
47
60
  * Remove top-level entries by id from a preset composition, preserving every
48
61
  * other byte. Each entry owns the comment/blank run directly above its opener
@@ -61,7 +74,7 @@ export interface PresetCompositionSource {
61
74
  read(id: string): Promise<string>;
62
75
  }
63
76
  /**
64
- * Regenerate the hosted-engine preset under the dsh home's user preset root
77
+ * Regenerate every hosted engine's preset under the dsh home's user preset root
65
78
  * from the roster's `standard` preset. Idempotent: an up-to-date directory is
66
79
  * untouched, so no standing mount sees a spurious file-stamp change.
67
80
  * @param dshHome - the resolved harness home.
@@ -69,5 +82,5 @@ export interface PresetCompositionSource {
69
82
  * @returns whether any file was written.
70
83
  * @throws when the source preset cannot be read or the writes fail.
71
84
  */
72
- export declare function ensureHostedPreset(dshHome: string, source: PresetCompositionSource): Promise<boolean>;
85
+ export declare function ensureEnginePresets(dshHome: string, source: PresetCompositionSource): Promise<boolean>;
73
86
  //# sourceMappingURL=preset.d.ts.map
@@ -1,56 +1,103 @@
1
1
  /**
2
- * Hosted-engine provider route placeholders.
2
+ * Hosted-engine provider route placeholder.
3
3
  *
4
- * Every hosted engine logs its sessions' request/header with its own provider
5
- * label (`claude-code`, `codex`, `pi`, `kimi`) rather than a model endpoint the
4
+ * Every hosted engine logs its sessions' request/header with ONE shared provider
5
+ * label ({@link HOSTED_ROUTE_LABEL}, `external`) rather than a model endpoint the
6
6
  * harness llm registry serves — the engine owns its model natively. The web
7
7
  * host derives a session's model selection from that header and refuses a turn
8
8
  * whose provider no registered adapter serves, so without a placeholder route
9
9
  * the SECOND prompt of every hosted session fails with `model-unavailable`.
10
- * The placeholder serves the label and advertises no models unless a deployment
11
- * injects a catalog (only `pi` does, from its model probe); catalog groups that
12
- * advertise nothing are dropped, so the picker is otherwise unchanged.
10
+ *
11
+ * One label for all four engines, because the browser model catalog is built
12
+ * per Host GENERATION and does not require (or vary by) a Session
13
+ * (`packages/api/session-controller/src/catalog.ts`). A per-engine label would
14
+ * therefore show one provider group per engine in every session's menu at once —
15
+ * four identical `default` entries — so they are collapsed into this one route.
16
+ *
17
+ * Serving the label is only half of it. The model menu renders the session's
18
+ * selection through the catalog, and a provider group that advertises no models
19
+ * is dropped (`packages/api/session-controller/src/catalog.ts`, non-empty
20
+ * groups only) — leaving the seat to show the raw `provider/model` string, i.e.
21
+ * a model that does not exist to any adapter. So the placeholder advertises
22
+ * exactly ONE entry, {@link HOSTED_DEFAULT_MODEL}:
23
+ * `{ provider: HOSTED_ROUTE_LABEL, id: 'default', name: 'default' }`. The id is
24
+ * the same string every engine logs as its model label, which is what makes the
25
+ * seat resolve the session's `(provider, model)` to this entry and render the
26
+ * engine's own word for "whatever it decides" instead of a composite string
27
+ * (see {@link HOSTED_DEFAULT_MODEL} for the host-side mechanism).
28
+ *
29
+ * The entry is not a model this plugin can serve: {@link HostedEngineRouteAdapter.stream}
30
+ * fails loud, because a real model call reaching one of these routes means a
31
+ * session the harness loop drives was handed an engine label — a wiring bug,
32
+ * not a request. Two things keep that from happening: a session switched back
33
+ * to `in-process` has the deployment default written into its log
34
+ * (`model-selection-reset.ts`), and a session BUILT on `in-process` whose
35
+ * selection is one of these labels has it replaced by the same authority before
36
+ * the host installs it (same module, `guardFor`).
13
37
  *
14
38
  * @module dsh-loop-engine/provider-route
15
39
  */
16
- import type { GenerateOptions, LlmModelInfo, StreamChunk } from '@deepseek-ai/dsh-llm';
40
+ import type { GenerateOptions, LlmModelInfo, LlmProviderInfo, StreamChunk } from '@deepseek-ai/dsh-llm';
17
41
  import { LlmAdapter } from '@deepseek-ai/dsh-llm';
18
- import type { LoopEngineId } from './settings.ts';
19
- import type { PiModelEntry } from './engine-pi/probe.ts';
20
- /** Provider route label each hosted engine logs into its sessions' request/header. */
21
- export declare const HOSTED_PROVIDER_ROUTES: Readonly<Record<Exclude<LoopEngineId, 'in-process'>, string>>;
22
- /** Injectable catalog source a hosted engine route can advertise over the placeholder. */
23
- export interface HostedEngineRouteAdapterOptions {
24
- /**
25
- * Optional model catalog generator. When present, `listModels` advertises
26
- * these entries under this route's provider label; when absent, the catalog
27
- * stays empty (the default, "engine owns its models" behavior).
28
- */
29
- readonly listModels?: () => readonly PiModelEntry[];
30
- }
42
+ import type { HostedEngineId } from './settings.ts';
43
+ /**
44
+ * The provider route label ONE hosted engine logs into its sessions'
45
+ * request/header — always {@link HOSTED_ROUTE_LABEL}.
46
+ *
47
+ * A function rather than a per-engine map because there is now ONE label: the
48
+ * engine an id names no longer changes the route. It is kept as a function so
49
+ * the "an engine logs a route" relationship still reads as such at the call
50
+ * sites that have an engine id in hand (`router-loop.ts` `engineRouteOptions`,
51
+ * `model-selection-reset.ts` `seatOf`).
52
+ * @param _engine - the hosted engine whose route label is asked for.
53
+ * @returns the single route label every hosted engine logs.
54
+ */
55
+ export declare function hostedRouteLabelOf(_engine: HostedEngineId): string;
31
56
  /**
32
- * Placeholder adapter serving one hosted engine's provider route label. It
33
- * advertises the injected catalog when a deployment provides one and stays
34
- * empty otherwise (the engine's model is not itself a harness-selectable
35
- * endpoint), and {@link stream} fails loud: a call reaching it means a real
36
- * model query was routed to an engine that owns its model natively — a wiring
37
- * bug, not a request to serve.
57
+ * Whether a provider is one of this plugin's hosted engine route labels — a
58
+ * label some hosted engine logs (now, or in an earlier build), which no adapter
59
+ * serves a real model on.
60
+ *
61
+ * The OLD four per-engine labels are members on purpose, even though only
62
+ * {@link HOSTED_ROUTE_LABEL} is registered. A pre-existing session's header
63
+ * still names one of them; treating only the current label as hosted would let
64
+ * such a session keep the stale selection, and the host — which finds no
65
+ * adapter serving `kimi` any more — would refuse its next turn
66
+ * (`model-unavailable`). Membership here is what lets `model-selection-reset`
67
+ * rewrite the seat to `external/default` (or the deployment default) first.
68
+ * @param provider - the provider of any selection, header, or default.
69
+ * @returns whether that provider is a hosted engine's route label.
70
+ */
71
+ export declare function isHostedProviderRoute(provider: string): boolean;
72
+ /**
73
+ * Placeholder adapter serving the one hosted engine provider route label.
74
+ *
75
+ * It advertises the single menu entry ({@link HOSTED_DEFAULT_MODEL}) so the
76
+ * model seat can name the session's selection, carries the route's display name
77
+ * ({@link HOSTED_ROUTE_NAME}) so the catalog's provider group is labelled
78
+ * `external`, and {@link stream} fails loud: a call reaching it means a real model
79
+ * query was routed to an engine that owns its model natively — a wiring bug, not
80
+ * a request to serve.
38
81
  */
39
82
  export declare class HostedEngineRouteAdapter extends LlmAdapter {
40
- private readonly label;
41
- private readonly options;
42
83
  /**
43
- * @param label - the provider route label this placeholder serves.
44
- * @param options - optional catalog source; omit for an empty catalog.
84
+ * Name the route's one entry.
85
+ *
86
+ * `id` must equal the provider the adapter was registered for (the registry
87
+ * rejects a mismatch — `packages/llm/llm/src/index.ts` `prepareRoutes`), so it
88
+ * is echoed back; `name` is the one localized string the catalog carries.
89
+ * @param provider - the route this adapter is registered for.
90
+ * @returns the route's display metadata.
45
91
  */
46
- constructor(label: string, options?: HostedEngineRouteAdapterOptions);
92
+ providerInfo(provider: string): LlmProviderInfo;
47
93
  /**
48
- * Advertise the injected Pi models (if any) under this route's provider label.
94
+ * Advertise the route's single entry.
49
95
  *
50
- * The model is what the picker shows at the top level, so `name` is the bare
51
- * model; the `provider/model` composite stays the submitted `id`, which is
52
- * both what the engine receives as `--model` and how the driver validates a
53
- * session-selected model against its catalog.
96
+ * The id is the model label the engine logs, so the picker resolves a hosted
97
+ * session's selection to this entry (and highlights its row) rather than
98
+ * falling through to the raw composite string; the name is the same word,
99
+ * rendered as-is.
100
+ * @returns the one entry this route advertises.
54
101
  */
55
102
  listModels(_provider: string): Promise<readonly LlmModelInfo[]>;
56
103
  stream(_options: GenerateOptions): AsyncIterable<StreamChunk>;