dsh-loop-engine 1.0.0-rc10
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 +121 -0
- package/README.zh.md +38 -0
- package/cordis.patch.yml +3 -0
- package/lib/client.js +37506 -0
- package/lib/index.js +6412 -0
- package/lib/invariant.js +108 -0
- package/lib/types/client/LoopEngineBadge.d.ts +34 -0
- package/lib/types/client/LoopEngineComposerSelect.d.ts +40 -0
- package/lib/types/client/LoopEngineSection.d.ts +34 -0
- package/lib/types/client/index.d.ts +29 -0
- package/lib/types/client/locales.d.ts +46 -0
- package/lib/types/client/store.d.ts +58 -0
- package/lib/types/commands.d.ts +69 -0
- package/lib/types/driver-core/context-files.d.ts +62 -0
- package/lib/types/driver-core/ownership.d.ts +40 -0
- package/lib/types/driver-core/permission-knobs.d.ts +26 -0
- package/lib/types/driver-core/prompt.d.ts +23 -0
- package/lib/types/driver-core/skill-inject.d.ts +59 -0
- package/lib/types/engine-claude/agent.d.ts +104 -0
- package/lib/types/engine-claude/loop.d.ts +111 -0
- package/lib/types/engine-claude/mapping.d.ts +83 -0
- package/lib/types/engine-claude/permission.d.ts +41 -0
- package/lib/types/engine-claude/process.d.ts +59 -0
- package/lib/types/engine-claude/sdk.d.ts +57 -0
- package/lib/types/engine-claude/types.d.ts +18 -0
- package/lib/types/engine-codex/agent.d.ts +111 -0
- package/lib/types/engine-codex/appserver/client.d.ts +49 -0
- package/lib/types/engine-codex/appserver/mapping.d.ts +67 -0
- package/lib/types/engine-codex/appserver/thread.d.ts +66 -0
- package/lib/types/engine-codex/appserver/types.d.ts +215 -0
- package/lib/types/engine-codex/loop.d.ts +114 -0
- package/lib/types/engine-codex/permission.d.ts +32 -0
- package/lib/types/engine-codex/skills.d.ts +29 -0
- package/lib/types/engine-codex/types.d.ts +19 -0
- package/lib/types/engine-kimi/acp/client.d.ts +76 -0
- package/lib/types/engine-kimi/acp/mapping.d.ts +44 -0
- package/lib/types/engine-kimi/acp/types.d.ts +95 -0
- package/lib/types/engine-kimi/agent.d.ts +123 -0
- package/lib/types/engine-kimi/commands.d.ts +40 -0
- package/lib/types/engine-kimi/loop.d.ts +108 -0
- package/lib/types/engine-kimi/mapping.d.ts +71 -0
- package/lib/types/engine-kimi/permission.d.ts +28 -0
- package/lib/types/engine-kimi/process.d.ts +61 -0
- package/lib/types/engine-kimi/skills.d.ts +57 -0
- package/lib/types/engine-kimi/types.d.ts +23 -0
- package/lib/types/engine-pi/agent.d.ts +135 -0
- package/lib/types/engine-pi/loop.d.ts +123 -0
- package/lib/types/engine-pi/permission.d.ts +43 -0
- package/lib/types/engine-pi/probe.d.ts +23 -0
- package/lib/types/engine-pi/rpc/client.d.ts +105 -0
- package/lib/types/engine-pi/rpc/mapping.d.ts +37 -0
- package/lib/types/engine-pi/rpc/types.d.ts +235 -0
- package/lib/types/engine-pi/skills.d.ts +55 -0
- package/lib/types/engine-pi/types.d.ts +27 -0
- package/lib/types/index.d.ts +114 -0
- package/lib/types/invariant.d.ts +23 -0
- package/lib/types/namespace.d.ts +9 -0
- package/lib/types/patch-manager.d.ts +59 -0
- package/lib/types/preset.d.ts +73 -0
- package/lib/types/provider-route.d.ts +49 -0
- package/lib/types/settings.d.ts +31 -0
- package/lib/types/skills.d.ts +93 -0
- package/package.json +103 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps completed app-server items and turn usage to dsh session-log events.
|
|
3
|
+
* Only these end-state projections live here: token-level streaming deltas are
|
|
4
|
+
* folded inline by the driver's step loop; this module turns the item that
|
|
5
|
+
* finished a stream into the durable tool/call + tool/result events and folds
|
|
6
|
+
* a finished turn's usage into a TokenUsage.
|
|
7
|
+
*
|
|
8
|
+
* @module dsh-loop-engine/engine-codex/appserver/mapping
|
|
9
|
+
*/
|
|
10
|
+
import type { TokenUsage, ToolResultMessage } from '@deepseek-ai/dsh-llm';
|
|
11
|
+
import { ToolCallId } from '@deepseek-ai/dsh-llm';
|
|
12
|
+
/** Map app-server turn usage to dsh TokenUsage. */
|
|
13
|
+
export declare function mapUsage(usage: {
|
|
14
|
+
inputTokens: number;
|
|
15
|
+
outputTokens: number;
|
|
16
|
+
cachedInputTokens?: number;
|
|
17
|
+
reasoningOutputTokens?: number;
|
|
18
|
+
}): TokenUsage;
|
|
19
|
+
/** Map a completed commandExecution item to tool call and result message. */
|
|
20
|
+
export declare function mapCommandExecution(item: {
|
|
21
|
+
id: string;
|
|
22
|
+
command?: string;
|
|
23
|
+
aggregatedOutput?: string | null;
|
|
24
|
+
exitCode?: number | null;
|
|
25
|
+
status?: string;
|
|
26
|
+
}): {
|
|
27
|
+
call: {
|
|
28
|
+
callId: ToolCallId;
|
|
29
|
+
name: string;
|
|
30
|
+
arguments: string;
|
|
31
|
+
};
|
|
32
|
+
result: ToolResultMessage;
|
|
33
|
+
};
|
|
34
|
+
/** Map a completed fileChange item to tool call and result message. */
|
|
35
|
+
export declare function mapFileChange(item: {
|
|
36
|
+
id: string;
|
|
37
|
+
changes?: unknown[];
|
|
38
|
+
status?: string;
|
|
39
|
+
}): {
|
|
40
|
+
call: {
|
|
41
|
+
callId: ToolCallId;
|
|
42
|
+
name: string;
|
|
43
|
+
arguments: string;
|
|
44
|
+
};
|
|
45
|
+
result: ToolResultMessage;
|
|
46
|
+
};
|
|
47
|
+
/** Map a completed mcpToolCall item to tool call and result message. */
|
|
48
|
+
export declare function mapMcpToolCall(item: {
|
|
49
|
+
id: string;
|
|
50
|
+
server?: string;
|
|
51
|
+
tool?: string;
|
|
52
|
+
arguments?: unknown;
|
|
53
|
+
result?: {
|
|
54
|
+
content?: unknown[];
|
|
55
|
+
};
|
|
56
|
+
error?: {
|
|
57
|
+
message?: string;
|
|
58
|
+
};
|
|
59
|
+
}): {
|
|
60
|
+
call: {
|
|
61
|
+
callId: ToolCallId;
|
|
62
|
+
name: string;
|
|
63
|
+
arguments: string;
|
|
64
|
+
};
|
|
65
|
+
result: ToolResultMessage;
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=mapping.d.ts.map
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thread lifecycle management for the codex app-server. Wraps a codex thread
|
|
3
|
+
* and its turn-level streaming, producing dsh-native events from the
|
|
4
|
+
* app-server's JSON-RPC notifications.
|
|
5
|
+
*
|
|
6
|
+
* @module dsh-loop-engine/engine-codex/appserver/thread
|
|
7
|
+
*/
|
|
8
|
+
import type { AppServerClient } from './client.ts';
|
|
9
|
+
import type { ErrorNotification, ItemCompletedNotification, ThreadStartParams, ThreadTokenUsageUpdatedNotification, TurnCompletedNotification, TurnInput } from './types.ts';
|
|
10
|
+
/** An event yielded during a turn's streaming. */
|
|
11
|
+
export type AppServerEvent = {
|
|
12
|
+
readonly kind: 'turn-started';
|
|
13
|
+
readonly turnId: string;
|
|
14
|
+
} | {
|
|
15
|
+
readonly kind: 'item-started';
|
|
16
|
+
readonly itemType: string;
|
|
17
|
+
readonly itemId: string;
|
|
18
|
+
} | {
|
|
19
|
+
readonly kind: 'agent-delta';
|
|
20
|
+
readonly itemId: string;
|
|
21
|
+
readonly delta: string;
|
|
22
|
+
} | {
|
|
23
|
+
readonly kind: 'reasoning-summary-delta';
|
|
24
|
+
readonly itemId: string;
|
|
25
|
+
readonly delta: string;
|
|
26
|
+
readonly summaryIndex: number;
|
|
27
|
+
} | {
|
|
28
|
+
readonly kind: 'reasoning-text-delta';
|
|
29
|
+
readonly itemId: string;
|
|
30
|
+
readonly delta: string;
|
|
31
|
+
readonly contentIndex: number;
|
|
32
|
+
} | {
|
|
33
|
+
readonly kind: 'plan-delta';
|
|
34
|
+
readonly itemId: string;
|
|
35
|
+
readonly delta: string;
|
|
36
|
+
} | {
|
|
37
|
+
readonly kind: 'item-completed';
|
|
38
|
+
readonly item: ItemCompletedNotification['item'];
|
|
39
|
+
} | {
|
|
40
|
+
readonly kind: 'turn-completed';
|
|
41
|
+
readonly turn: TurnCompletedNotification['turn'];
|
|
42
|
+
} | {
|
|
43
|
+
readonly kind: 'token-usage';
|
|
44
|
+
readonly usage: ThreadTokenUsageUpdatedNotification['tokenUsage'];
|
|
45
|
+
} | {
|
|
46
|
+
readonly kind: 'error';
|
|
47
|
+
readonly error: ErrorNotification['error'];
|
|
48
|
+
readonly willRetry: boolean;
|
|
49
|
+
};
|
|
50
|
+
/** Wraps one codex thread and its streaming turns. */
|
|
51
|
+
export declare class AppServerThread {
|
|
52
|
+
private readonly client;
|
|
53
|
+
readonly threadId: string;
|
|
54
|
+
constructor(client: AppServerClient, threadId: string);
|
|
55
|
+
/** Create a new thread on the app-server. */
|
|
56
|
+
static create(client: AppServerClient, params: ThreadStartParams): Promise<AppServerThread>;
|
|
57
|
+
/**
|
|
58
|
+
* Start a turn and stream its events as an async generator.
|
|
59
|
+
* The generator ends when the turn completes or an error occurs.
|
|
60
|
+
*/
|
|
61
|
+
turn(input: readonly TurnInput[], options: {
|
|
62
|
+
signal?: AbortSignal;
|
|
63
|
+
params?: Partial<Omit<import('./types.ts').TurnStartParams, 'threadId' | 'input'>>;
|
|
64
|
+
}): AsyncGenerator<AppServerEvent, void, void>;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=thread.d.ts.map
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App-server protocol type definitions. A minimal subset of the types generated
|
|
3
|
+
* by `codex app-server generate-ts`, covering only what the driver needs for
|
|
4
|
+
* streaming (initialize, thread/start, turn/start, notifications).
|
|
5
|
+
*
|
|
6
|
+
* @module dsh-loop-engine/engine-codex/appserver/types
|
|
7
|
+
*/
|
|
8
|
+
/** A JSON-RPC 2.0 request sent to the app-server. */
|
|
9
|
+
export interface JsonRpcRequest {
|
|
10
|
+
readonly jsonrpc: '2.0';
|
|
11
|
+
readonly id: number;
|
|
12
|
+
readonly method: string;
|
|
13
|
+
readonly params?: unknown;
|
|
14
|
+
}
|
|
15
|
+
/** A JSON-RPC 2.0 response (success or error). */
|
|
16
|
+
export interface JsonRpcResponse {
|
|
17
|
+
readonly id: number;
|
|
18
|
+
readonly result?: unknown;
|
|
19
|
+
readonly error?: {
|
|
20
|
+
readonly code: number;
|
|
21
|
+
readonly message: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** A JSON-RPC 2.0 notification (no id). */
|
|
25
|
+
export interface JsonRpcNotification {
|
|
26
|
+
readonly method: string;
|
|
27
|
+
readonly params: unknown;
|
|
28
|
+
}
|
|
29
|
+
export interface InitializeParams {
|
|
30
|
+
readonly clientInfo: {
|
|
31
|
+
readonly name: string;
|
|
32
|
+
readonly title: string | null;
|
|
33
|
+
readonly version: string;
|
|
34
|
+
};
|
|
35
|
+
readonly capabilities: {
|
|
36
|
+
readonly experimentalApi: boolean;
|
|
37
|
+
readonly requestAttestation: boolean;
|
|
38
|
+
} | null;
|
|
39
|
+
}
|
|
40
|
+
export interface InitializeResult {
|
|
41
|
+
readonly userAgent: string;
|
|
42
|
+
readonly codexHome: string;
|
|
43
|
+
readonly platformFamily: string;
|
|
44
|
+
readonly platformOs: string;
|
|
45
|
+
}
|
|
46
|
+
/** Sandbox mode accepted by `thread/start`; unlike turn policies, this is a string enum. */
|
|
47
|
+
export type SandboxMode = 'read-only' | 'workspace-write' | 'danger-full-access';
|
|
48
|
+
/** Internally tagged sandbox override accepted by `turn/start`. */
|
|
49
|
+
export type SandboxPolicy = {
|
|
50
|
+
readonly type: 'dangerFullAccess';
|
|
51
|
+
} | {
|
|
52
|
+
readonly type: 'readOnly';
|
|
53
|
+
readonly networkAccess: boolean;
|
|
54
|
+
} | {
|
|
55
|
+
readonly type: 'externalSandbox';
|
|
56
|
+
readonly networkAccess: 'restricted' | 'enabled';
|
|
57
|
+
} | {
|
|
58
|
+
readonly type: 'workspaceWrite';
|
|
59
|
+
readonly writableRoots: readonly string[];
|
|
60
|
+
readonly networkAccess: boolean;
|
|
61
|
+
readonly excludeTmpdirEnvVar: boolean;
|
|
62
|
+
readonly excludeSlashTmp: boolean;
|
|
63
|
+
};
|
|
64
|
+
export interface ThreadStartParams {
|
|
65
|
+
readonly model?: string | null;
|
|
66
|
+
readonly modelProvider?: string | null;
|
|
67
|
+
readonly cwd?: string | null;
|
|
68
|
+
readonly approvalPolicy?: string | null;
|
|
69
|
+
readonly sandbox?: SandboxMode | null;
|
|
70
|
+
readonly ephemeral?: boolean | null;
|
|
71
|
+
readonly [key: string]: unknown;
|
|
72
|
+
}
|
|
73
|
+
export interface ThreadInfo {
|
|
74
|
+
readonly id: string;
|
|
75
|
+
readonly sessionId: string;
|
|
76
|
+
readonly modelProvider: string;
|
|
77
|
+
readonly [key: string]: unknown;
|
|
78
|
+
}
|
|
79
|
+
export interface ThreadStartResult {
|
|
80
|
+
readonly thread: ThreadInfo;
|
|
81
|
+
}
|
|
82
|
+
export interface ThreadResumeParams {
|
|
83
|
+
readonly threadId: string;
|
|
84
|
+
readonly cwd?: string | null;
|
|
85
|
+
readonly approvalPolicy?: string | null;
|
|
86
|
+
readonly sandbox?: string | null;
|
|
87
|
+
readonly [key: string]: unknown;
|
|
88
|
+
}
|
|
89
|
+
export interface TurnStartParams {
|
|
90
|
+
readonly threadId: string;
|
|
91
|
+
readonly input: readonly TurnInput[];
|
|
92
|
+
readonly cwd?: string | null;
|
|
93
|
+
readonly approvalPolicy?: string | null;
|
|
94
|
+
readonly sandboxPolicy?: SandboxPolicy | null;
|
|
95
|
+
readonly model?: string | null;
|
|
96
|
+
readonly [key: string]: unknown;
|
|
97
|
+
}
|
|
98
|
+
export interface TurnInput {
|
|
99
|
+
readonly type: 'text';
|
|
100
|
+
readonly text: string;
|
|
101
|
+
}
|
|
102
|
+
export interface TurnInfo {
|
|
103
|
+
readonly id: string;
|
|
104
|
+
readonly status: string;
|
|
105
|
+
readonly error: {
|
|
106
|
+
readonly message: string;
|
|
107
|
+
} | null;
|
|
108
|
+
readonly items: readonly unknown[];
|
|
109
|
+
readonly [key: string]: unknown;
|
|
110
|
+
}
|
|
111
|
+
export interface TurnStartResult {
|
|
112
|
+
readonly turn: TurnInfo;
|
|
113
|
+
}
|
|
114
|
+
export interface TurnInterruptParams {
|
|
115
|
+
readonly threadId: string;
|
|
116
|
+
readonly turnId: string;
|
|
117
|
+
}
|
|
118
|
+
/** item/agentMessage/delta — agent message token delta. */
|
|
119
|
+
export interface AgentMessageDeltaNotification {
|
|
120
|
+
readonly threadId: string;
|
|
121
|
+
readonly turnId: string;
|
|
122
|
+
readonly itemId: string;
|
|
123
|
+
readonly delta: string;
|
|
124
|
+
}
|
|
125
|
+
/** item/reasoning/summaryTextDelta — reasoning summary token delta. */
|
|
126
|
+
export interface ReasoningSummaryTextDeltaNotification {
|
|
127
|
+
readonly threadId: string;
|
|
128
|
+
readonly turnId: string;
|
|
129
|
+
readonly itemId: string;
|
|
130
|
+
readonly delta: string;
|
|
131
|
+
readonly summaryIndex: number;
|
|
132
|
+
}
|
|
133
|
+
/** item/reasoning/textDelta — reasoning content token delta. */
|
|
134
|
+
export interface ReasoningTextDeltaNotification {
|
|
135
|
+
readonly threadId: string;
|
|
136
|
+
readonly turnId: string;
|
|
137
|
+
readonly itemId: string;
|
|
138
|
+
readonly delta: string;
|
|
139
|
+
readonly contentIndex: number;
|
|
140
|
+
}
|
|
141
|
+
/** item/plan/delta — plan delta. */
|
|
142
|
+
export interface PlanDeltaNotification {
|
|
143
|
+
readonly threadId: string;
|
|
144
|
+
readonly turnId: string;
|
|
145
|
+
readonly itemId: string;
|
|
146
|
+
readonly delta: string;
|
|
147
|
+
}
|
|
148
|
+
/** item/started — item lifecycle start. */
|
|
149
|
+
export interface ItemStartedNotification {
|
|
150
|
+
readonly threadId: string;
|
|
151
|
+
readonly turnId: string;
|
|
152
|
+
readonly item: {
|
|
153
|
+
readonly type: string;
|
|
154
|
+
readonly id: string;
|
|
155
|
+
readonly [key: string]: unknown;
|
|
156
|
+
};
|
|
157
|
+
readonly startedAtMs: number;
|
|
158
|
+
}
|
|
159
|
+
/** item/completed — item lifecycle end. */
|
|
160
|
+
export interface ItemCompletedNotification {
|
|
161
|
+
readonly threadId: string;
|
|
162
|
+
readonly turnId: string;
|
|
163
|
+
readonly item: {
|
|
164
|
+
readonly type: string;
|
|
165
|
+
readonly id: string;
|
|
166
|
+
readonly text?: string;
|
|
167
|
+
readonly [key: string]: unknown;
|
|
168
|
+
};
|
|
169
|
+
readonly completedAtMs: number;
|
|
170
|
+
}
|
|
171
|
+
/** turn/completed — turn end with usage. */
|
|
172
|
+
export interface TurnCompletedNotification {
|
|
173
|
+
readonly threadId: string;
|
|
174
|
+
readonly turn: TurnInfo & {
|
|
175
|
+
readonly usage?: {
|
|
176
|
+
readonly inputTokens: number;
|
|
177
|
+
readonly cachedInputTokens?: number;
|
|
178
|
+
readonly outputTokens: number;
|
|
179
|
+
readonly reasoningOutputTokens?: number;
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
/** thread/tokenUsage/updated — token usage update. */
|
|
184
|
+
export interface ThreadTokenUsageUpdatedNotification {
|
|
185
|
+
readonly threadId: string;
|
|
186
|
+
readonly turnId: string;
|
|
187
|
+
readonly tokenUsage: {
|
|
188
|
+
readonly total: {
|
|
189
|
+
readonly totalTokens: number;
|
|
190
|
+
readonly inputTokens: number;
|
|
191
|
+
readonly cachedInputTokens: number;
|
|
192
|
+
readonly outputTokens: number;
|
|
193
|
+
readonly reasoningOutputTokens: number;
|
|
194
|
+
};
|
|
195
|
+
readonly last: {
|
|
196
|
+
readonly totalTokens: number;
|
|
197
|
+
readonly inputTokens: number;
|
|
198
|
+
readonly cachedInputTokens: number;
|
|
199
|
+
readonly outputTokens: number;
|
|
200
|
+
readonly reasoningOutputTokens: number;
|
|
201
|
+
};
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
/** error notification. */
|
|
205
|
+
export interface ErrorNotification {
|
|
206
|
+
readonly threadId: string;
|
|
207
|
+
readonly turnId: string;
|
|
208
|
+
readonly error: {
|
|
209
|
+
readonly message: string;
|
|
210
|
+
readonly codexErrorInfo?: string | null;
|
|
211
|
+
readonly additionalDetails?: string | null;
|
|
212
|
+
};
|
|
213
|
+
readonly willRetry: boolean;
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex loop engine module: hosts the AgentFactory that drives every session
|
|
3
|
+
* through the OpenAI Codex SDK, one stateless thread per dsh step, with the
|
|
4
|
+
* durable session log as the sole source of model context. dsh-loop-engine
|
|
5
|
+
* constructs this factory when the Codex engine is selected; this module is a
|
|
6
|
+
* library, not a Cordis plugin entry. The Codex SDK spawns its own CLI binary
|
|
7
|
+
* (no spawn injection seam), so this loop deliberately does not inject the dsh
|
|
8
|
+
* subprocess service.
|
|
9
|
+
*
|
|
10
|
+
* @module dsh-loop-engine/engine-codex
|
|
11
|
+
*/
|
|
12
|
+
import { Service } from '@deepseek-ai/cordis';
|
|
13
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
14
|
+
import z from '@deepseek-ai/schemastery';
|
|
15
|
+
import type { AgentFactory, AgentHandle, CreateAgentOptions, ResumeAgentOptions } from '@deepseek-ai/dsh-agent';
|
|
16
|
+
import type { CodexApprovalPolicy, CodexSandboxMode, ResolvedConfig } from './types.ts';
|
|
17
|
+
/** Codex CLI sandbox modes a deployment may pin. */
|
|
18
|
+
export declare const CODEX_SANDBOX_MODES: readonly CodexSandboxMode[];
|
|
19
|
+
/** Codex CLI approval policies a deployment may pin. */
|
|
20
|
+
export declare const CODEX_APPROVAL_POLICIES: readonly CodexApprovalPolicy[];
|
|
21
|
+
/** Deployment-owned configuration for the Codex loop plugin. */
|
|
22
|
+
export interface Config {
|
|
23
|
+
/**
|
|
24
|
+
* Pinned sandbox mode for every thread. When omitted, each query follows the
|
|
25
|
+
* session's dsh permission knobs (`sandbox/mode` and `approval/policy`):
|
|
26
|
+
* full access maps to `danger-full-access`, an `ask` policy maps to
|
|
27
|
+
* `workspace-write`, and anything else fails closed with `read-only`.
|
|
28
|
+
*/
|
|
29
|
+
sandboxMode?: CodexSandboxMode;
|
|
30
|
+
/**
|
|
31
|
+
* Pinned approval policy for every thread. When omitted, each query follows
|
|
32
|
+
* the session's dsh permission knobs: an `ask` policy maps to `on-request`
|
|
33
|
+
* (the CLI's own interactive prompt degrades to a denial in the unattended
|
|
34
|
+
* dsh runtime) and anything else maps to `never`.
|
|
35
|
+
*/
|
|
36
|
+
approvalPolicy?: CodexApprovalPolicy;
|
|
37
|
+
/** Explicit environment entries layered over the credential-scrubbed parent environment. */
|
|
38
|
+
env?: Record<string, string>;
|
|
39
|
+
/** Model override for the SDK; Codex native settings own the model when omitted. */
|
|
40
|
+
model?: string;
|
|
41
|
+
}
|
|
42
|
+
/** Schema of the Codex loop plugin configuration. */
|
|
43
|
+
export declare const Config: z<Config>;
|
|
44
|
+
/** Host-face ctx key for the Codex loop service. */
|
|
45
|
+
declare module '@deepseek-ai/cordis' {
|
|
46
|
+
interface Context {
|
|
47
|
+
agentLoopCodex: CodexLoop;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Concrete AgentFactory and driver service of the Codex loop. Creation and
|
|
52
|
+
* resume follow the registry factory contract and the shared publication
|
|
53
|
+
* transaction: prepare, run setup, then publish through both registries,
|
|
54
|
+
* announce, and emit `agent/session-start`.
|
|
55
|
+
*/
|
|
56
|
+
export declare class CodexLoop extends Service implements AgentFactory {
|
|
57
|
+
/** Services the loop resolves through its own fiber; blessed identically to the package-level entry inject. */
|
|
58
|
+
static inject: string[];
|
|
59
|
+
/** Validated configuration owned by the loop plugin. */
|
|
60
|
+
readonly config: ResolvedConfig;
|
|
61
|
+
private readonly ownership;
|
|
62
|
+
/** Plain holder prevents Cordis from re-tracing the factory's dependency context through a caller shadow. */
|
|
63
|
+
private readonly runtime;
|
|
64
|
+
constructor(ctx: Context, config: Config);
|
|
65
|
+
/**
|
|
66
|
+
* Construct the driver, scope, and one memoized reverse teardown for a new
|
|
67
|
+
* agent. The teardown is registered with the factory and the owner fiber
|
|
68
|
+
* BEFORE publication, so a mid-setup unload rolls everything back; `signal`
|
|
69
|
+
* fuses caller cancellation with lifecycle teardown for setup awaits.
|
|
70
|
+
*/
|
|
71
|
+
private prepare;
|
|
72
|
+
/** Prepare one Agent around an acquired Session, run setup, and publish it. */
|
|
73
|
+
private setupAndPublish;
|
|
74
|
+
/**
|
|
75
|
+
* Create an agent and session under one caller-supplied identity, owned by
|
|
76
|
+
* the accessing fiber. When a persistence backend is mounted, the session's
|
|
77
|
+
* durable identity is stored before publication.
|
|
78
|
+
* @param ownerCtx - caller context that structurally owns the lifecycle.
|
|
79
|
+
* @param options - identities, session seed/metadata, loop options, setup, and cancellation.
|
|
80
|
+
* @returns the published handle.
|
|
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;
|
|
104
|
+
/**
|
|
105
|
+
* Resume an owned agent from the configured persistence service.
|
|
106
|
+
* @param ownerCtx - caller context that owns load, setup, and the live lifecycle.
|
|
107
|
+
* @param options - persisted identity, loop options, setup, and cancellation.
|
|
108
|
+
* @returns the published handle.
|
|
109
|
+
*/
|
|
110
|
+
resume(ownerCtx: Context, options: ResumeAgentOptions): Promise<AgentHandle>;
|
|
111
|
+
/** Resume through an explicit persistence service. */
|
|
112
|
+
private resumeWith;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=loop.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mapping from the dsh session's durable permission knobs to one Codex query's
|
|
3
|
+
* declarative permission stance. Codex has no interactive approval callback:
|
|
4
|
+
* permissions are the `sandboxMode` + `approvalPolicy` pair chosen when the
|
|
5
|
+
* thread starts, so the fold maps the session's `sandbox/mode` and
|
|
6
|
+
* `approval/policy` events directly, mirroring the web surface's presets:
|
|
7
|
+
* - full access → `danger-full-access` + `never` (no native checks at all),
|
|
8
|
+
* - an `ask` policy → `workspace-write` + `on-request` (the CLI's own
|
|
9
|
+
* interactive prompt degrades to a denial in the unattended dsh runtime),
|
|
10
|
+
* - anything else fails closed → `read-only` + `never`.
|
|
11
|
+
*
|
|
12
|
+
* @module dsh-loop-engine/engine-codex/permission
|
|
13
|
+
*/
|
|
14
|
+
import type { PermissionEvent } from '../driver-core/permission-knobs.ts';
|
|
15
|
+
import type { CodexApprovalPolicy, CodexSandboxMode } from './types.ts';
|
|
16
|
+
/** The declarative permission stance one Codex thread runs under. */
|
|
17
|
+
export interface CodexPermission {
|
|
18
|
+
readonly sandboxMode: CodexSandboxMode;
|
|
19
|
+
readonly approvalPolicy: CodexApprovalPolicy;
|
|
20
|
+
}
|
|
21
|
+
/** Conservative unattended default: read-only sandbox, never ask. */
|
|
22
|
+
export declare const DEFAULT_CODEX_PERMISSION: CodexPermission;
|
|
23
|
+
/**
|
|
24
|
+
* Resolve the session's effective Codex permission stance. Full access wins
|
|
25
|
+
* outright; otherwise an `ask` policy maps to the CLI's on-request approval
|
|
26
|
+
* inside a workspace-write sandbox; anything else — including a session with
|
|
27
|
+
* no recorded knobs — fails closed.
|
|
28
|
+
* @param events - the durable session log.
|
|
29
|
+
* @returns the stance one query should run under.
|
|
30
|
+
*/
|
|
31
|
+
export declare function resolveSessionPermission(events: readonly PermissionEvent[]): CodexPermission;
|
|
32
|
+
//# sourceMappingURL=permission.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex skill provider: exposes the codex CLI's instruction files as DSH
|
|
3
|
+
* skills.
|
|
4
|
+
*
|
|
5
|
+
* Codex has no per-skill catalog like the agents-skill standard; its
|
|
6
|
+
* instructions are `AGENTS.md` files read from the session cwd up to the git
|
|
7
|
+
* root, plus the global `~/.codex/AGENTS.md`. Each file set is surfaced as one
|
|
8
|
+
* user-invocable `agents-md` skill whose body is the concatenated file
|
|
9
|
+
* contents, so the dsh skill-injection seam (`/name` gestures) can carry it
|
|
10
|
+
* into the prompt.
|
|
11
|
+
*
|
|
12
|
+
* @module dsh-loop-engine/engine-codex/skills
|
|
13
|
+
*/
|
|
14
|
+
import type { SkillCandidate, SkillDefinition, SkillLookupOptions, SkillProvider, SkillProviderControl } from '../skills.ts';
|
|
15
|
+
/**
|
|
16
|
+
* Skill provider that discovers `AGENTS.md` from every directory between the
|
|
17
|
+
* project cwd and the git root, plus the user home `~/.codex/AGENTS.md`.
|
|
18
|
+
*/
|
|
19
|
+
export declare class CodexSkillProvider implements SkillProvider {
|
|
20
|
+
private readonly control;
|
|
21
|
+
readonly name = "codex";
|
|
22
|
+
constructor(control: SkillProviderControl);
|
|
23
|
+
list(options: SkillLookupOptions): Promise<readonly SkillCandidate[]>;
|
|
24
|
+
get(candidate: SkillCandidate, _options: SkillLookupOptions): Promise<SkillDefinition | undefined>;
|
|
25
|
+
/** One merged `agents-md` candidate for a ranked file set. */
|
|
26
|
+
private agentsCandidate;
|
|
27
|
+
}
|
|
28
|
+
export default CodexSkillProvider;
|
|
29
|
+
//# sourceMappingURL=skills.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types of the Codex loop driver. Types only — no runtime code.
|
|
3
|
+
*
|
|
4
|
+
* @module dsh-loop-engine/engine-codex/types
|
|
5
|
+
*/
|
|
6
|
+
/** Codex CLI sandbox modes, as spoken by the app-server `sandbox` field. */
|
|
7
|
+
export type CodexSandboxMode = 'read-only' | 'workspace-write' | 'danger-full-access';
|
|
8
|
+
/** Codex CLI approval policies, as spoken by the app-server `approvalPolicy` field. */
|
|
9
|
+
export type CodexApprovalPolicy = 'never' | 'on-request' | 'on-failure' | 'untrusted';
|
|
10
|
+
/** Driver configuration after defaults and load-time validation. */
|
|
11
|
+
export interface ResolvedConfig {
|
|
12
|
+
/** Pinned sandbox mode; `undefined` follows the session's dsh permission knobs per query. */
|
|
13
|
+
readonly sandboxMode: CodexSandboxMode | undefined;
|
|
14
|
+
/** Pinned approval policy; `undefined` follows the session's dsh permission knobs per query. */
|
|
15
|
+
readonly approvalPolicy: CodexApprovalPolicy | undefined;
|
|
16
|
+
readonly env: Record<string, string>;
|
|
17
|
+
readonly model: string | undefined;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC client for the `kimi acp` subprocess (Agent Client Protocol over
|
|
3
|
+
* stdio).
|
|
4
|
+
*
|
|
5
|
+
* The driver hands the client a process handle carrying its stdin/stdout/stderr
|
|
6
|
+
* (projected from the dsh subprocess seam). The client frames JSON-RPC 2.0
|
|
7
|
+
* records on a bare `\n` (via a byte decoder, tolerating a trailing `\r`),
|
|
8
|
+
* correlates request responses by `id`, dispatches every `session/update`
|
|
9
|
+
* notification to a buffered event stream, and answers the reverse-RPC
|
|
10
|
+
* `session/request_permission` requests the agent publishes. The child is
|
|
11
|
+
* long-lived (one per factory) and stepped over via `newSession` + `prompt`.
|
|
12
|
+
*
|
|
13
|
+
* @module dsh-loop-engine/engine-kimi/acp/client
|
|
14
|
+
*/
|
|
15
|
+
import type { KimiProcess, KimiSpawnCapability, KimiSpawnSpec } from '../process.ts';
|
|
16
|
+
import { type AcpFrame, type AcpUpdate } from './types.ts';
|
|
17
|
+
/** How the client answers one `session/request_permission`. */
|
|
18
|
+
export type AcpPermissionHandler = (request: AcpFrame) => boolean | Promise<boolean>;
|
|
19
|
+
/** Callback receiving every non-response event line. */
|
|
20
|
+
export type AcpUpdateHandler = (update: AcpUpdate) => void;
|
|
21
|
+
/**
|
|
22
|
+
* ACP client over one `kimi acp` child. Created once per driver scope and reused
|
|
23
|
+
* across steps, matching the Pi RPC client's lifecycle.
|
|
24
|
+
*/
|
|
25
|
+
export declare class AcpClient {
|
|
26
|
+
private readonly process;
|
|
27
|
+
private readonly pending;
|
|
28
|
+
private readonly updateBuffer;
|
|
29
|
+
private updateWake;
|
|
30
|
+
private updateHandler;
|
|
31
|
+
private permissionHandler;
|
|
32
|
+
private sealed;
|
|
33
|
+
private nextId;
|
|
34
|
+
private readonly decoder;
|
|
35
|
+
private buffer;
|
|
36
|
+
/** Whether this client was sealed or its process exited. */
|
|
37
|
+
get closed(): boolean;
|
|
38
|
+
/** Mount a client over an already-spawned `kimi acp` process. */
|
|
39
|
+
constructor(process: KimiProcess);
|
|
40
|
+
/**
|
|
41
|
+
* Create a client, spawning the `kimi acp` child through the supplied
|
|
42
|
+
* capability (or the default node spawn when none is given).
|
|
43
|
+
* @param spec - the `kimi acp` argv/cwd/env the child should run with.
|
|
44
|
+
* @param spawn - optional process-spawn capability (the subprocess seam).
|
|
45
|
+
* @returns the connected client.
|
|
46
|
+
*/
|
|
47
|
+
static create(spec: KimiSpawnSpec, spawn?: KimiSpawnCapability): AcpClient;
|
|
48
|
+
/** Register the event dispatch handler. */
|
|
49
|
+
onUpdate(handler: AcpUpdateHandler): void;
|
|
50
|
+
/** Register the permission-approval handler (reverse-RPC answers). */
|
|
51
|
+
onPermission(handler: AcpPermissionHandler): void;
|
|
52
|
+
/** Send one request and await the correlated response. */
|
|
53
|
+
request(method: string, params: unknown): Promise<unknown>;
|
|
54
|
+
/** Send a notification (no correlated response awaited). */
|
|
55
|
+
notify(method: string, params: unknown): void;
|
|
56
|
+
/** Open the protocol handshake. */
|
|
57
|
+
initialize(): Promise<unknown>;
|
|
58
|
+
/** Start a fresh ACP session and resolve to its session id. */
|
|
59
|
+
newSession(cwd: string): Promise<string>;
|
|
60
|
+
/** Prompt the agent in a session and resolve when the turn completes. */
|
|
61
|
+
prompt(sessionId: string, text: string): Promise<unknown>;
|
|
62
|
+
/** Cancel the active turn in a session (fire-and-forget). */
|
|
63
|
+
cancel(sessionId: string): void;
|
|
64
|
+
/** Answer a pending `session/request_permission`. */
|
|
65
|
+
respondPermission(id: number, approved: boolean): void;
|
|
66
|
+
/** Consume every buffered update as an async generator. */
|
|
67
|
+
updates(): AsyncGenerator<AcpUpdate, void, void>;
|
|
68
|
+
/** Seal the client and request child termination. */
|
|
69
|
+
dispose(): void;
|
|
70
|
+
private feed;
|
|
71
|
+
/** Dispatch one parsed line: a response, an update notification, or a reverse-RPC request. */
|
|
72
|
+
private dispatch;
|
|
73
|
+
private settle;
|
|
74
|
+
private handlePermission;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps `kimi acp` `session/update` events to dsh session-log projections.
|
|
3
|
+
*
|
|
4
|
+
* Kimi streams incremental assistant text (`agent_message_chunk`), incremental
|
|
5
|
+
* thinking (`agent_thought_chunk`), a tool-call announcement (`tool_call`) and its
|
|
6
|
+
* progress/result stream (`tool_call_update`). This module is pure: it classifies
|
|
7
|
+
* an update, extracts chunk deltas, and projects the tool-call identity/result so
|
|
8
|
+
* the agent can fold them into the durable log. Content blocks use the observed
|
|
9
|
+
* kimi `{ type: 'content', content: { type: 'text', text } }` nesting; unknown
|
|
10
|
+
* block types are ignored.
|
|
11
|
+
*
|
|
12
|
+
* @module dsh-loop-engine/engine-kimi/acp/mapping
|
|
13
|
+
*/
|
|
14
|
+
import type { ToolResultMessage } from '@deepseek-ai/dsh-llm';
|
|
15
|
+
import type { AcpContentBlock, AcpToolCallExt, AcpToolCallStreamExt, AcpUpdate } from './types.ts';
|
|
16
|
+
/** Whether the update is an incremental assistant text chunk. */
|
|
17
|
+
export declare function isTextChunk(update: AcpUpdate): update is AcpUpdate & {
|
|
18
|
+
readonly sessionUpdate: 'agent_message_chunk';
|
|
19
|
+
readonly content: AcpContentBlock;
|
|
20
|
+
};
|
|
21
|
+
/** Whether the update is an incremental thinking chunk. */
|
|
22
|
+
export declare function isThoughtChunk(update: AcpUpdate): update is AcpUpdate & {
|
|
23
|
+
readonly sessionUpdate: 'agent_thought_chunk';
|
|
24
|
+
readonly content: AcpContentBlock;
|
|
25
|
+
};
|
|
26
|
+
/** Whether the update announces a tool call. */
|
|
27
|
+
export declare function isToolCall(update: AcpUpdate): update is AcpToolCallExt;
|
|
28
|
+
/** Whether the update streams a tool call's progress/result. */
|
|
29
|
+
export declare function isToolCallUpdate(update: AcpUpdate): update is AcpToolCallStreamExt;
|
|
30
|
+
/** The delta text of a text/thinking chunk. */
|
|
31
|
+
export declare function chunkDelta(update: AcpUpdate): string;
|
|
32
|
+
/** The raw tool-call id (+ content index) as the wire carries it. */
|
|
33
|
+
export declare function toolCallIdOf(update: AcpUpdate): string;
|
|
34
|
+
/** The tool display name (`title`). */
|
|
35
|
+
export declare function toolCallName(update: AcpUpdate): string;
|
|
36
|
+
/** Whether a tool stream status is settled (no longer streaming). */
|
|
37
|
+
export declare function isToolSettledStatus(status: string): boolean;
|
|
38
|
+
/** Whether a tool stream status denotes a failure. */
|
|
39
|
+
export declare function isToolErrorStatus(status: string): boolean;
|
|
40
|
+
/** Join the observed `{ type: 'content', content: { type: 'text', text } }` blocks. */
|
|
41
|
+
export declare function toolContentText(update: AcpToolCallExt | AcpToolCallStreamExt): string;
|
|
42
|
+
/** Project a completed tool call to a durable tool/result message. */
|
|
43
|
+
export declare function toolResult(callId: string, text: string, isError: boolean): ToolResultMessage;
|
|
44
|
+
//# sourceMappingURL=mapping.d.ts.map
|