dsh-loop-engine 1.0.0-rc7 → 1.0.0-rc9
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 +39 -0
- package/lib/client.js +6 -2
- package/lib/index.js +953 -269
- package/lib/invariant.js +2 -1
- package/lib/types/client/LoopEngineBadge.d.ts +1 -1
- package/lib/types/client/LoopEngineComposerSelect.d.ts +1 -1
- package/lib/types/client/LoopEngineSection.d.ts +1 -1
- package/lib/types/client/index.d.ts +1 -1
- package/lib/types/client/locales.d.ts +2 -0
- package/lib/types/client/store.d.ts +2 -1
- package/lib/types/driver-core/ownership.d.ts +1 -2
- package/lib/types/engine-claude/agent.d.ts +2 -0
- package/lib/types/engine-claude/loop.d.ts +24 -2
- package/lib/types/engine-claude/mapping.d.ts +3 -3
- package/lib/types/engine-codex/agent.d.ts +2 -0
- package/lib/types/engine-codex/appserver/mapping.d.ts +4 -4
- package/lib/types/engine-codex/loop.d.ts +24 -2
- package/lib/types/engine-kimi/agent.d.ts +2 -0
- package/lib/types/engine-kimi/commands.d.ts +7 -0
- package/lib/types/engine-kimi/loop.d.ts +24 -2
- package/lib/types/engine-pi/agent.d.ts +10 -0
- package/lib/types/engine-pi/loop.d.ts +29 -2
- package/lib/types/engine-pi/probe.d.ts +23 -0
- package/lib/types/index.d.ts +16 -0
- package/lib/types/patch-manager.d.ts +9 -0
- package/lib/types/preset.d.ts +73 -0
- package/lib/types/provider-route.d.ts +49 -0
- package/lib/types/settings.d.ts +5 -5
- package/package.json +23 -23
package/lib/invariant.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// src/settings.ts
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
|
-
import { settingsNamespace } from "@deepseek-ai/dsh-settings";
|
|
4
3
|
var LOOP_ENGINE_IDS = ["in-process", "claude-code", "codex", "pi", "kimi"];
|
|
5
4
|
var LOOP_ENGINE_SETTINGS_SCHEMA = z.object({
|
|
6
5
|
engine: z.union([z.const("in-process"), z.const("claude-code"), z.const("codex"), z.const("pi"), z.const("kimi")]).default("in-process"),
|
|
@@ -18,6 +17,8 @@ function renderManagedBlock(engine) {
|
|
|
18
17
|
`${MANAGED_BLOCK_BEGIN}${engine} --`,
|
|
19
18
|
"- id: agent-loop",
|
|
20
19
|
" disabled: true",
|
|
20
|
+
"- id: command-goal",
|
|
21
|
+
" disabled: true",
|
|
21
22
|
END_MARKER_LINE
|
|
22
23
|
].join("\n");
|
|
23
24
|
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* @module dsh-loop-engine/client/badge
|
|
10
10
|
*/
|
|
11
11
|
import type { JSX } from 'react';
|
|
12
|
-
import type { SnapshotStore } from '@deepseek-ai/dsh-client-
|
|
12
|
+
import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
13
13
|
import type { InjectFace } from '@deepseek-ai/dsh-client-ui-slots';
|
|
14
14
|
import type { LoopEngineState } from './store.ts';
|
|
15
15
|
import type { en } from './locales.ts';
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* @module dsh-loop-engine/client/composer
|
|
14
14
|
*/
|
|
15
15
|
import { type JSX } from 'react';
|
|
16
|
-
import type { SnapshotStore } from '@deepseek-ai/dsh-client-
|
|
16
|
+
import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
17
17
|
import type { InjectFace } from '@deepseek-ai/dsh-client-ui-slots';
|
|
18
18
|
import type { LoopEngineStore, LoopEngineState } from './store.ts';
|
|
19
19
|
import type { en } from './locales.ts';
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* @module dsh-loop-engine/client
|
|
13
13
|
*/
|
|
14
14
|
import { type JSX } from 'react';
|
|
15
|
-
import type { SnapshotStore } from '@deepseek-ai/dsh-client-
|
|
15
|
+
import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
16
16
|
import type { InjectFace } from '@deepseek-ai/dsh-client-ui-slots';
|
|
17
17
|
import type { LoopEngineStore, LoopEngineState } from './store.ts';
|
|
18
18
|
import type { en } from './locales.ts';
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Export discipline: packages/client/AGENTS.md.
|
|
6
6
|
* @module dsh-loop-engine/client
|
|
7
7
|
*/
|
|
8
|
-
import type { ClientContext } from '@deepseek-ai/
|
|
8
|
+
import type { Context as ClientContext } from '@deepseek-ai/cordis';
|
|
9
9
|
import { type LoopEngineKey } from './locales.ts';
|
|
10
10
|
export type { LoopEngineSectionInjected, LoopEngineSectionProps } from './LoopEngineSection.tsx';
|
|
11
11
|
export type { LoopEngineBadgeInjected, LoopEngineBadgeProps } from './LoopEngineBadge.tsx';
|
|
@@ -34,6 +34,8 @@ export interface LoopEngineKey {
|
|
|
34
34
|
confirmAction: string;
|
|
35
35
|
/** Cancel action label. */
|
|
36
36
|
cancelAction: string;
|
|
37
|
+
/** Accessible close-button label of the confirmation dialog. */
|
|
38
|
+
closeLabel: string;
|
|
37
39
|
/** Notice shown while the Claude Code engine owns the slot: model selection is native. */
|
|
38
40
|
claudeModelNotice: string;
|
|
39
41
|
}
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* and the store publishes a render-safe snapshot plus the write path.
|
|
4
4
|
* @module dsh-loop-engine/client/store
|
|
5
5
|
*/
|
|
6
|
-
import type { SettingsScope
|
|
6
|
+
import type { SettingsScope } from '@deepseek-ai/dsh-client-ui-settings/client';
|
|
7
|
+
import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
7
8
|
import type { LoopEngineId } from '../settings.ts';
|
|
8
9
|
/** State rendered by the loop engine section. */
|
|
9
10
|
export interface LoopEngineState {
|
|
@@ -9,11 +9,10 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @module dsh-loop-engine/driver-core/ownership
|
|
11
11
|
*/
|
|
12
|
-
import { FiberState } from '@deepseek-ai/cordis';
|
|
13
12
|
import type { Context } from '@deepseek-ai/cordis';
|
|
14
13
|
import type { SessionId } from '@deepseek-ai/dsh-session';
|
|
15
14
|
/** Fiber states that cannot own or serve a new lifecycle. */
|
|
16
|
-
export declare const INACTIVE_STATES: ReadonlySet<
|
|
15
|
+
export declare const INACTIVE_STATES: ReadonlySet<number>;
|
|
17
16
|
/** Factory-level ownership: live agent teardowns plus load-time tracking. */
|
|
18
17
|
export declare class FactoryOwnership {
|
|
19
18
|
private readonly fiber;
|
|
@@ -12,6 +12,8 @@ import type { Scope } from '@deepseek-ai/dsh-scope';
|
|
|
12
12
|
import type { Session, SessionId, UserMessage } from '@deepseek-ai/dsh-session';
|
|
13
13
|
import type { Context } from '@deepseek-ai/cordis';
|
|
14
14
|
import type { ResolvedConfig } from './types.ts';
|
|
15
|
+
/** Provider route label used for logged header snapshots and message provenance. */
|
|
16
|
+
export declare const PROVIDER = "claude-code";
|
|
15
17
|
/** Drives one session through turn and step boundaries on Claude Code. */
|
|
16
18
|
export declare class ClaudeCodeAgent implements Agent {
|
|
17
19
|
private loopCtx;
|
|
@@ -70,12 +70,34 @@ export declare class ClaudeCodeLoop extends Service implements AgentFactory {
|
|
|
70
70
|
private setupAndPublish;
|
|
71
71
|
/**
|
|
72
72
|
* Create an agent and session under one caller-supplied identity, owned by
|
|
73
|
-
* the accessing fiber.
|
|
73
|
+
* the accessing fiber. When a persistence backend is mounted, the session's
|
|
74
|
+
* durable identity is stored before publication.
|
|
74
75
|
* @param ownerCtx - caller context that structurally owns the lifecycle.
|
|
75
76
|
* @param options - identities, session seed/metadata, loop options, setup, and cancellation.
|
|
76
77
|
* @returns the published handle.
|
|
77
78
|
*/
|
|
78
79
|
createAgent(ownerCtx: Context, options: CreateAgentOptions): Promise<AgentHandle>;
|
|
80
|
+
/**
|
|
81
|
+
* Take a fresh session's write ownership when persistence is mounted.
|
|
82
|
+
* Nothing is appended here: the constructor seed (which never re-emits
|
|
83
|
+
* through `session/event`) is stored by {@link appendUnstoredSuffix} at the
|
|
84
|
+
* publication commit point, so a failed or cancelled setup closes an
|
|
85
|
+
* unmaterialized handle and leaves no stored residue — the same id can be
|
|
86
|
+
* created again.
|
|
87
|
+
* @param session - the unpublished session to store.
|
|
88
|
+
* @param signal - optional cancellation forwarded to the backend create.
|
|
89
|
+
* @returns the owned handle and stored cursor, or `undefined` without a backend.
|
|
90
|
+
*/
|
|
91
|
+
private createStoredSession;
|
|
92
|
+
/**
|
|
93
|
+
* Durably store the session events appended since the last stored cursor.
|
|
94
|
+
* Pre-publication appends (constructor seed markers, setup-window events)
|
|
95
|
+
* never re-emit through `session/event`, so publication must flush them
|
|
96
|
+
* through the handle before live events start routing into it.
|
|
97
|
+
* @param stored - the session's owned handle and stored cursor, if any.
|
|
98
|
+
* @param session - the unpublished session whose suffix is stored.
|
|
99
|
+
*/
|
|
100
|
+
private appendUnstoredSuffix;
|
|
79
101
|
/**
|
|
80
102
|
* Resume an owned agent from the configured persistence service.
|
|
81
103
|
* @param ownerCtx - caller context that owns load, setup, and the live lifecycle.
|
|
@@ -83,7 +105,7 @@ export declare class ClaudeCodeLoop extends Service implements AgentFactory {
|
|
|
83
105
|
* @returns the published handle.
|
|
84
106
|
*/
|
|
85
107
|
resume(ownerCtx: Context, options: ResumeAgentOptions): Promise<AgentHandle>;
|
|
86
|
-
/** Resume through an explicit persistence
|
|
108
|
+
/** Resume through an explicit persistence service. */
|
|
87
109
|
private resumeWith;
|
|
88
110
|
}
|
|
89
111
|
//# sourceMappingURL=loop.d.ts.map
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { BetaMessage, BetaRawMessageStreamEvent, BetaUsage } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs';
|
|
10
10
|
import type { MessageParam } from '@anthropic-ai/sdk/resources';
|
|
11
|
-
import {
|
|
11
|
+
import { ToolCallId, type ContentBlock, type StreamChunk, type TokenUsage, type ToolResultMessage } from '@deepseek-ai/dsh-llm';
|
|
12
12
|
/** One tool invocation surfaced from a Claude Code assistant message. */
|
|
13
13
|
export interface MappedToolCall {
|
|
14
14
|
/** SDK tool_use id, reused as the dsh call-id so results pair. */
|
|
15
|
-
readonly callId:
|
|
15
|
+
readonly callId: ToolCallId;
|
|
16
16
|
/** Tool name exactly as the SDK reported it. */
|
|
17
17
|
readonly name: string;
|
|
18
18
|
/** Raw JSON arguments string as the SDK produced them. */
|
|
@@ -63,7 +63,7 @@ export declare function mapToolResults(message: MessageParam): ToolResultMessage
|
|
|
63
63
|
export declare function mapUsage(usage: BetaUsage): TokenUsage;
|
|
64
64
|
/** Per-block-index tool-call identity captured at `content_block_start`, reused by `input_json_delta`. */
|
|
65
65
|
export interface StreamToolCall {
|
|
66
|
-
readonly callId:
|
|
66
|
+
readonly callId: ToolCallId;
|
|
67
67
|
readonly name: string;
|
|
68
68
|
}
|
|
69
69
|
/**
|
|
@@ -17,6 +17,8 @@ import type { Scope } from '@deepseek-ai/dsh-scope';
|
|
|
17
17
|
import type { Session, SessionId, UserMessage } from '@deepseek-ai/dsh-session';
|
|
18
18
|
import type { Context } from '@deepseek-ai/cordis';
|
|
19
19
|
import type { ResolvedConfig } from './types.ts';
|
|
20
|
+
/** Provider route label used for logged header snapshots and message provenance. */
|
|
21
|
+
export declare const PROVIDER = "codex";
|
|
20
22
|
/** Drives one session through turn and step boundaries on Codex. */
|
|
21
23
|
export declare class CodexAgent implements Agent {
|
|
22
24
|
private loopCtx;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @module dsh-loop-engine/engine-codex/appserver/mapping
|
|
9
9
|
*/
|
|
10
10
|
import type { TokenUsage, ToolResultMessage } from '@deepseek-ai/dsh-llm';
|
|
11
|
-
import {
|
|
11
|
+
import { ToolCallId } from '@deepseek-ai/dsh-llm';
|
|
12
12
|
/** Map app-server turn usage to dsh TokenUsage. */
|
|
13
13
|
export declare function mapUsage(usage: {
|
|
14
14
|
inputTokens: number;
|
|
@@ -25,7 +25,7 @@ export declare function mapCommandExecution(item: {
|
|
|
25
25
|
status?: string;
|
|
26
26
|
}): {
|
|
27
27
|
call: {
|
|
28
|
-
callId:
|
|
28
|
+
callId: ToolCallId;
|
|
29
29
|
name: string;
|
|
30
30
|
arguments: string;
|
|
31
31
|
};
|
|
@@ -38,7 +38,7 @@ export declare function mapFileChange(item: {
|
|
|
38
38
|
status?: string;
|
|
39
39
|
}): {
|
|
40
40
|
call: {
|
|
41
|
-
callId:
|
|
41
|
+
callId: ToolCallId;
|
|
42
42
|
name: string;
|
|
43
43
|
arguments: string;
|
|
44
44
|
};
|
|
@@ -58,7 +58,7 @@ export declare function mapMcpToolCall(item: {
|
|
|
58
58
|
};
|
|
59
59
|
}): {
|
|
60
60
|
call: {
|
|
61
|
-
callId:
|
|
61
|
+
callId: ToolCallId;
|
|
62
62
|
name: string;
|
|
63
63
|
arguments: string;
|
|
64
64
|
};
|
|
@@ -73,12 +73,34 @@ export declare class CodexLoop extends Service implements AgentFactory {
|
|
|
73
73
|
private setupAndPublish;
|
|
74
74
|
/**
|
|
75
75
|
* Create an agent and session under one caller-supplied identity, owned by
|
|
76
|
-
* the accessing fiber.
|
|
76
|
+
* the accessing fiber. When a persistence backend is mounted, the session's
|
|
77
|
+
* durable identity is stored before publication.
|
|
77
78
|
* @param ownerCtx - caller context that structurally owns the lifecycle.
|
|
78
79
|
* @param options - identities, session seed/metadata, loop options, setup, and cancellation.
|
|
79
80
|
* @returns the published handle.
|
|
80
81
|
*/
|
|
81
82
|
createAgent(ownerCtx: Context, options: CreateAgentOptions): Promise<AgentHandle>;
|
|
83
|
+
/**
|
|
84
|
+
* Take a fresh session's write ownership when persistence is mounted.
|
|
85
|
+
* Nothing is appended here: the constructor seed (which never re-emits
|
|
86
|
+
* through `session/event`) is stored by {@link appendUnstoredSuffix} at the
|
|
87
|
+
* publication commit point, so a failed or cancelled setup closes an
|
|
88
|
+
* unmaterialized handle and leaves no stored residue — the same id can be
|
|
89
|
+
* created again.
|
|
90
|
+
* @param session - the unpublished session to store.
|
|
91
|
+
* @param signal - optional cancellation forwarded to the backend create.
|
|
92
|
+
* @returns the owned handle and stored cursor, or `undefined` without a backend.
|
|
93
|
+
*/
|
|
94
|
+
private createStoredSession;
|
|
95
|
+
/**
|
|
96
|
+
* Durably store the session events appended since the last stored cursor.
|
|
97
|
+
* Pre-publication appends (constructor seed markers, setup-window events)
|
|
98
|
+
* never re-emit through `session/event`, so publication must flush them
|
|
99
|
+
* through the handle before live events start routing into it.
|
|
100
|
+
* @param stored - the session's owned handle and stored cursor, if any.
|
|
101
|
+
* @param session - the unpublished session whose suffix is stored.
|
|
102
|
+
*/
|
|
103
|
+
private appendUnstoredSuffix;
|
|
82
104
|
/**
|
|
83
105
|
* Resume an owned agent from the configured persistence service.
|
|
84
106
|
* @param ownerCtx - caller context that owns load, setup, and the live lifecycle.
|
|
@@ -86,7 +108,7 @@ export declare class CodexLoop extends Service implements AgentFactory {
|
|
|
86
108
|
* @returns the published handle.
|
|
87
109
|
*/
|
|
88
110
|
resume(ownerCtx: Context, options: ResumeAgentOptions): Promise<AgentHandle>;
|
|
89
|
-
/** Resume through an explicit persistence
|
|
111
|
+
/** Resume through an explicit persistence service. */
|
|
90
112
|
private resumeWith;
|
|
91
113
|
}
|
|
92
114
|
//# sourceMappingURL=loop.d.ts.map
|
|
@@ -17,6 +17,8 @@ import type { Session, SessionId, UserMessage } from '@deepseek-ai/dsh-session';
|
|
|
17
17
|
import type { Context } from '@deepseek-ai/cordis';
|
|
18
18
|
import type { ResolvedConfig } from './types.ts';
|
|
19
19
|
import type { KimiSpawnCapability } from './process.ts';
|
|
20
|
+
/** Provider route label used for logged header snapshots and message provenance. */
|
|
21
|
+
export declare const PROVIDER = "kimi";
|
|
20
22
|
/** Drives one session through turn and step boundaries on Kimi Code. */
|
|
21
23
|
export declare class KimiAgent implements Agent {
|
|
22
24
|
private loopCtx;
|
|
@@ -16,6 +16,13 @@
|
|
|
16
16
|
* the goal form). `skill:` commands are already carried by the dsh skill
|
|
17
17
|
* injection seam and Kimi's own shorthand, so they are not duplicated here.
|
|
18
18
|
*
|
|
19
|
+
* `model` is deliberately absent even though the CLI has it: the dsh web
|
|
20
|
+
* client owns a `/model` contribution, and a same-named host command makes
|
|
21
|
+
* `ui-commands` throw the whole command menu source away, leaving only the
|
|
22
|
+
* skill group. `/goal` stays: the managed block disables dsh's `command-goal`
|
|
23
|
+
* row for hosted engines, so the slot is free and the CLI's own goal mode
|
|
24
|
+
* takes it over.
|
|
25
|
+
*
|
|
19
26
|
* @module dsh-loop-engine/engine-kimi/commands
|
|
20
27
|
*/
|
|
21
28
|
import type { CommandDefinition, CommandInvocation, CommandResult } from '../commands.ts';
|
|
@@ -67,12 +67,34 @@ export declare class KimiLoop extends Service implements AgentFactory {
|
|
|
67
67
|
private setupAndPublish;
|
|
68
68
|
/**
|
|
69
69
|
* Create an agent and session under one caller-supplied identity, owned by
|
|
70
|
-
* the accessing fiber.
|
|
70
|
+
* the accessing fiber. When a persistence backend is mounted, the session's
|
|
71
|
+
* durable identity is stored before publication.
|
|
71
72
|
* @param ownerCtx - caller context that structurally owns the lifecycle.
|
|
72
73
|
* @param options - identities, session seed/metadata, loop options, setup, and cancellation.
|
|
73
74
|
* @returns the published handle.
|
|
74
75
|
*/
|
|
75
76
|
createAgent(ownerCtx: Context, options: CreateAgentOptions): Promise<AgentHandle>;
|
|
77
|
+
/**
|
|
78
|
+
* Take a fresh session's write ownership when persistence is mounted.
|
|
79
|
+
* Nothing is appended here: the constructor seed (which never re-emits
|
|
80
|
+
* through `session/event`) is stored by {@link appendUnstoredSuffix} at the
|
|
81
|
+
* publication commit point, so a failed or cancelled setup closes an
|
|
82
|
+
* unmaterialized handle and leaves no stored residue — the same id can be
|
|
83
|
+
* created again.
|
|
84
|
+
* @param session - the unpublished session to store.
|
|
85
|
+
* @param signal - optional cancellation forwarded to the backend create.
|
|
86
|
+
* @returns the owned handle and stored cursor, or `undefined` without a backend.
|
|
87
|
+
*/
|
|
88
|
+
private createStoredSession;
|
|
89
|
+
/**
|
|
90
|
+
* Durably store the session events appended since the last stored cursor.
|
|
91
|
+
* Pre-publication appends (constructor seed markers, setup-window events)
|
|
92
|
+
* never re-emit through `session/event`, so publication must flush them
|
|
93
|
+
* through the handle before live events start routing into it.
|
|
94
|
+
* @param stored - the session's owned handle and stored cursor, if any.
|
|
95
|
+
* @param session - the unpublished session whose suffix is stored.
|
|
96
|
+
*/
|
|
97
|
+
private appendUnstoredSuffix;
|
|
76
98
|
/**
|
|
77
99
|
* Resume an owned agent from the configured persistence service.
|
|
78
100
|
* @param ownerCtx - caller context that owns load, setup, and the live lifecycle.
|
|
@@ -80,7 +102,7 @@ export declare class KimiLoop extends Service implements AgentFactory {
|
|
|
80
102
|
* @returns the published handle.
|
|
81
103
|
*/
|
|
82
104
|
resume(ownerCtx: Context, options: ResumeAgentOptions): Promise<AgentHandle>;
|
|
83
|
-
/** Resume through an explicit persistence
|
|
105
|
+
/** Resume through an explicit persistence service. */
|
|
84
106
|
private resumeWith;
|
|
85
107
|
}
|
|
86
108
|
//# sourceMappingURL=loop.d.ts.map
|
|
@@ -17,6 +17,8 @@ import type { Session, SessionId, UserMessage } from '@deepseek-ai/dsh-session';
|
|
|
17
17
|
import type { Context } from '@deepseek-ai/cordis';
|
|
18
18
|
import type { ResolvedConfig } from './types.ts';
|
|
19
19
|
import { type PiSpawnCapability } from './rpc/client.ts';
|
|
20
|
+
/** Provider route label used for logged header snapshots and message provenance. */
|
|
21
|
+
export declare const PROVIDER = "pi";
|
|
20
22
|
/** Drives one session through turn and step boundaries on Pi. */
|
|
21
23
|
export declare class PiAgent implements Agent {
|
|
22
24
|
private loopCtx;
|
|
@@ -107,6 +109,14 @@ export declare class PiAgent implements Agent {
|
|
|
107
109
|
private modelLabel;
|
|
108
110
|
/** Append the request header snapshot once per loop instance. */
|
|
109
111
|
private assertRequestHeader;
|
|
112
|
+
/**
|
|
113
|
+
* The harness Session's web-side model selection, if any was stored. The
|
|
114
|
+
* durable `model/selection` event carries `{ provider, model, ... }`; when a
|
|
115
|
+
* user picked a model via `/model`, this is the newest pick, and it overrides
|
|
116
|
+
* the deployment config (which stays the fallback). Returns `undefined` when
|
|
117
|
+
* no selection was stored, so the deployment config governs.
|
|
118
|
+
*/
|
|
119
|
+
private dynamicModel;
|
|
110
120
|
/** Build the `pi --mode rpc` argv/cwd/env for one step's child process. */
|
|
111
121
|
private spawnSpec;
|
|
112
122
|
/**
|
|
@@ -14,6 +14,7 @@ import { Service } from '@deepseek-ai/cordis';
|
|
|
14
14
|
import type { Context } from '@deepseek-ai/cordis';
|
|
15
15
|
import z from '@deepseek-ai/schemastery';
|
|
16
16
|
import type { AgentFactory, AgentHandle, CreateAgentOptions, ResumeAgentOptions } from '@deepseek-ai/dsh-agent';
|
|
17
|
+
import type { PiModelEntry } from './probe.ts';
|
|
17
18
|
import type { PiProcess, PiSpawnSpec } from './rpc/client.ts';
|
|
18
19
|
import type { PiSandboxMode, ResolvedConfig } from './types.ts';
|
|
19
20
|
/** Pi CLI sandbox modes a deployment may pin. */
|
|
@@ -38,6 +39,10 @@ export interface Config {
|
|
|
38
39
|
thinkingLevel?: string;
|
|
39
40
|
/** Explicit environment entries passed to the `pi` child. */
|
|
40
41
|
env?: Record<string, string>;
|
|
42
|
+
/** Shared Pi model catalog holder; the loop writes its `pi --list-models` probe result here. */
|
|
43
|
+
piCatalogHolder?: {
|
|
44
|
+
entries: readonly PiModelEntry[];
|
|
45
|
+
};
|
|
41
46
|
}
|
|
42
47
|
/** Schema of the Pi loop plugin configuration. */
|
|
43
48
|
export declare const Config: z<Config>;
|
|
@@ -77,12 +82,34 @@ export declare class PiLoop extends Service implements AgentFactory {
|
|
|
77
82
|
private setupAndPublish;
|
|
78
83
|
/**
|
|
79
84
|
* Create an agent and session under one caller-supplied identity, owned by
|
|
80
|
-
* the accessing fiber.
|
|
85
|
+
* the accessing fiber. When a persistence backend is mounted, the session's
|
|
86
|
+
* durable identity is stored before publication.
|
|
81
87
|
* @param ownerCtx - caller context that structurally owns the lifecycle.
|
|
82
88
|
* @param options - identities, session seed/metadata, loop options, setup, and cancellation.
|
|
83
89
|
* @returns the published handle.
|
|
84
90
|
*/
|
|
85
91
|
createAgent(ownerCtx: Context, options: CreateAgentOptions): Promise<AgentHandle>;
|
|
92
|
+
/**
|
|
93
|
+
* Take a fresh session's write ownership when persistence is mounted.
|
|
94
|
+
* Nothing is appended here: the constructor seed (which never re-emits
|
|
95
|
+
* through `session/event`) is stored by {@link appendUnstoredSuffix} at the
|
|
96
|
+
* publication commit point, so a failed or cancelled setup closes an
|
|
97
|
+
* unmaterialized handle and leaves no stored residue — the same id can be
|
|
98
|
+
* created again.
|
|
99
|
+
* @param session - the unpublished session to store.
|
|
100
|
+
* @param signal - optional cancellation forwarded to the backend create.
|
|
101
|
+
* @returns the owned handle and stored cursor, or `undefined` without a backend.
|
|
102
|
+
*/
|
|
103
|
+
private createStoredSession;
|
|
104
|
+
/**
|
|
105
|
+
* Durably store the session events appended since the last stored cursor.
|
|
106
|
+
* Pre-publication appends (constructor seed markers, setup-window events)
|
|
107
|
+
* never re-emit through `session/event`, so publication must flush them
|
|
108
|
+
* through the handle before live events start routing into it.
|
|
109
|
+
* @param stored - the session's owned handle and stored cursor, if any.
|
|
110
|
+
* @param session - the unpublished session whose suffix is stored.
|
|
111
|
+
*/
|
|
112
|
+
private appendUnstoredSuffix;
|
|
86
113
|
/**
|
|
87
114
|
* Resume an owned agent from the configured persistence service.
|
|
88
115
|
* @param ownerCtx - caller context that owns load, setup, and the live lifecycle.
|
|
@@ -90,7 +117,7 @@ export declare class PiLoop extends Service implements AgentFactory {
|
|
|
90
117
|
* @returns the published handle.
|
|
91
118
|
*/
|
|
92
119
|
resume(ownerCtx: Context, options: ResumeAgentOptions): Promise<AgentHandle>;
|
|
93
|
-
/** Resume through an explicit persistence
|
|
120
|
+
/** Resume through an explicit persistence service. */
|
|
94
121
|
private resumeWith;
|
|
95
122
|
}
|
|
96
123
|
//# sourceMappingURL=loop.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { PiProcess, PiSpawnSpec } from './rpc/client.ts';
|
|
2
|
+
/** One discoverable Pi model: the raw two-part identity `pi` exposes. */
|
|
3
|
+
export interface PiModelEntry {
|
|
4
|
+
readonly provider: string;
|
|
5
|
+
readonly model: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Parse the output of `pi --list-models`: a column-aligned table whose first
|
|
9
|
+
* two columns are `provider` and `model`. The header row and blank lines are
|
|
10
|
+
* skipped; long model ids simply occupy more columns. Splitting on 2+ spaces
|
|
11
|
+
* yields provider and model in the first two fields regardless of alignment.
|
|
12
|
+
*/
|
|
13
|
+
export declare function parsePiModelList(output: string): PiModelEntry[];
|
|
14
|
+
/**
|
|
15
|
+
* Spawn `pi --list-models` and return the parsed model entries. Failures
|
|
16
|
+
* (non-zero exit, no stdout, spawn throw) resolve to an empty array so the
|
|
17
|
+
* catalog stays advisory and a probe glitch never breaks the engine mount.
|
|
18
|
+
* @param bin - the Pi CLI entrypoint (from `piCliEntrypoint()`); becomes spec.argv[0].
|
|
19
|
+
* @param spawn - the process-spawn adapter; `piSubprocessSpec` prepends the node
|
|
20
|
+
* prefix, so spec.argv must NOT carry it.
|
|
21
|
+
*/
|
|
22
|
+
export declare function probePiModels(bin: string, spawn: (spec: PiSpawnSpec) => PiProcess): Promise<readonly PiModelEntry[]>;
|
|
23
|
+
//# sourceMappingURL=probe.d.ts.map
|
package/lib/types/index.d.ts
CHANGED
|
@@ -17,6 +17,22 @@
|
|
|
17
17
|
* The settings section is seeded from the block so the UI mirrors the file,
|
|
18
18
|
* and a committed settings change writes the block (only when it differs).
|
|
19
19
|
*
|
|
20
|
+
* A hosted engine also takes over the session's command and skill surface:
|
|
21
|
+
* the block disables dsh's `command-goal` row, and the plugin authors a
|
|
22
|
+
* stripped copy of the `standard` agent preset into the user preset root
|
|
23
|
+
* (see `preset.ts`) and steers the `agent-presets` roster default to it, so
|
|
24
|
+
* new sessions get the engine's commands and skills instead of the dsh-native
|
|
25
|
+
* ones an external engine cannot honor. Switching back to `in-process`
|
|
26
|
+
* restores the previous default.
|
|
27
|
+
*
|
|
28
|
+
* While a hosted engine is mounted the plugin also serves its provider route
|
|
29
|
+
* label (`claude-code` / `codex` / `pi` / `kimi`) from the llm registry with
|
|
30
|
+
* a model-less placeholder adapter (see `provider-route.ts`): the engine logs
|
|
31
|
+
* that label into each session's request/header, and the web host refuses a
|
|
32
|
+
* turn whose session selection names a provider no adapter serves — without
|
|
33
|
+
* the placeholder the second prompt of every hosted session would fail with
|
|
34
|
+
* `model-unavailable`.
|
|
35
|
+
*
|
|
20
36
|
* @module dsh-loop-engine
|
|
21
37
|
*/
|
|
22
38
|
import { Context } from '@deepseek-ai/cordis';
|
|
@@ -12,8 +12,17 @@
|
|
|
12
12
|
* # -- dsh-loop-engine managed block: claude-code --
|
|
13
13
|
* - id: agent-loop
|
|
14
14
|
* disabled: true
|
|
15
|
+
* - id: command-goal
|
|
16
|
+
* disabled: true
|
|
15
17
|
* # -- /dsh-loop-engine managed block --
|
|
16
18
|
*
|
|
19
|
+
* The `command-goal` row goes down with the loop: a hosted engine owns the
|
|
20
|
+
* session's command surface, and dsh's `/goal` would otherwise collide with
|
|
21
|
+
* an engine's own goal command (Kimi) or dangle over a goal service nothing
|
|
22
|
+
* drives (the other engines). The remaining dsh-native commands (`/export`,
|
|
23
|
+
* `/feedback`, `/permission`) are engine-agnostic session/settings controls
|
|
24
|
+
* that keep working under a hosted engine, so they stay.
|
|
25
|
+
*
|
|
17
26
|
* `in-process` renders an absent block (the base bundle's `agent-loop` row
|
|
18
27
|
* stays active and supplies the factory), so switching back removes the span
|
|
19
28
|
* entirely. Any other engine renders the same disable block, and the begin
|
|
@@ -0,0 +1,73 @@
|
|
|
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.
|
|
4
|
+
*
|
|
5
|
+
* 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).
|
|
15
|
+
*
|
|
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.
|
|
21
|
+
*
|
|
22
|
+
* @module dsh-loop-engine/preset
|
|
23
|
+
*/
|
|
24
|
+
/** Preset id the plugin authors into the user preset root. */
|
|
25
|
+
export declare const HOSTED_PRESET_ID = "loop-engine";
|
|
26
|
+
/** Harness-home-relative directory of locally authored presets (mirrors `USER_PRESET_DIR` in `dsh-agent-presets`). */
|
|
27
|
+
export declare const USER_PRESET_DIR = ".agent-presets";
|
|
28
|
+
/** The composition file that makes a directory a preset. */
|
|
29
|
+
export declare const COMPOSITION_FILE = "agent.cordis.yml";
|
|
30
|
+
/** The display-metadata file beside a preset's composition. */
|
|
31
|
+
export declare const METADATA_FILE = "preset.yml";
|
|
32
|
+
/** Source preset the hosted preset derives from. */
|
|
33
|
+
export declare const SOURCE_PRESET_ID = "standard";
|
|
34
|
+
/**
|
|
35
|
+
* Top-level rows stripped from the source preset for hosted engines:
|
|
36
|
+
* - `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;
|
|
40
|
+
* - `planning`: dsh plan mode — its only model-visible effect is a system
|
|
41
|
+
* prompt section an external engine never assembles;
|
|
42
|
+
* - `compaction`: dsh `/compact` and auto-compaction — a hosted engine owns
|
|
43
|
+
* its context and its own `/compact` (Claude, Kimi).
|
|
44
|
+
*/
|
|
45
|
+
export declare const STRIPPED_ROWS: readonly ["skill-filesystem", "tool-skill", "tool-goal", "planning", "compaction"];
|
|
46
|
+
/**
|
|
47
|
+
* Remove top-level entries by id from a preset composition, preserving every
|
|
48
|
+
* other byte. Each entry owns the comment/blank run directly above its opener
|
|
49
|
+
* — that run is the entry's section heading and drops with it — except the
|
|
50
|
+
* run above the FIRST entry, which is the file header and stays. Entries
|
|
51
|
+
* without an `id` opener are always kept: the transform touches only what it
|
|
52
|
+
* can name.
|
|
53
|
+
* @param text - the source composition.
|
|
54
|
+
* @param ids - top-level row ids to strip.
|
|
55
|
+
* @returns the stripped composition.
|
|
56
|
+
*/
|
|
57
|
+
export declare function stripPresetRows(text: string, ids?: readonly string[]): string;
|
|
58
|
+
/** Minimal read seam over the host's preset roster (`AgentPresets.read`). */
|
|
59
|
+
export interface PresetCompositionSource {
|
|
60
|
+
/** Read one preset's composition text; throws when the id is unknown. */
|
|
61
|
+
read(id: string): Promise<string>;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Regenerate the hosted-engine preset under the dsh home's user preset root
|
|
65
|
+
* from the roster's `standard` preset. Idempotent: an up-to-date directory is
|
|
66
|
+
* untouched, so no standing mount sees a spurious file-stamp change.
|
|
67
|
+
* @param dshHome - the resolved harness home.
|
|
68
|
+
* @param source - the roster's composition reader.
|
|
69
|
+
* @returns whether any file was written.
|
|
70
|
+
* @throws when the source preset cannot be read or the writes fail.
|
|
71
|
+
*/
|
|
72
|
+
export declare function ensureHostedPreset(dshHome: string, source: PresetCompositionSource): Promise<boolean>;
|
|
73
|
+
//# sourceMappingURL=preset.d.ts.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hosted-engine provider route placeholders.
|
|
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
|
|
6
|
+
* harness llm registry serves — the engine owns its model natively. The web
|
|
7
|
+
* host derives a session's model selection from that header and refuses a turn
|
|
8
|
+
* whose provider no registered adapter serves, so without a placeholder route
|
|
9
|
+
* the SECOND prompt of every hosted session fails with `model-unavailable`.
|
|
10
|
+
* The placeholder serves the label while advertising no models; catalog groups
|
|
11
|
+
* that advertise nothing are dropped, so the model picker is unchanged.
|
|
12
|
+
*
|
|
13
|
+
* @module dsh-loop-engine/provider-route
|
|
14
|
+
*/
|
|
15
|
+
import type { GenerateOptions, LlmModelInfo, StreamChunk } from '@deepseek-ai/dsh-llm';
|
|
16
|
+
import { LlmAdapter } from '@deepseek-ai/dsh-llm';
|
|
17
|
+
import type { LoopEngineId } from './settings.ts';
|
|
18
|
+
import type { PiModelEntry } from './engine-pi/probe.ts';
|
|
19
|
+
/** Provider route label each hosted engine logs into its sessions' request/header. */
|
|
20
|
+
export declare const HOSTED_PROVIDER_ROUTES: Readonly<Record<Exclude<LoopEngineId, 'in-process'>, string>>;
|
|
21
|
+
/** Injectable catalog source a hosted engine route can advertise over the placeholder. */
|
|
22
|
+
export interface HostedEngineRouteAdapterOptions {
|
|
23
|
+
/**
|
|
24
|
+
* Optional model catalog generator. When present, `listModels` advertises
|
|
25
|
+
* these entries under this route's provider label; when absent, the catalog
|
|
26
|
+
* stays empty (the default, "engine owns its models" behavior).
|
|
27
|
+
*/
|
|
28
|
+
readonly listModels?: () => readonly PiModelEntry[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Placeholder adapter serving one hosted engine's provider route label. It
|
|
32
|
+
* inherits the empty catalog and default metadata (the engine's model is not a
|
|
33
|
+
* harness-selectable endpoint), and {@link stream} fails loud: a call reaching
|
|
34
|
+
* it means a real model query was routed to an engine that owns its model
|
|
35
|
+
* natively — a wiring bug, not a request to serve.
|
|
36
|
+
*/
|
|
37
|
+
export declare class HostedEngineRouteAdapter extends LlmAdapter {
|
|
38
|
+
private readonly label;
|
|
39
|
+
private readonly options;
|
|
40
|
+
/**
|
|
41
|
+
* @param label - the provider route label this placeholder serves.
|
|
42
|
+
* @param options - optional catalog source; omit for an empty catalog.
|
|
43
|
+
*/
|
|
44
|
+
constructor(label: string, options?: HostedEngineRouteAdapterOptions);
|
|
45
|
+
/** Advertise the injected Pi models (if any) under this route's provider label. */
|
|
46
|
+
listModels(_provider: string): Promise<readonly LlmModelInfo[]>;
|
|
47
|
+
stream(_options: GenerateOptions): AsyncIterable<StreamChunk>;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=provider-route.d.ts.map
|
package/lib/types/settings.d.ts
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Shared loop-engine identity, namespace, and schema.
|
|
3
3
|
*
|
|
4
4
|
* The namespace literal lives in the zero-import `./namespace.ts` so both
|
|
5
|
-
* halves agree on the section name: the node half brands it
|
|
6
|
-
* `
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* halves agree on the section name: the node half brands it as a
|
|
6
|
+
* `SettingsNamespace`, while the browser half imports the same literal
|
|
7
|
+
* without pulling the host-side `dsh-settings` service into the client
|
|
8
|
+
* bundle (cross-plugin value imports go through cordis services, and
|
|
9
9
|
* `settings-scope.ts` follows the same discipline).
|
|
10
10
|
*
|
|
11
11
|
* @module dsh-loop-engine/settings
|
|
@@ -26,6 +26,6 @@ export interface LoopEngineSettings {
|
|
|
26
26
|
}
|
|
27
27
|
/** Schema of the loop engine settings section. */
|
|
28
28
|
export declare const LOOP_ENGINE_SETTINGS_SCHEMA: z<LoopEngineSettings>;
|
|
29
|
-
/**
|
|
29
|
+
/** The shared literal branded as a settings namespace on the node side. */
|
|
30
30
|
export declare function loopEngineSettingsNamespace(): SettingsNamespace;
|
|
31
31
|
//# sourceMappingURL=settings.d.ts.map
|