@love-moon/ai-sdk 0.13.1 → 0.13.3
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 +48 -0
- package/dist/client.d.ts +5 -0
- package/dist/client.js +24 -0
- package/dist/providers/claude-agent-sdk-session.d.ts +25 -1
- package/dist/providers/claude-agent-sdk-session.js +96 -7
- package/dist/providers/codex-app-server-session.d.ts +44 -0
- package/dist/providers/codex-app-server-session.js +199 -17
- package/dist/providers/copilot-sdk-session.d.ts +29 -1
- package/dist/providers/copilot-sdk-session.js +111 -16
- package/dist/providers/dsh-sdk-session.d.ts +20 -1
- package/dist/providers/dsh-sdk-session.js +75 -8
- package/dist/providers/kimi-cli-session.d.ts +18 -1
- package/dist/providers/kimi-cli-session.js +36 -5
- package/dist/providers/kimi-print-session.d.ts +16 -1
- package/dist/providers/kimi-print-session.js +45 -4
- package/dist/providers/opencode-sdk-session.d.ts +44 -2
- package/dist/providers/opencode-sdk-session.js +169 -24
- package/dist/shared.d.ts +66 -0
- package/dist/shared.js +25 -1
- package/dist/worker.js +1 -1
- package/package.json +3 -3
|
@@ -11,6 +11,12 @@ const require = createRequire(import.meta.url);
|
|
|
11
11
|
const DEFAULT_TURN_DEADLINE_MS = 12 * 60 * 1000;
|
|
12
12
|
const MIN_TURN_DEADLINE_MS = 30 * 1000;
|
|
13
13
|
const MAX_TURN_DEADLINE_MS = 30 * 60 * 1000;
|
|
14
|
+
export const COMPACT_SUMMARY_PROMPT = [
|
|
15
|
+
"Summarize our conversation so far so it can replace the full history.",
|
|
16
|
+
"Keep the goals, decisions, current state of the work, relevant files and commands, and open next steps.",
|
|
17
|
+
"Do not use tools. Reply with the summary only.",
|
|
18
|
+
].join(" ");
|
|
19
|
+
const COMPACT_SUMMARY_PREFIX = "Summary of the conversation so far:\n\n";
|
|
14
20
|
// Pinned defaults for the dsh runtime route. `deepseek-official` is the
|
|
15
21
|
// provider route the stock `@deepseek-ai/dsh-llm-deepseek` adapter registers;
|
|
16
22
|
// the model can be overridden via options.model or an allow_cli_list command
|
|
@@ -126,7 +132,7 @@ function accumulateUsage(total, usage) {
|
|
|
126
132
|
* the next runTurn spawns a fresh runtime resuming the same session id.
|
|
127
133
|
*/
|
|
128
134
|
export class DshSdkSession extends EventEmitter {
|
|
129
|
-
static capabilities = Object.freeze({ goal: false });
|
|
135
|
+
static capabilities = Object.freeze({ goal: false, compact: true });
|
|
130
136
|
getCapabilities() {
|
|
131
137
|
return { ...DshSdkSession.capabilities };
|
|
132
138
|
}
|
|
@@ -376,6 +382,7 @@ export class DshSdkSession extends EventEmitter {
|
|
|
376
382
|
return [];
|
|
377
383
|
}
|
|
378
384
|
const restored = [];
|
|
385
|
+
let compactSummaryPending = false;
|
|
379
386
|
let content;
|
|
380
387
|
try {
|
|
381
388
|
content = fs.readFileSync(logPath, "utf8");
|
|
@@ -397,14 +404,26 @@ export class DshSdkSession extends EventEmitter {
|
|
|
397
404
|
}
|
|
398
405
|
if (event?.type === "user/message" && event.data?.source?.kind === "user") {
|
|
399
406
|
const text = extractTextBlocks(event.data?.content);
|
|
400
|
-
|
|
407
|
+
// A `/compact` summary turn supersedes everything before it, but only
|
|
408
|
+
// once its reply lands; a failed or interrupted one changes nothing.
|
|
409
|
+
compactSummaryPending = text.includes(COMPACT_SUMMARY_PROMPT);
|
|
410
|
+
if (text && !compactSummaryPending) {
|
|
401
411
|
restored.push({ role: "user", content: text });
|
|
402
412
|
}
|
|
403
413
|
continue;
|
|
404
414
|
}
|
|
415
|
+
if (event?.type === "turn/end" && event.data?.reason?.kind !== "completed") {
|
|
416
|
+
compactSummaryPending = false;
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
405
419
|
if (event?.type === "assistant/message") {
|
|
406
420
|
const text = extractTextBlocks(event.data?.message?.content);
|
|
407
|
-
if (text) {
|
|
421
|
+
if (text && compactSummaryPending) {
|
|
422
|
+
restored.length = 0;
|
|
423
|
+
restored.push({ role: "assistant", content: `${COMPACT_SUMMARY_PREFIX}${text}` });
|
|
424
|
+
compactSummaryPending = false;
|
|
425
|
+
}
|
|
426
|
+
else if (text) {
|
|
408
427
|
restored.push({ role: "assistant", content: text });
|
|
409
428
|
}
|
|
410
429
|
}
|
|
@@ -701,8 +720,11 @@ export class DshSdkSession extends EventEmitter {
|
|
|
701
720
|
if (!text) {
|
|
702
721
|
return;
|
|
703
722
|
}
|
|
704
|
-
currentTurn.emittedAssistantMessage = true;
|
|
705
723
|
currentTurn.fullText = text;
|
|
724
|
+
if (currentTurn.suppressReply) {
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
currentTurn.emittedAssistantMessage = true;
|
|
706
728
|
await this.emitWorkingStatus({
|
|
707
729
|
phase: "message_aggregation",
|
|
708
730
|
reply_in_progress: true,
|
|
@@ -745,6 +767,15 @@ export class DshSdkSession extends EventEmitter {
|
|
|
745
767
|
}, onProgress);
|
|
746
768
|
return;
|
|
747
769
|
}
|
|
770
|
+
case "compaction/end": {
|
|
771
|
+
// Automatic compaction finished mid-turn; drop the "compacting" line.
|
|
772
|
+
await this.emitWorkingStatus({
|
|
773
|
+
phase: "turn_started",
|
|
774
|
+
reply_in_progress: true,
|
|
775
|
+
status_line: "dsh is working",
|
|
776
|
+
}, onProgress);
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
748
779
|
case "turn/end": {
|
|
749
780
|
currentTurn.turnEndReason = event.data?.reason || null;
|
|
750
781
|
return;
|
|
@@ -766,7 +797,40 @@ export class DshSdkSession extends EventEmitter {
|
|
|
766
797
|
await this.disposeHarness();
|
|
767
798
|
return true;
|
|
768
799
|
}
|
|
769
|
-
|
|
800
|
+
/**
|
|
801
|
+
* Manually compact the conversation. The dsh SDK wire exposes no compaction
|
|
802
|
+
* request (its engine's `compactNow` is internal), so the model summarizes
|
|
803
|
+
* the conversation in one silent turn and the chat continues on a fresh
|
|
804
|
+
* wire session seeded with only that summary.
|
|
805
|
+
*
|
|
806
|
+
* @param {import("../shared.js").CompactRequest} [request]
|
|
807
|
+
* @param {{ onProgress?: Function }} [options]
|
|
808
|
+
* @returns {Promise<import("../shared.js").CompactResult>}
|
|
809
|
+
*/
|
|
810
|
+
async runCompact(request = {}, { onProgress = null } = {}) {
|
|
811
|
+
const instructions = typeof request?.instructions === "string" ? request.instructions.trim() : "";
|
|
812
|
+
const resumableLog = this.pendingResumeFromSessionId && this.findPersistedSessionLog(this.pendingResumeFromSessionId);
|
|
813
|
+
if (this.history.length === 0 && !resumableLog) {
|
|
814
|
+
return { compact: { status: "noop", instructionsApplied: false }, usage: null, metadata: {} };
|
|
815
|
+
}
|
|
816
|
+
const prompt = instructions ? `${COMPACT_SUMMARY_PROMPT}\n\nAdditional focus: ${instructions}` : COMPACT_SUMMARY_PROMPT;
|
|
817
|
+
const turnResult = await this.runTurn(prompt, { onProgress, suppressReply: true });
|
|
818
|
+
const summary = String(turnResult.text || "").trim();
|
|
819
|
+
if (!summary) {
|
|
820
|
+
throw createTurnError("dsh compaction produced an empty summary", { reason: "compact_failed" });
|
|
821
|
+
}
|
|
822
|
+
this.history = [{ role: "assistant", content: `${COMPACT_SUMMARY_PREFIX}${summary}` }];
|
|
823
|
+
// Dropping the runtime makes the next turn rotate onto a fresh id seeded
|
|
824
|
+
// with the summary. Rotating here instead would expose the new id for
|
|
825
|
+
// binding before it has a persisted log, so a restart would resume empty.
|
|
826
|
+
await this.disposeHarness();
|
|
827
|
+
return {
|
|
828
|
+
compact: { status: "compacted", instructionsApplied: Boolean(instructions) },
|
|
829
|
+
usage: turnResult.usage,
|
|
830
|
+
metadata: { source: DSH_SDK_VARIANT, sessionId: this.sessionId },
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
async runTurn(promptText, { useInitialImages = false, onProgress = null, suppressReply = false } = {}) {
|
|
770
834
|
if (this.closeRequested) {
|
|
771
835
|
throw this.createSessionClosedError();
|
|
772
836
|
}
|
|
@@ -798,8 +862,11 @@ export class DshSdkSession extends EventEmitter {
|
|
|
798
862
|
this.rotateSessionId();
|
|
799
863
|
}
|
|
800
864
|
const effectivePrompt = this.buildPrompt(promptText, { useInitialImages });
|
|
801
|
-
|
|
865
|
+
if (!suppressReply) {
|
|
866
|
+
this.history.push({ role: "user", content: promptText });
|
|
867
|
+
}
|
|
802
868
|
const currentTurn = {
|
|
869
|
+
suppressReply,
|
|
803
870
|
emittedAssistantMessage: false,
|
|
804
871
|
fullText: "",
|
|
805
872
|
interrupted: false,
|
|
@@ -861,10 +928,10 @@ export class DshSdkSession extends EventEmitter {
|
|
|
861
928
|
const responseText = typeof runResult?.finalResponse === "string" && runResult.finalResponse
|
|
862
929
|
? runResult.finalResponse
|
|
863
930
|
: currentTurn.fullText;
|
|
864
|
-
if (!currentTurn.emittedAssistantMessage && responseText) {
|
|
931
|
+
if (!suppressReply && !currentTurn.emittedAssistantMessage && responseText) {
|
|
865
932
|
await this.emitAssistantMessage(responseText);
|
|
866
933
|
}
|
|
867
|
-
if (responseText) {
|
|
934
|
+
if (!suppressReply && responseText) {
|
|
868
935
|
this.history.push({ role: "assistant", content: responseText });
|
|
869
936
|
}
|
|
870
937
|
const turnEndKind = currentTurn.turnEndReason?.kind;
|
|
@@ -20,6 +20,8 @@ export class KimiCliSession extends EventEmitter<[never]> {
|
|
|
20
20
|
activeReplyTarget: string;
|
|
21
21
|
lastReplyTarget: string;
|
|
22
22
|
currentTurn: {
|
|
23
|
+
suppressReply: boolean;
|
|
24
|
+
compacted: boolean;
|
|
23
25
|
fullText: string;
|
|
24
26
|
bufferedAssistantText: string;
|
|
25
27
|
thinkText: string;
|
|
@@ -84,6 +86,7 @@ export class KimiCliSession extends EventEmitter<[never]> {
|
|
|
84
86
|
} | null;
|
|
85
87
|
currentTurnStatus: any;
|
|
86
88
|
capabilities: {
|
|
89
|
+
compact: boolean;
|
|
87
90
|
media: Readonly<{
|
|
88
91
|
image: "native";
|
|
89
92
|
}>;
|
|
@@ -154,10 +157,23 @@ export class KimiCliSession extends EventEmitter<[never]> {
|
|
|
154
157
|
handleTransportFailure(error: any): void;
|
|
155
158
|
handleTransportExit(payload: any): void;
|
|
156
159
|
interruptCurrentTurn(): Promise<boolean>;
|
|
157
|
-
|
|
160
|
+
/**
|
|
161
|
+
* Manually compact via Kimi CLI's built-in `/compact` slash command, which
|
|
162
|
+
* the wire `prompt` method dispatches like the interactive shell does. The
|
|
163
|
+
* command takes no focus instructions.
|
|
164
|
+
*
|
|
165
|
+
* @param {import("../shared.js").CompactRequest} [request]
|
|
166
|
+
* @param {{ onProgress?: Function }} [options]
|
|
167
|
+
* @returns {Promise<import("../shared.js").CompactResult>}
|
|
168
|
+
*/
|
|
169
|
+
runCompact(request?: import("../shared.js").CompactRequest, { onProgress }?: {
|
|
170
|
+
onProgress?: Function;
|
|
171
|
+
}): Promise<import("../shared.js").CompactResult>;
|
|
172
|
+
runTurn(promptText: any, { useInitialImages, media: mediaInput, contextFiles, onProgress, jsonSchema, suppressReply }?: {
|
|
158
173
|
useInitialImages?: boolean | undefined;
|
|
159
174
|
onProgress?: null | undefined;
|
|
160
175
|
jsonSchema?: null | undefined;
|
|
176
|
+
suppressReply?: boolean | undefined;
|
|
161
177
|
}): Promise<{
|
|
162
178
|
text: string;
|
|
163
179
|
usage: null;
|
|
@@ -175,6 +191,7 @@ export class KimiCliSession extends EventEmitter<[never]> {
|
|
|
175
191
|
promptStatus: string | undefined;
|
|
176
192
|
contextUsagePercent: number | undefined;
|
|
177
193
|
};
|
|
194
|
+
compacted: boolean;
|
|
178
195
|
}>;
|
|
179
196
|
close(): Promise<void>;
|
|
180
197
|
}
|
|
@@ -233,7 +233,7 @@ export class KimiCliSession extends EventEmitter {
|
|
|
233
233
|
}
|
|
234
234
|
: null,
|
|
235
235
|
currentTurnStatus: this.getCurrentTurnStatus(),
|
|
236
|
-
capabilities: { media: PROVIDER_MEDIA_CAPABILITIES[KIMI_PROVIDER_VARIANT] },
|
|
236
|
+
capabilities: { compact: true, media: PROVIDER_MEDIA_CAPABILITIES[KIMI_PROVIDER_VARIANT] },
|
|
237
237
|
pid: this.transport.pid || undefined,
|
|
238
238
|
};
|
|
239
239
|
}
|
|
@@ -642,6 +642,9 @@ export class KimiCliSession extends EventEmitter {
|
|
|
642
642
|
}
|
|
643
643
|
currentTurn.fullText += text;
|
|
644
644
|
currentTurn.bufferedAssistantText = "";
|
|
645
|
+
if (currentTurn.suppressReply) {
|
|
646
|
+
return false;
|
|
647
|
+
}
|
|
645
648
|
await this.emitAssistantMessage(text);
|
|
646
649
|
return true;
|
|
647
650
|
}
|
|
@@ -760,6 +763,7 @@ export class KimiCliSession extends EventEmitter {
|
|
|
760
763
|
}, currentTurn.onProgress);
|
|
761
764
|
return;
|
|
762
765
|
case "CompactionBegin":
|
|
766
|
+
currentTurn.compacted = true;
|
|
763
767
|
await this.emitWorkingStatus({
|
|
764
768
|
phase: "context_compaction",
|
|
765
769
|
reply_in_progress: true,
|
|
@@ -792,7 +796,9 @@ export class KimiCliSession extends EventEmitter {
|
|
|
792
796
|
phase: "message_aggregation",
|
|
793
797
|
reply_in_progress: true,
|
|
794
798
|
status_line: statusLineForPhase("message_aggregation"),
|
|
795
|
-
reply_preview:
|
|
799
|
+
reply_preview: currentTurn.suppressReply
|
|
800
|
+
? undefined
|
|
801
|
+
: sanitizeSummary(currentTurn.bufferedAssistantText, 120),
|
|
796
802
|
}, currentTurn.onProgress);
|
|
797
803
|
}
|
|
798
804
|
return;
|
|
@@ -879,7 +885,27 @@ export class KimiCliSession extends EventEmitter {
|
|
|
879
885
|
}
|
|
880
886
|
return false;
|
|
881
887
|
}
|
|
882
|
-
|
|
888
|
+
/**
|
|
889
|
+
* Manually compact via Kimi CLI's built-in `/compact` slash command, which
|
|
890
|
+
* the wire `prompt` method dispatches like the interactive shell does. The
|
|
891
|
+
* command takes no focus instructions.
|
|
892
|
+
*
|
|
893
|
+
* @param {import("../shared.js").CompactRequest} [request]
|
|
894
|
+
* @param {{ onProgress?: Function }} [options]
|
|
895
|
+
* @returns {Promise<import("../shared.js").CompactResult>}
|
|
896
|
+
*/
|
|
897
|
+
async runCompact(request = {}, { onProgress = null } = {}) {
|
|
898
|
+
if (this.pendingHistorySeed) {
|
|
899
|
+
return { compact: { status: "noop", instructionsApplied: false }, usage: null, metadata: {} };
|
|
900
|
+
}
|
|
901
|
+
const turnResult = await this.runTurn("/compact", { onProgress, suppressReply: true });
|
|
902
|
+
return {
|
|
903
|
+
compact: { status: turnResult.compacted ? "compacted" : "noop", instructionsApplied: false },
|
|
904
|
+
usage: turnResult.usage,
|
|
905
|
+
metadata: turnResult.metadata,
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
async runTurn(promptText, { useInitialImages = false, media: mediaInput, contextFiles, onProgress = null, jsonSchema = null, suppressReply = false } = {}) {
|
|
883
909
|
if (this.closeRequested || this.closed) {
|
|
884
910
|
throw this.createSessionClosedError();
|
|
885
911
|
}
|
|
@@ -907,8 +933,12 @@ export class KimiCliSession extends EventEmitter {
|
|
|
907
933
|
await this.failPendingTurnStart(error, onProgress);
|
|
908
934
|
throw error;
|
|
909
935
|
}
|
|
910
|
-
|
|
936
|
+
if (!suppressReply) {
|
|
937
|
+
this.history.push({ role: "user", content: promptText });
|
|
938
|
+
}
|
|
911
939
|
const currentTurn = {
|
|
940
|
+
suppressReply,
|
|
941
|
+
compacted: false,
|
|
912
942
|
fullText: "",
|
|
913
943
|
bufferedAssistantText: "",
|
|
914
944
|
thinkText: "",
|
|
@@ -950,7 +980,7 @@ export class KimiCliSession extends EventEmitter {
|
|
|
950
980
|
]);
|
|
951
981
|
currentTurn.settled = true;
|
|
952
982
|
await this.finalizeAssistantMessage(currentTurn);
|
|
953
|
-
if (currentTurn.fullText) {
|
|
983
|
+
if (currentTurn.fullText && !suppressReply) {
|
|
954
984
|
this.history.push({ role: "assistant", content: currentTurn.fullText });
|
|
955
985
|
}
|
|
956
986
|
const normalizedStatus = normalizeText(promptResult?.status);
|
|
@@ -979,6 +1009,7 @@ export class KimiCliSession extends EventEmitter {
|
|
|
979
1009
|
promptStatus: normalizedStatus || undefined,
|
|
980
1010
|
contextUsagePercent: this.lastContextUsagePercent,
|
|
981
1011
|
},
|
|
1012
|
+
compacted: currentTurn.compacted,
|
|
982
1013
|
};
|
|
983
1014
|
}
|
|
984
1015
|
catch (error) {
|
|
@@ -61,6 +61,7 @@ export class KimiPrintSession extends EventEmitter<[never]> {
|
|
|
61
61
|
} | null;
|
|
62
62
|
currentTurnStatus: any;
|
|
63
63
|
capabilities: {
|
|
64
|
+
compact: boolean;
|
|
64
65
|
media: Readonly<{
|
|
65
66
|
image: "unsupported";
|
|
66
67
|
}> | Readonly<{
|
|
@@ -115,10 +116,24 @@ export class KimiPrintSession extends EventEmitter<[never]> {
|
|
|
115
116
|
};
|
|
116
117
|
maybeEmitAuthRequired(stderrTail: any): void;
|
|
117
118
|
interruptCurrentTurn(): Promise<boolean>;
|
|
118
|
-
|
|
119
|
+
/**
|
|
120
|
+
* Manually compact via kimi-cli's built-in `/compact` slash command; print
|
|
121
|
+
* mode runs it through the same soul as the interactive shell. Print output
|
|
122
|
+
* carries no compaction events, so the outcome is read from the CLI's fixed
|
|
123
|
+
* replies. The command takes no focus instructions.
|
|
124
|
+
*
|
|
125
|
+
* @param {import("../shared.js").CompactRequest} [request]
|
|
126
|
+
* @param {{ onProgress?: Function }} [options]
|
|
127
|
+
* @returns {Promise<import("../shared.js").CompactResult>}
|
|
128
|
+
*/
|
|
129
|
+
runCompact(request?: import("../shared.js").CompactRequest, { onProgress }?: {
|
|
130
|
+
onProgress?: Function;
|
|
131
|
+
}): Promise<import("../shared.js").CompactResult>;
|
|
132
|
+
runTurn(promptText: any, { useInitialImages, media: mediaInput, contextFiles, onProgress, jsonSchema, suppressReply }?: {
|
|
119
133
|
useInitialImages?: boolean | undefined;
|
|
120
134
|
onProgress?: null | undefined;
|
|
121
135
|
jsonSchema?: null | undefined;
|
|
136
|
+
suppressReply?: boolean | undefined;
|
|
122
137
|
}): Promise<{
|
|
123
138
|
text: string;
|
|
124
139
|
usage: null;
|
|
@@ -270,6 +270,8 @@ export class KimiPrintSession extends EventEmitter {
|
|
|
270
270
|
: null,
|
|
271
271
|
currentTurnStatus: this.getCurrentTurnStatus(),
|
|
272
272
|
capabilities: {
|
|
273
|
+
// Kimi Code's `--prompt` CLI is unverified for slash commands.
|
|
274
|
+
compact: this.cliMode !== "prompt",
|
|
273
275
|
media: this.cliMode === "prompt"
|
|
274
276
|
? UNSUPPORTED_MEDIA_CAPABILITIES
|
|
275
277
|
: PROVIDER_MEDIA_CAPABILITIES[KIMI_PRINT_PROVIDER_VARIANT],
|
|
@@ -468,7 +470,42 @@ export class KimiPrintSession extends EventEmitter {
|
|
|
468
470
|
return false;
|
|
469
471
|
}
|
|
470
472
|
}
|
|
471
|
-
|
|
473
|
+
/**
|
|
474
|
+
* Manually compact via kimi-cli's built-in `/compact` slash command; print
|
|
475
|
+
* mode runs it through the same soul as the interactive shell. Print output
|
|
476
|
+
* carries no compaction events, so the outcome is read from the CLI's fixed
|
|
477
|
+
* replies. The command takes no focus instructions.
|
|
478
|
+
*
|
|
479
|
+
* @param {import("../shared.js").CompactRequest} [request]
|
|
480
|
+
* @param {{ onProgress?: Function }} [options]
|
|
481
|
+
* @returns {Promise<import("../shared.js").CompactResult>}
|
|
482
|
+
*/
|
|
483
|
+
async runCompact(request = {}, { onProgress = null } = {}) {
|
|
484
|
+
if (this.cliMode === "prompt") {
|
|
485
|
+
throw createTurnError("Kimi prompt mode does not support /compact", { reason: "unsupported_compact" });
|
|
486
|
+
}
|
|
487
|
+
if (this.pendingHistorySeed) {
|
|
488
|
+
return { compact: { status: "noop", instructionsApplied: false }, usage: null, metadata: {} };
|
|
489
|
+
}
|
|
490
|
+
const turnResult = await this.runTurn("/compact", { onProgress, suppressReply: true });
|
|
491
|
+
const reply = String(turnResult.text || "");
|
|
492
|
+
// Print mode exits 0 even when the model call fails, so only kimi-cli's
|
|
493
|
+
// fixed replies are trusted.
|
|
494
|
+
if (!/context has been compacted|context is empty/i.test(reply)) {
|
|
495
|
+
throw createTurnError(`Kimi compaction failed${reply.trim() ? `: ${reply.trim()}` : ""}`, {
|
|
496
|
+
reason: "compact_failed",
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
return {
|
|
500
|
+
compact: {
|
|
501
|
+
status: /context is empty/i.test(reply) ? "noop" : "compacted",
|
|
502
|
+
instructionsApplied: false,
|
|
503
|
+
},
|
|
504
|
+
usage: turnResult.usage,
|
|
505
|
+
metadata: turnResult.metadata,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
async runTurn(promptText, { useInitialImages = false, media: mediaInput, contextFiles, onProgress = null, jsonSchema = null, suppressReply = false } = {}) {
|
|
472
509
|
if (this.closeRequested || this.closed) {
|
|
473
510
|
throw this.createSessionClosedError();
|
|
474
511
|
}
|
|
@@ -497,7 +534,9 @@ export class KimiPrintSession extends EventEmitter {
|
|
|
497
534
|
return buildEmptyTurnResult();
|
|
498
535
|
}
|
|
499
536
|
this.announceSession();
|
|
500
|
-
|
|
537
|
+
if (!suppressReply) {
|
|
538
|
+
this.history.push({ role: "user", content: String(promptText || "") });
|
|
539
|
+
}
|
|
501
540
|
const currentTurn = {
|
|
502
541
|
child: null,
|
|
503
542
|
fullText: "",
|
|
@@ -624,7 +663,9 @@ export class KimiPrintSession extends EventEmitter {
|
|
|
624
663
|
}
|
|
625
664
|
if (assistantText) {
|
|
626
665
|
currentTurn.fullText += assistantText;
|
|
627
|
-
|
|
666
|
+
if (!suppressReply) {
|
|
667
|
+
void this.emitAssistantMessage(assistantText);
|
|
668
|
+
}
|
|
628
669
|
}
|
|
629
670
|
return;
|
|
630
671
|
}
|
|
@@ -688,7 +729,7 @@ export class KimiPrintSession extends EventEmitter {
|
|
|
688
729
|
}
|
|
689
730
|
child.stdin.end();
|
|
690
731
|
});
|
|
691
|
-
if (result?.text) {
|
|
732
|
+
if (result?.text && !suppressReply) {
|
|
692
733
|
this.history.push({ role: "assistant", content: result.text });
|
|
693
734
|
}
|
|
694
735
|
this.activeReplyTarget = "";
|
|
@@ -20,7 +20,7 @@ export class OpencodeSdkSession extends EventEmitter<[never]> {
|
|
|
20
20
|
activeReplyTarget: string;
|
|
21
21
|
lastReplyTarget: string;
|
|
22
22
|
currentTurn: {
|
|
23
|
-
abortController:
|
|
23
|
+
abortController: any;
|
|
24
24
|
assistantMessages: Map<any, any>;
|
|
25
25
|
assistantMessageOrder: never[];
|
|
26
26
|
activeAssistantMessageId: string;
|
|
@@ -29,7 +29,7 @@ export class OpencodeSdkSession extends EventEmitter<[never]> {
|
|
|
29
29
|
fullText: string;
|
|
30
30
|
items: never[];
|
|
31
31
|
lastAssistantInfo: null;
|
|
32
|
-
onProgress:
|
|
32
|
+
onProgress: any;
|
|
33
33
|
resolve: null;
|
|
34
34
|
reject: null;
|
|
35
35
|
settled: boolean;
|
|
@@ -79,6 +79,7 @@ export class OpencodeSdkSession extends EventEmitter<[never]> {
|
|
|
79
79
|
manualResume: null;
|
|
80
80
|
currentTurnStatus: any;
|
|
81
81
|
capabilities: {
|
|
82
|
+
compact: boolean;
|
|
82
83
|
media: Readonly<{
|
|
83
84
|
image: "native";
|
|
84
85
|
}>;
|
|
@@ -169,6 +170,47 @@ export class OpencodeSdkSession extends EventEmitter<[never]> {
|
|
|
169
170
|
handleTransportFailure(error: any): void;
|
|
170
171
|
handleTransportExit(payload: any): void;
|
|
171
172
|
interruptCurrentTurn(): Promise<boolean>;
|
|
173
|
+
createTurnState(abortController: any, onProgress: any): {
|
|
174
|
+
currentTurn: {
|
|
175
|
+
abortController: any;
|
|
176
|
+
assistantMessages: Map<any, any>;
|
|
177
|
+
assistantMessageOrder: never[];
|
|
178
|
+
activeAssistantMessageId: string;
|
|
179
|
+
messageRoles: Map<any, any>;
|
|
180
|
+
pendingMessageEvents: Map<any, any>;
|
|
181
|
+
fullText: string;
|
|
182
|
+
items: never[];
|
|
183
|
+
lastAssistantInfo: null;
|
|
184
|
+
onProgress: any;
|
|
185
|
+
resolve: null;
|
|
186
|
+
reject: null;
|
|
187
|
+
settled: boolean;
|
|
188
|
+
terminalWorkingStatusEmitted: boolean;
|
|
189
|
+
};
|
|
190
|
+
completionPromise: Promise<any>;
|
|
191
|
+
};
|
|
192
|
+
/**
|
|
193
|
+
* Model to summarize with: `session.summarize` requires one explicitly.
|
|
194
|
+
* Prefer what the session actually ran on (last turn, then its recent
|
|
195
|
+
* messages); the configured model is only a fallback.
|
|
196
|
+
*/
|
|
197
|
+
resolveCompactionModel(): Promise<{
|
|
198
|
+
providerID: any;
|
|
199
|
+
modelID: any;
|
|
200
|
+
}>;
|
|
201
|
+
/**
|
|
202
|
+
* Manually compact via the server's `session.summarize` (what the TUI's
|
|
203
|
+
* `/compact` calls). It takes no focus instructions and answers `true`
|
|
204
|
+
* even when summarizing fails, so success is judged from the summary
|
|
205
|
+
* message itself.
|
|
206
|
+
*
|
|
207
|
+
* @param {import("../shared.js").CompactRequest} [request]
|
|
208
|
+
* @param {{ onProgress?: Function }} [options]
|
|
209
|
+
* @returns {Promise<import("../shared.js").CompactResult>}
|
|
210
|
+
*/
|
|
211
|
+
runCompact(request?: import("../shared.js").CompactRequest, { onProgress }?: {
|
|
212
|
+
onProgress?: Function;
|
|
213
|
+
}): Promise<import("../shared.js").CompactResult>;
|
|
172
214
|
runTurn(promptText: any, { useInitialImages, media: mediaInput, contextFiles, onProgress, jsonSchema }?: {
|
|
173
215
|
useInitialImages?: boolean | undefined;
|
|
174
216
|
onProgress?: null | undefined;
|