@love-moon/ai-sdk 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/built-in-backends.d.ts +1 -0
- package/dist/built-in-backends.js +6 -0
- package/dist/context-files.d.ts +16 -0
- package/dist/context-files.js +86 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +4 -1
- package/dist/manager/index.d.ts +1 -0
- package/dist/manager/index.js +1 -0
- package/dist/manager/install.js +29 -2
- package/dist/manager/manager.d.ts +5 -1
- package/dist/manager/manager.js +8 -0
- package/dist/manager/network.js +4 -2
- package/dist/manager/quota/dsh.d.ts +55 -0
- package/dist/manager/quota/dsh.js +149 -0
- package/dist/manager/types.d.ts +25 -1
- package/dist/media-adapters.d.ts +34 -0
- package/dist/media-adapters.js +57 -0
- package/dist/media-input.d.ts +21 -0
- package/dist/media-input.js +197 -0
- package/dist/providers/chat-web-session.d.ts +7 -1
- package/dist/providers/chat-web-session.js +12 -1
- package/dist/providers/claude-agent-sdk-session.d.ts +10 -1
- package/dist/providers/claude-agent-sdk-session.js +24 -4
- package/dist/providers/codex-app-server-session.d.ts +19 -21
- package/dist/providers/codex-app-server-session.js +124 -12
- package/dist/providers/codex-exec-session.d.ts +8 -3
- package/dist/providers/codex-exec-session.js +13 -13
- package/dist/providers/copilot-sdk-session.d.ts +6 -1
- package/dist/providers/copilot-sdk-session.js +10 -3
- package/dist/providers/dsh-sdk-session.d.ts +194 -0
- package/dist/providers/dsh-sdk-session.js +951 -0
- package/dist/providers/kimi-cli-session.d.ts +6 -1
- package/dist/providers/kimi-cli-session.js +13 -3
- package/dist/providers/kimi-print-session.d.ts +10 -3
- package/dist/providers/kimi-print-session.js +23 -53
- package/dist/providers/opencode-sdk-session.d.ts +6 -1
- package/dist/providers/opencode-sdk-session.js +11 -9
- package/dist/resume/dsh.d.ts +23 -0
- package/dist/resume/dsh.js +122 -0
- package/dist/resume/index.js +2 -0
- package/dist/session-factory.d.ts +3 -1
- package/dist/session-factory.js +5 -1
- package/dsh/cordis.yml +100 -0
- package/package.json +24 -3
|
@@ -6,6 +6,9 @@ import { randomUUID } from "node:crypto";
|
|
|
6
6
|
import { EventEmitter } from "node:events";
|
|
7
7
|
import readline from "node:readline";
|
|
8
8
|
import { CODEX_EXEC_VARIANT as CODEX_EXEC_PROVIDER_VARIANT } from "../built-in-backends.js";
|
|
9
|
+
import { appendContextFilesToPrompt } from "../context-files.js";
|
|
10
|
+
import { PROVIDER_MEDIA_CAPABILITIES } from "../media-adapters.js";
|
|
11
|
+
import { assertMediaCapabilities, defaultPromptForMedia, resolveTurnMedia, } from "../media-input.js";
|
|
9
12
|
import { emitLog, getBoundedEnvInt, loadEnvConfig, normalizeLogger, parseCommandParts, proxyToEnv, sanitizeForLog, } from "../shared.js";
|
|
10
13
|
const DEFAULT_TURN_DEADLINE_MS = 12 * 60 * 1000;
|
|
11
14
|
const MIN_TURN_DEADLINE_MS = 30 * 1000;
|
|
@@ -239,6 +242,7 @@ export class CodexExecSession extends EventEmitter {
|
|
|
239
242
|
resumeReady: false,
|
|
240
243
|
manualResume: null,
|
|
241
244
|
currentTurnStatus: this.getCurrentTurnStatus(),
|
|
245
|
+
capabilities: { media: PROVIDER_MEDIA_CAPABILITIES[CODEX_EXEC_PROVIDER_VARIANT] },
|
|
242
246
|
pid: this.currentTurn?.child?.pid || undefined,
|
|
243
247
|
};
|
|
244
248
|
}
|
|
@@ -338,7 +342,7 @@ export class CodexExecSession extends EventEmitter {
|
|
|
338
342
|
buildPrompt(promptText) {
|
|
339
343
|
return buildHistoryPrompt(this.history, promptText);
|
|
340
344
|
}
|
|
341
|
-
buildExecArgs({
|
|
345
|
+
buildExecArgs({ media = [], schemaFilePath = "", lastMessageFilePath = "" } = {}) {
|
|
342
346
|
const args = [...this.baseArgs];
|
|
343
347
|
args.push("exec");
|
|
344
348
|
args.push("--json");
|
|
@@ -354,11 +358,8 @@ export class CodexExecSession extends EventEmitter {
|
|
|
354
358
|
if (typeof this.options.model === "string" && this.options.model.trim()) {
|
|
355
359
|
args.push("--model", this.options.model.trim());
|
|
356
360
|
}
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
-
: [];
|
|
360
|
-
for (const imagePath of images) {
|
|
361
|
-
args.push("--image", imagePath);
|
|
361
|
+
for (const image of media.filter((item) => item.kind === "image")) {
|
|
362
|
+
args.push("--image", image.path);
|
|
362
363
|
}
|
|
363
364
|
return args;
|
|
364
365
|
}
|
|
@@ -376,7 +377,7 @@ export class CodexExecSession extends EventEmitter {
|
|
|
376
377
|
message: lastMessage || "Codex authentication required",
|
|
377
378
|
});
|
|
378
379
|
}
|
|
379
|
-
async runTurn(promptText, { useInitialImages = false, onProgress = null, jsonSchema = null } = {}) {
|
|
380
|
+
async runTurn(promptText, { useInitialImages = false, media: mediaInput, contextFiles, onProgress = null, jsonSchema = null } = {}) {
|
|
380
381
|
if (this.closeRequested || this.closed) {
|
|
381
382
|
throw this.createSessionClosedError();
|
|
382
383
|
}
|
|
@@ -385,12 +386,11 @@ export class CodexExecSession extends EventEmitter {
|
|
|
385
386
|
reason: "turn_already_running",
|
|
386
387
|
});
|
|
387
388
|
}
|
|
389
|
+
const media = resolveTurnMedia(this.options, { useInitialImages, media: mediaInput });
|
|
390
|
+
assertMediaCapabilities(media, this.backend, PROVIDER_MEDIA_CAPABILITIES[CODEX_EXEC_PROVIDER_VARIANT]);
|
|
388
391
|
const effectivePrompt = this.buildPrompt(promptText);
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
: [];
|
|
392
|
-
const stdinPrompt = effectivePrompt || (imagePaths.length > 0 ? "Analyze the attached image." : "");
|
|
393
|
-
if (!stdinPrompt && imagePaths.length === 0) {
|
|
392
|
+
const stdinPrompt = appendContextFilesToPrompt(effectivePrompt || (media.length > 0 ? defaultPromptForMedia(media) : ""), contextFiles).prompt;
|
|
393
|
+
if (!stdinPrompt && media.length === 0) {
|
|
394
394
|
return buildEmptyTurnResult();
|
|
395
395
|
}
|
|
396
396
|
const normalizedSchema = normalizeJsonSchema(jsonSchema);
|
|
@@ -416,7 +416,7 @@ export class CodexExecSession extends EventEmitter {
|
|
|
416
416
|
status_line: statusLineForPhase("turn_started"),
|
|
417
417
|
}, onProgress);
|
|
418
418
|
const args = this.buildExecArgs({
|
|
419
|
-
|
|
419
|
+
media,
|
|
420
420
|
schemaFilePath,
|
|
421
421
|
lastMessageFilePath,
|
|
422
422
|
});
|
|
@@ -83,6 +83,11 @@ export class CopilotSdkSession extends EventEmitter<[never]> {
|
|
|
83
83
|
command: string;
|
|
84
84
|
} | null;
|
|
85
85
|
currentTurnStatus: any;
|
|
86
|
+
capabilities: {
|
|
87
|
+
media: Readonly<{
|
|
88
|
+
image: "native";
|
|
89
|
+
}>;
|
|
90
|
+
};
|
|
86
91
|
};
|
|
87
92
|
getSessionInfo(): {
|
|
88
93
|
backend: string;
|
|
@@ -165,7 +170,7 @@ export class CopilotSdkSession extends EventEmitter<[never]> {
|
|
|
165
170
|
handleCopilotEventFailure(error: any): void;
|
|
166
171
|
handleCopilotEvent(event: any): Promise<void>;
|
|
167
172
|
interruptCurrentTurn(): Promise<void>;
|
|
168
|
-
runTurn(promptText: any, { useInitialImages, onProgress }?: {
|
|
173
|
+
runTurn(promptText: any, { useInitialImages, media: mediaInput, contextFiles, onProgress }?: {
|
|
169
174
|
useInitialImages?: boolean | undefined;
|
|
170
175
|
onProgress?: null | undefined;
|
|
171
176
|
}): Promise<{
|
|
@@ -3,6 +3,9 @@ import { existsSync } from "node:fs";
|
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { COPILOT_SDK_VARIANT as COPILOT_PROVIDER_VARIANT } from "../built-in-backends.js";
|
|
6
|
+
import { appendContextFilesToPrompt } from "../context-files.js";
|
|
7
|
+
import { PROVIDER_MEDIA_CAPABILITIES, buildCopilotAttachments } from "../media-adapters.js";
|
|
8
|
+
import { assertMediaCapabilities, defaultPromptForMedia, resolveTurnMedia, } from "../media-input.js";
|
|
6
9
|
import { emitLog, getBoundedEnvInt, loadEnvConfig, normalizeLogger, parseCommandParts, proxyToEnv, sanitizeForLog, withoutCopilotGithubTokenEnv, } from "../shared.js";
|
|
7
10
|
const DEFAULT_TURN_DEADLINE_MS = 12 * 60 * 1000;
|
|
8
11
|
const MIN_TURN_DEADLINE_MS = 30 * 1000;
|
|
@@ -591,6 +594,7 @@ export class CopilotSdkSession extends EventEmitter {
|
|
|
591
594
|
}
|
|
592
595
|
: null,
|
|
593
596
|
currentTurnStatus: this.getCurrentTurnStatus(),
|
|
597
|
+
capabilities: { media: PROVIDER_MEDIA_CAPABILITIES[COPILOT_PROVIDER_VARIANT] },
|
|
594
598
|
};
|
|
595
599
|
}
|
|
596
600
|
getSessionInfo() {
|
|
@@ -1368,12 +1372,14 @@ export class CopilotSdkSession extends EventEmitter {
|
|
|
1368
1372
|
}
|
|
1369
1373
|
}
|
|
1370
1374
|
}
|
|
1371
|
-
async runTurn(promptText, { useInitialImages = false, onProgress = null } = {}) {
|
|
1375
|
+
async runTurn(promptText, { useInitialImages = false, media: mediaInput, contextFiles, onProgress = null } = {}) {
|
|
1372
1376
|
if (this.currentTurn) {
|
|
1373
1377
|
throw this.createTurnAlreadyRunningError();
|
|
1374
1378
|
}
|
|
1375
|
-
const
|
|
1376
|
-
|
|
1379
|
+
const media = resolveTurnMedia(this.options, { useInitialImages, media: mediaInput });
|
|
1380
|
+
assertMediaCapabilities(media, this.backend, PROVIDER_MEDIA_CAPABILITIES[COPILOT_PROVIDER_VARIANT]);
|
|
1381
|
+
const prompt = appendContextFilesToPrompt(this.buildPrompt(promptText, { useInitialImages: false }) || (media.length ? defaultPromptForMedia(media) : ""), contextFiles).prompt;
|
|
1382
|
+
if (!prompt && media.length === 0) {
|
|
1377
1383
|
return {
|
|
1378
1384
|
text: "",
|
|
1379
1385
|
usage: this.lastUsage ? { ...this.lastUsage } : null,
|
|
@@ -1419,6 +1425,7 @@ export class CopilotSdkSession extends EventEmitter {
|
|
|
1419
1425
|
const completion = await Promise.race([
|
|
1420
1426
|
this.requestOrThrow(this.session.sendAndWait({
|
|
1421
1427
|
prompt,
|
|
1428
|
+
attachments: buildCopilotAttachments(media),
|
|
1422
1429
|
mode: "immediate",
|
|
1423
1430
|
}, this.turnDeadlineMs + SDK_SEND_AND_WAIT_TIMEOUT_GRACE_MS)),
|
|
1424
1431
|
closeGuard.promise,
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
export function defaultDshSessionRoot(): string;
|
|
2
|
+
/**
|
|
3
|
+
* DeepSeek Harness (dsh) backend session.
|
|
4
|
+
*
|
|
5
|
+
* Drives a dsh runtime subprocess through `@deepseek-ai/dsh-sdk-client`
|
|
6
|
+
* (stdio JSON-RPC). The runtime composition is the package-owned
|
|
7
|
+
* `dsh/cordis.yml`; the pinned runtime bin comes from
|
|
8
|
+
* `@deepseek-ai/dsh-sdk-jsonrpc-demo`. One DshSdkSession owns at most one
|
|
9
|
+
* runtime subprocess across turns; the dsh-side session id is minted by us
|
|
10
|
+
* (or taken from resumeSessionId) so the same conversation resumes across
|
|
11
|
+
* runtime restarts through dsh's JSONL session persistence.
|
|
12
|
+
*
|
|
13
|
+
* Interrupt semantics: the dsh SDK wire has NO mid-turn cancel. Interrupting
|
|
14
|
+
* closes the runtime subprocess (SIGTERM ladder inside the SDK client) and
|
|
15
|
+
* the next runTurn spawns a fresh runtime resuming the same session id.
|
|
16
|
+
*/
|
|
17
|
+
export class DshSdkSession extends EventEmitter<[never]> {
|
|
18
|
+
static capabilities: Readonly<{
|
|
19
|
+
goal: false;
|
|
20
|
+
}>;
|
|
21
|
+
constructor(backend: any, options?: {});
|
|
22
|
+
getCapabilities(): {
|
|
23
|
+
goal: false;
|
|
24
|
+
};
|
|
25
|
+
backend: string;
|
|
26
|
+
options: {};
|
|
27
|
+
logger: any;
|
|
28
|
+
cwd: any;
|
|
29
|
+
resumeSessionId: any;
|
|
30
|
+
pendingResumeFromSessionId: any;
|
|
31
|
+
sessionId: string;
|
|
32
|
+
sessionIdUsed: boolean;
|
|
33
|
+
model: any;
|
|
34
|
+
dshProvider: any;
|
|
35
|
+
maxTokens: number | undefined;
|
|
36
|
+
sessionRoot: any;
|
|
37
|
+
sessionInfo: {
|
|
38
|
+
backend: string;
|
|
39
|
+
sessionId: string;
|
|
40
|
+
model: any;
|
|
41
|
+
modelProvider: any;
|
|
42
|
+
};
|
|
43
|
+
history: any[];
|
|
44
|
+
pendingHistorySeed: boolean;
|
|
45
|
+
closeRequested: boolean;
|
|
46
|
+
closed: boolean;
|
|
47
|
+
closeWaiters: Set<any>;
|
|
48
|
+
sessionMessageHandler: any;
|
|
49
|
+
workingStatusHandler: any;
|
|
50
|
+
activeReplyTarget: string;
|
|
51
|
+
lastReplyTarget: string;
|
|
52
|
+
manualResumeReady: boolean;
|
|
53
|
+
sessionAnnounced: boolean;
|
|
54
|
+
currentTurn: {
|
|
55
|
+
emittedAssistantMessage: boolean;
|
|
56
|
+
fullText: string;
|
|
57
|
+
interrupted: boolean;
|
|
58
|
+
items: never[];
|
|
59
|
+
terminalWorkingStatusEmitted: boolean;
|
|
60
|
+
turnEndReason: null;
|
|
61
|
+
usage: null;
|
|
62
|
+
} | null;
|
|
63
|
+
harness: any;
|
|
64
|
+
lastUsage: any;
|
|
65
|
+
currentTurnStatus: any;
|
|
66
|
+
currentTurnActivityAt: number;
|
|
67
|
+
now: any;
|
|
68
|
+
turnDeadlineMs: any;
|
|
69
|
+
sdkModulePromise: Promise<any> | Promise<typeof import("@deepseek-ai/dsh-sdk-client")> | null;
|
|
70
|
+
env: any;
|
|
71
|
+
writeLog(message: any): void;
|
|
72
|
+
trace(message: any): void;
|
|
73
|
+
getSnapshot(): {
|
|
74
|
+
backend: string;
|
|
75
|
+
provider: string;
|
|
76
|
+
cwd: any;
|
|
77
|
+
sessionId: string;
|
|
78
|
+
sessionInfo: {
|
|
79
|
+
backend: string;
|
|
80
|
+
sessionId: string;
|
|
81
|
+
model: any;
|
|
82
|
+
modelProvider: any;
|
|
83
|
+
} | null;
|
|
84
|
+
useSessionFileReplyStream: boolean;
|
|
85
|
+
resumeReady: boolean;
|
|
86
|
+
manualResume: null;
|
|
87
|
+
currentTurnStatus: any;
|
|
88
|
+
capabilities: {
|
|
89
|
+
goal: false;
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
getSessionInfo(): {
|
|
93
|
+
backend: string;
|
|
94
|
+
sessionId: string;
|
|
95
|
+
model: any;
|
|
96
|
+
modelProvider: any;
|
|
97
|
+
} | null;
|
|
98
|
+
getCurrentTurnStatus(): any;
|
|
99
|
+
ensureSessionInfo(): Promise<{
|
|
100
|
+
backend: string;
|
|
101
|
+
sessionId: string;
|
|
102
|
+
model: any;
|
|
103
|
+
modelProvider: any;
|
|
104
|
+
} | null>;
|
|
105
|
+
getSessionUsageSummary(): Promise<{
|
|
106
|
+
sessionId: string;
|
|
107
|
+
sessionFilePath: undefined;
|
|
108
|
+
totalCostUsd: undefined;
|
|
109
|
+
usage: any;
|
|
110
|
+
modelUsage: null;
|
|
111
|
+
rateLimits: null;
|
|
112
|
+
manualResume: null;
|
|
113
|
+
}>;
|
|
114
|
+
usesSessionFileReplyStream(): boolean;
|
|
115
|
+
setSessionMessageHandler(handler: any): void;
|
|
116
|
+
setWorkingStatusHandler(handler: any): void;
|
|
117
|
+
setSessionReplyTarget(replyTo: any): void;
|
|
118
|
+
getCurrentReplyTarget(): string | undefined;
|
|
119
|
+
touchTurnActivity(): void;
|
|
120
|
+
updateCurrentTurnStatus(payload: any): void;
|
|
121
|
+
emitWorkingStatus(payload: any, onProgress?: null): Promise<void>;
|
|
122
|
+
emitAssistantMessage(text: any): Promise<void>;
|
|
123
|
+
emitTerminalWorkingStatus(currentTurn: any, payload: any, onProgress?: null): Promise<void>;
|
|
124
|
+
announceSession(): void;
|
|
125
|
+
/**
|
|
126
|
+
* Mint a fresh wire session id after the previous one's runtime was torn
|
|
127
|
+
* down (interrupt/timeout). The persisted log of the old id would collide
|
|
128
|
+
* on the next create, so the conversation continues on a new id seeded
|
|
129
|
+
* with the in-memory history; the new id is re-announced on success.
|
|
130
|
+
*/
|
|
131
|
+
rotateSessionId(): void;
|
|
132
|
+
findPersistedSessionLog(sessionId: any): string | null;
|
|
133
|
+
/**
|
|
134
|
+
* Recover the user/assistant conversation from a persisted dsh JSONL log
|
|
135
|
+
* so a cross-process resume can seed it into the fresh wire session.
|
|
136
|
+
*/
|
|
137
|
+
loadPersistedHistory(sessionId: any): {
|
|
138
|
+
role: string;
|
|
139
|
+
content: string;
|
|
140
|
+
}[];
|
|
141
|
+
createSessionClosedError(): Error;
|
|
142
|
+
createTurnTimeoutError(timeoutMs: any): Error;
|
|
143
|
+
createCloseGuard(onClose: any): {
|
|
144
|
+
promise: Promise<any>;
|
|
145
|
+
cleanup: () => void;
|
|
146
|
+
};
|
|
147
|
+
createTurnTimeoutGuard(onTimeout: any): {
|
|
148
|
+
promise: Promise<any>;
|
|
149
|
+
cleanup: () => void;
|
|
150
|
+
};
|
|
151
|
+
flushCloseWaiters(): void;
|
|
152
|
+
buildPrompt(promptText: any, { useInitialImages }?: {
|
|
153
|
+
useInitialImages?: boolean | undefined;
|
|
154
|
+
}): string;
|
|
155
|
+
resolveLaunchSpec(): {
|
|
156
|
+
command: any;
|
|
157
|
+
args: any;
|
|
158
|
+
};
|
|
159
|
+
buildRuntimeEnv(): any;
|
|
160
|
+
getSdkModule(): Promise<any>;
|
|
161
|
+
getHarness(): Promise<any>;
|
|
162
|
+
disposeHarness(): Promise<void>;
|
|
163
|
+
maybeEmitAuthRequired(message: any): void;
|
|
164
|
+
handleNotification(notification: any, currentTurn: any, { onProgress }: {
|
|
165
|
+
onProgress: any;
|
|
166
|
+
}): Promise<void>;
|
|
167
|
+
interruptCurrentTurn(): Promise<boolean>;
|
|
168
|
+
runTurn(promptText: any, { useInitialImages, onProgress }?: {
|
|
169
|
+
useInitialImages?: boolean | undefined;
|
|
170
|
+
onProgress?: null | undefined;
|
|
171
|
+
}): Promise<{
|
|
172
|
+
text: string;
|
|
173
|
+
usage: null;
|
|
174
|
+
items: never[];
|
|
175
|
+
events: never[];
|
|
176
|
+
provider?: undefined;
|
|
177
|
+
metadata?: undefined;
|
|
178
|
+
} | {
|
|
179
|
+
text: any;
|
|
180
|
+
usage: any;
|
|
181
|
+
items: never[];
|
|
182
|
+
events: never[];
|
|
183
|
+
provider: string;
|
|
184
|
+
metadata: {
|
|
185
|
+
source: string;
|
|
186
|
+
sessionId: string;
|
|
187
|
+
model: any;
|
|
188
|
+
modelProvider: any;
|
|
189
|
+
turnEndReason: undefined;
|
|
190
|
+
};
|
|
191
|
+
}>;
|
|
192
|
+
close(): Promise<void>;
|
|
193
|
+
}
|
|
194
|
+
import { EventEmitter } from "node:events";
|