@qwen-code/arena-agent 0.0.10-dev.0 → 0.0.10-dev.10
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/.env.example +57 -14
- package/CHANGELOG.md +228 -0
- package/README.md +240 -57
- package/dist/agent.d.ts +30 -2
- package/dist/agent.js +351 -104
- package/dist/agent.js.map +1 -1
- package/dist/anthropic.js +23 -22
- package/dist/anthropic.js.map +1 -1
- package/dist/ask-user.js +2 -0
- package/dist/ask-user.js.map +1 -1
- package/dist/attachments.js +4 -3
- package/dist/attachments.js.map +1 -1
- package/dist/brave-search.js +1 -3
- package/dist/brave-search.js.map +1 -1
- package/dist/canonical-data.js +2 -2
- package/dist/canonical-data.js.map +1 -1
- package/dist/cli.js +197 -34
- package/dist/cli.js.map +1 -1
- package/dist/code-tools.d.ts +8 -2
- package/dist/code-tools.js +709 -117
- package/dist/code-tools.js.map +1 -1
- package/dist/compaction.d.ts +49 -3
- package/dist/compaction.js +383 -170
- package/dist/compaction.js.map +1 -1
- package/dist/config.d.ts +17 -2
- package/dist/config.js +47 -5
- package/dist/config.js.map +1 -1
- package/dist/fetch-page.js +9 -33
- package/dist/fetch-page.js.map +1 -1
- package/dist/file-edit.d.ts +8 -0
- package/dist/file-edit.js +63 -0
- package/dist/file-edit.js.map +1 -0
- package/dist/history.d.ts +35 -1
- package/dist/history.js +400 -16
- package/dist/history.js.map +1 -1
- package/dist/legacy-compaction.d.ts +20 -0
- package/dist/legacy-compaction.js +209 -0
- package/dist/legacy-compaction.js.map +1 -0
- package/dist/midturn-checkpoint-hook.d.ts +31 -0
- package/dist/midturn-checkpoint-hook.js +38 -0
- package/dist/midturn-checkpoint-hook.js.map +1 -0
- package/dist/mock.js +5 -0
- package/dist/mock.js.map +1 -1
- package/dist/mode.js +4 -2
- package/dist/mode.js.map +1 -1
- package/dist/model-router-media.d.ts +1 -0
- package/dist/model-router-media.js +71 -1
- package/dist/model-router-media.js.map +1 -1
- package/dist/openai-responses.js +2 -0
- package/dist/openai-responses.js.map +1 -1
- package/dist/process-manager.js +18 -11
- package/dist/process-manager.js.map +1 -1
- package/dist/prompts.d.ts +2 -0
- package/dist/prompts.js +6 -2
- package/dist/prompts.js.map +1 -1
- package/dist/protocol.d.ts +5 -1
- package/dist/protocol.js +24 -2
- package/dist/protocol.js.map +1 -1
- package/dist/provider.d.ts +12 -5
- package/dist/provider.js +60 -52
- package/dist/provider.js.map +1 -1
- package/dist/repetitive-output.d.ts +12 -0
- package/dist/repetitive-output.js +80 -0
- package/dist/repetitive-output.js.map +1 -0
- package/dist/replay-responses.d.ts +17 -0
- package/dist/replay-responses.js +100 -0
- package/dist/replay-responses.js.map +1 -0
- package/dist/routify-web-fetch.js +20 -7
- package/dist/routify-web-fetch.js.map +1 -1
- package/dist/sandbox-file-write.d.ts +10 -0
- package/dist/sandbox-file-write.js +58 -0
- package/dist/sandbox-file-write.js.map +1 -0
- package/dist/sdk.js +9 -1
- package/dist/sdk.js.map +1 -1
- package/dist/server.js +127 -44
- package/dist/server.js.map +1 -1
- package/dist/session-memory-prompts.d.ts +5 -0
- package/dist/session-memory-prompts.js +7 -0
- package/dist/session-memory-prompts.js.map +1 -0
- package/dist/snapshot-client.d.ts +10 -0
- package/dist/snapshot-client.js +39 -0
- package/dist/snapshot-client.js.map +1 -0
- package/dist/spec.js +18 -10
- package/dist/spec.js.map +1 -1
- package/dist/speech-audio.d.ts +9 -0
- package/dist/speech-audio.js +130 -0
- package/dist/speech-audio.js.map +1 -0
- package/dist/speech-model.d.ts +3 -0
- package/dist/speech-model.js +8 -0
- package/dist/speech-model.js.map +1 -0
- package/dist/tools.d.ts +5 -0
- package/dist/tools.js +744 -121
- package/dist/tools.js.map +1 -1
- package/dist/tui.js +20 -12
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +28 -3
- package/dist/voice-registry.d.ts +2 -0
- package/dist/voice-registry.js +10 -2
- package/dist/voice-registry.js.map +1 -1
- package/dist/web/app.js +17 -3
- package/dist/web/app.js.map +1 -1
- package/dist/web-fetch-output.d.ts +9 -0
- package/dist/web-fetch-output.js +38 -0
- package/dist/web-fetch-output.js.map +1 -0
- package/dist/workspace.d.ts +2 -0
- package/dist/workspace.js +11 -6
- package/dist/workspace.js.map +1 -1
- package/docs/BINARY_DISTRIBUTION.md +27 -16
- package/docs/MODES_AND_RELEASES.md +28 -5
- package/docs/SDK.md +10 -4
- package/modes/code-arena/capture-provenance.json +57 -0
- package/modes/code-arena/full-stack/system-prompt.txt +1 -1
- package/modes/code-arena/full-stack/template/eslint.config.mjs +3 -4
- package/modes/code-arena/full-stack/template/postcss.config.mjs +2 -2
- package/modes/code-arena/full-stack/tools.json +186 -186
- package/modes/code-arena/html/system-prompt.txt +1 -1
- package/modes/code-arena/html/tools.json +123 -123
- package/modes/code-arena/react/system-prompt.txt +4 -3
- package/modes/code-arena/react/template/package.json +4 -4
- package/modes/code-arena/react/template/src/App.tsx +1 -1
- package/modes/code-arena/react/template/src/main.tsx +1 -1
- package/modes/code-arena/react/template/tsconfig.json +6 -0
- package/modes/code-arena/react/template/vite.config.ts +1 -0
- package/modes/code-arena/react/tools.json +178 -184
- package/package.json +15 -4
- package/scripts/README.md +62 -0
- package/scripts/check-changelog.mjs +66 -0
- package/vendor/audio/darwin-arm64/FFmpeg.LICENSE +502 -0
- package/vendor/audio/darwin-arm64/LAME.LICENSE +481 -0
- package/vendor/audio/darwin-arm64/Opus.LICENSE +44 -0
- package/vendor/audio/darwin-arm64/ffmpeg.gz +0 -0
- package/vendor/audio/darwin-arm64/manifest.json +39 -0
- package/vendor/audio/darwin-x64/FFmpeg.LICENSE +502 -0
- package/vendor/audio/darwin-x64/LAME.LICENSE +481 -0
- package/vendor/audio/darwin-x64/Opus.LICENSE +44 -0
- package/vendor/audio/darwin-x64/ffmpeg.gz +0 -0
- package/vendor/audio/darwin-x64/manifest.json +39 -0
- package/vendor/audio/linux-arm64/FFmpeg.LICENSE +502 -0
- package/vendor/audio/linux-arm64/LAME.LICENSE +481 -0
- package/vendor/audio/linux-arm64/Opus.LICENSE +44 -0
- package/vendor/audio/linux-arm64/ffmpeg.gz +0 -0
- package/vendor/audio/linux-arm64/manifest.json +39 -0
- package/vendor/audio/linux-x64/FFmpeg.LICENSE +502 -0
- package/vendor/audio/linux-x64/LAME.LICENSE +481 -0
- package/vendor/audio/linux-x64/Opus.LICENSE +44 -0
- package/vendor/audio/linux-x64/ffmpeg.gz +0 -0
- package/vendor/audio/linux-x64/manifest.json +39 -0
- package/vendor/audio/sources/build-audio-encoder.sh +76 -0
- package/vendor/audio/sources/ffmpeg-7.0.2.tar.xz +0 -0
- package/vendor/audio/sources/lame-3.100.tar.gz +0 -0
- package/vendor/audio/sources/opus-1.5.2.tar.gz +0 -0
- package/vendor/audio/sources/pkgconf-2.3.0.tar.xz +0 -0
- package/vendor/audio/sources/sources.lock.json +30 -0
- package/vendor/audio/win32-x64/FFmpeg.LICENSE +502 -0
- package/vendor/audio/win32-x64/LAME.LICENSE +481 -0
- package/vendor/audio/win32-x64/Opus.LICENSE +44 -0
- package/vendor/audio/win32-x64/ffmpeg.gz +0 -0
- package/vendor/audio/win32-x64/manifest.json +39 -0
package/dist/server.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import fs from "node:fs";
|
|
3
|
-
import { cp, mkdir, readFile, readdir, realpath, rename, rm, stat, writeFile, } from "node:fs/promises";
|
|
3
|
+
import { cp, copyFile, mkdir, readFile, readdir, realpath, rename, rm, stat, writeFile, } from "node:fs/promises";
|
|
4
4
|
import http from "node:http";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { Agent } from "./agent.js";
|
|
7
7
|
import { attachmentMimeType, attachmentUserMessage, maxAttachmentBytesPerMessage, maxAttachmentsPerMessage, maxUploadBytes, mimeTypes, saveAttachment, uploadsDirectory, } from "./attachments.js";
|
|
8
8
|
import { configFromEnv } from "./config.js";
|
|
9
9
|
import { isCodeArenaMode } from "./mode.js";
|
|
10
|
-
import { historyMetadata, loadStoredHistory, loadStoredHistoryState, saveStoredHistory, sessionStorageRoot, } from "./history.js";
|
|
10
|
+
import { historyMetadata, IncrementalHistoryWriter, loadStoredHistory, loadStoredHistoryState, saveStoredHistory, sessionStorageRoot, } from "./history.js";
|
|
11
11
|
import { ModelBashMetricJudge, SessionMetricsAnalyzer, } from "./metrics.js";
|
|
12
12
|
import { ModelConversationMetricJudge } from "./conversation-metrics.js";
|
|
13
13
|
import { MockModelClient } from "./mock.js";
|
|
@@ -171,14 +171,21 @@ function sessionUndoMetadataPath(session) {
|
|
|
171
171
|
function sessionUndoWorkspacePath(session) {
|
|
172
172
|
return path.join(sessionUndoRoot(session), "workspace");
|
|
173
173
|
}
|
|
174
|
+
function sessionUndoHistoryPath(session) {
|
|
175
|
+
return path.join(sessionUndoRoot(session), "history.json");
|
|
176
|
+
}
|
|
174
177
|
function sessionRetryPath(session) {
|
|
175
178
|
return path.join(session.root, "model-retry.json");
|
|
176
179
|
}
|
|
177
180
|
function historyHash(messages) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
181
|
+
const hash = crypto.createHash("sha256");
|
|
182
|
+
hash.update('{"messages":[');
|
|
183
|
+
for (let index = 0; index < messages.length; index += 1) {
|
|
184
|
+
if (index)
|
|
185
|
+
hash.update(",");
|
|
186
|
+
hash.update(JSON.stringify(messages[index]));
|
|
187
|
+
}
|
|
188
|
+
return hash.update("]}").digest("hex");
|
|
182
189
|
}
|
|
183
190
|
async function loadModelRetry(session) {
|
|
184
191
|
try {
|
|
@@ -284,7 +291,6 @@ async function loadUndoCheckpoint(session) {
|
|
|
284
291
|
typeof checkpoint.messageId !== "string" ||
|
|
285
292
|
typeof checkpoint.input !== "string" ||
|
|
286
293
|
!Array.isArray(checkpoint.attachments) ||
|
|
287
|
-
!Array.isArray(checkpoint.messages) ||
|
|
288
294
|
typeof checkpoint.createdAt !== "number") {
|
|
289
295
|
throw new Error("invalid persisted undo checkpoint");
|
|
290
296
|
}
|
|
@@ -292,7 +298,36 @@ async function loadUndoCheckpoint(session) {
|
|
|
292
298
|
if (!workspace.isDirectory()) {
|
|
293
299
|
throw new Error("undo checkpoint workspace is not a directory");
|
|
294
300
|
}
|
|
295
|
-
|
|
301
|
+
let undoHistoryExists = true;
|
|
302
|
+
try {
|
|
303
|
+
await stat(sessionUndoHistoryPath(session));
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
if (error.code !== "ENOENT")
|
|
307
|
+
throw error;
|
|
308
|
+
undoHistoryExists = false;
|
|
309
|
+
}
|
|
310
|
+
if (!undoHistoryExists) {
|
|
311
|
+
if (!Array.isArray(checkpoint.messages)) {
|
|
312
|
+
throw new Error("undo checkpoint history is missing");
|
|
313
|
+
}
|
|
314
|
+
// Migrate checkpoints written before undo history became disk-backed.
|
|
315
|
+
await saveStoredHistory(sessionUndoHistoryPath(session), checkpoint.messages, undefined, checkpoint.metrics ?? null);
|
|
316
|
+
await writeFile(sessionUndoMetadataPath(session), JSON.stringify({
|
|
317
|
+
version: 1,
|
|
318
|
+
messageId: checkpoint.messageId,
|
|
319
|
+
input: checkpoint.input,
|
|
320
|
+
attachments: checkpoint.attachments,
|
|
321
|
+
createdAt: checkpoint.createdAt,
|
|
322
|
+
}), "utf8");
|
|
323
|
+
}
|
|
324
|
+
return {
|
|
325
|
+
version: 1,
|
|
326
|
+
messageId: checkpoint.messageId,
|
|
327
|
+
input: checkpoint.input,
|
|
328
|
+
attachments: checkpoint.attachments,
|
|
329
|
+
createdAt: checkpoint.createdAt,
|
|
330
|
+
};
|
|
296
331
|
}
|
|
297
332
|
catch (error) {
|
|
298
333
|
if (error.code === "ENOENT")
|
|
@@ -344,16 +379,11 @@ async function installDirectory(staging, target) {
|
|
|
344
379
|
}
|
|
345
380
|
}
|
|
346
381
|
async function prepareUndoCheckpoint(session, messageId, input, attachments) {
|
|
347
|
-
const storedHistory = await loadStoredHistoryState(sessionHistoryPath(session));
|
|
348
382
|
const checkpoint = {
|
|
349
383
|
version: 1,
|
|
350
384
|
messageId,
|
|
351
385
|
input,
|
|
352
386
|
attachments: attachments.map(checkpointAttachment),
|
|
353
|
-
messages: structuredClone((await readHistory(session)) || []),
|
|
354
|
-
...(storedHistory?.metrics
|
|
355
|
-
? { metrics: structuredClone(storedHistory.metrics) }
|
|
356
|
-
: {}),
|
|
357
387
|
createdAt: Date.now(),
|
|
358
388
|
};
|
|
359
389
|
const target = sessionUndoRoot(session);
|
|
@@ -366,6 +396,19 @@ async function prepareUndoCheckpoint(session, messageId, input, attachments) {
|
|
|
366
396
|
filter: (source) => snapshotIncludes(session.workspace, source),
|
|
367
397
|
verbatimSymlinks: true,
|
|
368
398
|
});
|
|
399
|
+
const undoHistory = path.join(staging, "history.json");
|
|
400
|
+
try {
|
|
401
|
+
await copyFile(sessionHistoryPath(session), undoHistory, fs.constants.COPYFILE_FICLONE);
|
|
402
|
+
}
|
|
403
|
+
catch (error) {
|
|
404
|
+
if (error.code !== "ENOENT")
|
|
405
|
+
throw error;
|
|
406
|
+
await saveStoredHistory(undoHistory, [], undefined, null, []);
|
|
407
|
+
}
|
|
408
|
+
await copyFile(`${sessionHistoryPath(session)}.journal.jsonl`, `${undoHistory}.journal.jsonl`, fs.constants.COPYFILE_FICLONE).catch((error) => {
|
|
409
|
+
if (error.code !== "ENOENT")
|
|
410
|
+
throw error;
|
|
411
|
+
});
|
|
369
412
|
await writeFile(path.join(staging, "checkpoint.json"), JSON.stringify(checkpoint), "utf8");
|
|
370
413
|
await installDirectory(staging, target);
|
|
371
414
|
session.undoCheckpoint = checkpoint;
|
|
@@ -432,9 +475,9 @@ async function createSession(context, clientContext) {
|
|
|
432
475
|
root: paths.root,
|
|
433
476
|
workspace: paths.workspace,
|
|
434
477
|
artifacts: paths.artifacts,
|
|
435
|
-
history: null,
|
|
436
478
|
undoCheckpoint: null,
|
|
437
479
|
events: [],
|
|
480
|
+
eventBytes: 0,
|
|
438
481
|
nextEventId: 1,
|
|
439
482
|
subscribers: new Set(),
|
|
440
483
|
running: null,
|
|
@@ -497,9 +540,9 @@ async function getSession(context, sessionId) {
|
|
|
497
540
|
root: paths.root,
|
|
498
541
|
workspace: paths.workspace,
|
|
499
542
|
artifacts: paths.artifacts,
|
|
500
|
-
history: null,
|
|
501
543
|
undoCheckpoint: null,
|
|
502
544
|
events: [],
|
|
545
|
+
eventBytes: 0,
|
|
503
546
|
nextEventId: 1,
|
|
504
547
|
subscribers: new Set(),
|
|
505
548
|
running: null,
|
|
@@ -553,14 +596,35 @@ function authorize(request, response, session) {
|
|
|
553
596
|
session.touchedAt = Date.now();
|
|
554
597
|
return true;
|
|
555
598
|
}
|
|
599
|
+
const maxStoredEvents = 1000;
|
|
600
|
+
const maxStoredEventBytes = 16 * 1024 * 1024;
|
|
556
601
|
function emit(session, data) {
|
|
557
|
-
const
|
|
602
|
+
const id = String(session.nextEventId++);
|
|
603
|
+
const frame = `id: ${id}\ndata: ${JSON.stringify(data)}\n\n`;
|
|
604
|
+
const event = {
|
|
605
|
+
id,
|
|
606
|
+
type: data.type,
|
|
607
|
+
frame,
|
|
608
|
+
bytes: Buffer.byteLength(frame),
|
|
609
|
+
};
|
|
558
610
|
session.events.push(event);
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
611
|
+
session.eventBytes += event.bytes;
|
|
612
|
+
while (session.events.length > 1 &&
|
|
613
|
+
(session.events.length > maxStoredEvents ||
|
|
614
|
+
session.eventBytes > maxStoredEventBytes)) {
|
|
615
|
+
const removed = session.events.shift();
|
|
616
|
+
if (removed)
|
|
617
|
+
session.eventBytes -= removed.bytes;
|
|
618
|
+
}
|
|
619
|
+
for (const response of [...session.subscribers]) {
|
|
620
|
+
if (response.write(frame))
|
|
621
|
+
continue;
|
|
622
|
+
// Do not let a slow or disconnected SSE client make Node buffer an
|
|
623
|
+
// unbounded copy of a large history stream. The client reconnects with its
|
|
624
|
+
// last event id and replays from the bounded ring.
|
|
625
|
+
session.subscribers.delete(response);
|
|
626
|
+
response.end();
|
|
627
|
+
}
|
|
564
628
|
return event;
|
|
565
629
|
}
|
|
566
630
|
function openEventStream(request, response, session) {
|
|
@@ -574,11 +638,19 @@ function openEventStream(request, response, session) {
|
|
|
574
638
|
response.flushHeaders();
|
|
575
639
|
response.write(": connected\n\n");
|
|
576
640
|
const lastEventId = Number(request.headers["last-event-id"] || 0);
|
|
641
|
+
let replayBackpressured = false;
|
|
577
642
|
for (const event of session.events) {
|
|
578
643
|
if (Number(event.id) > lastEventId) {
|
|
579
|
-
response.write(
|
|
644
|
+
if (!response.write(event.frame)) {
|
|
645
|
+
replayBackpressured = true;
|
|
646
|
+
break;
|
|
647
|
+
}
|
|
580
648
|
}
|
|
581
649
|
}
|
|
650
|
+
if (replayBackpressured) {
|
|
651
|
+
response.end();
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
582
654
|
session.subscribers.add(response);
|
|
583
655
|
const heartbeat = setInterval(() => response.write(": heartbeat\n\n"), 15_000);
|
|
584
656
|
const close = () => {
|
|
@@ -805,6 +877,13 @@ function createUiStream(session, messageId) {
|
|
|
805
877
|
});
|
|
806
878
|
return;
|
|
807
879
|
}
|
|
880
|
+
if (event.type === "memory.update") {
|
|
881
|
+
emit(session, { type: "memory.update", status: event.status,
|
|
882
|
+
...(event.code ? { code: event.code } : {}),
|
|
883
|
+
...(event.error ? { error: event.error } : {}),
|
|
884
|
+
...(event.usage ? { usage: event.usage } : {}) });
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
808
887
|
if (event.type === "compaction") {
|
|
809
888
|
emit(session, {
|
|
810
889
|
type: "compaction",
|
|
@@ -973,10 +1052,6 @@ function createUiStream(session, messageId) {
|
|
|
973
1052
|
}
|
|
974
1053
|
if (event.type === "result") {
|
|
975
1054
|
closeOpenParts();
|
|
976
|
-
emit(session, {
|
|
977
|
-
type: "data-messages",
|
|
978
|
-
data: { messages: event.messages || [] },
|
|
979
|
-
});
|
|
980
1055
|
emit(session, {
|
|
981
1056
|
type: "finish",
|
|
982
1057
|
finishReason: event.status === "success" ? "stop" : "error",
|
|
@@ -1007,16 +1082,10 @@ function createUiStream(session, messageId) {
|
|
|
1007
1082
|
};
|
|
1008
1083
|
}
|
|
1009
1084
|
async function readHistory(session) {
|
|
1010
|
-
|
|
1011
|
-
return structuredClone(session.history);
|
|
1012
|
-
const messages = await loadStoredHistory(sessionHistoryPath(session));
|
|
1013
|
-
if (messages)
|
|
1014
|
-
session.history = structuredClone(messages);
|
|
1015
|
-
return messages ? structuredClone(messages) : undefined;
|
|
1085
|
+
return loadStoredHistory(sessionHistoryPath(session));
|
|
1016
1086
|
}
|
|
1017
|
-
async function saveHistory(session, messages, config, metrics, tools) {
|
|
1018
|
-
await saveStoredHistory(sessionHistoryPath(session), messages, historyMetadata(config, session.id), metrics, tools);
|
|
1019
|
-
session.history = structuredClone([...messages]);
|
|
1087
|
+
async function saveHistory(session, messages, config, metrics, tools, memory) {
|
|
1088
|
+
await saveStoredHistory(sessionHistoryPath(session), messages, historyMetadata(config, session.id), metrics, tools, memory);
|
|
1020
1089
|
}
|
|
1021
1090
|
function sessionMetricsAnalyzer(config, signal) {
|
|
1022
1091
|
const sideQueryModel = config.metricsSideQueryModel || config.model;
|
|
@@ -1100,12 +1169,21 @@ async function runAgent(context, session, prompt, messageId, controller, interru
|
|
|
1100
1169
|
try {
|
|
1101
1170
|
const storedHistory = await loadStoredHistoryState(sessionHistoryPath(session));
|
|
1102
1171
|
const history = storedHistory?.messages;
|
|
1172
|
+
const historyWriter = await IncrementalHistoryWriter.create(sessionHistoryPath(session), storedHistory, historyMetadata(sessionConfig, session.id));
|
|
1173
|
+
session.sessionMemory ||= {};
|
|
1174
|
+
let latestTools = storedHistory?.tools;
|
|
1103
1175
|
const result = await new Agent(sessionConfig, sink, {
|
|
1104
1176
|
askUserHandler,
|
|
1105
1177
|
sessionId: session.id,
|
|
1106
1178
|
sessionAffinityId: session.sessionAffinityId,
|
|
1107
1179
|
signal: controller.signal,
|
|
1108
|
-
|
|
1180
|
+
reuseHistoryMessages: true,
|
|
1181
|
+
sessionMemory: (session.sessionMemory ||= {}),
|
|
1182
|
+
storedSessionMemory: storedHistory?.session_memory,
|
|
1183
|
+
onCheckpoint: (messages, tools, memory) => {
|
|
1184
|
+
latestTools = [...tools];
|
|
1185
|
+
return historyWriter.checkpoint(messages, tools, memory);
|
|
1186
|
+
},
|
|
1109
1187
|
onModelFailure: (messages, error) => {
|
|
1110
1188
|
failedModelCheckpoint = structuredClone([...messages]);
|
|
1111
1189
|
failedModelError = error;
|
|
@@ -1119,6 +1197,7 @@ async function runAgent(context, session, prompt, messageId, controller, interru
|
|
|
1119
1197
|
interrupted: interruptionGeneration !== undefined,
|
|
1120
1198
|
userMessage,
|
|
1121
1199
|
resumeFromHistory,
|
|
1200
|
+
restoreSessionMemory: sessionConfig.restoreSessionMemory,
|
|
1122
1201
|
});
|
|
1123
1202
|
let deliveredResult = result;
|
|
1124
1203
|
let retryable = false;
|
|
@@ -1126,7 +1205,7 @@ async function runAgent(context, session, prompt, messageId, controller, interru
|
|
|
1126
1205
|
!controller.signal.aborted &&
|
|
1127
1206
|
failedModelCheckpoint) {
|
|
1128
1207
|
const checkpoint = structuredClone(failedModelCheckpoint);
|
|
1129
|
-
await
|
|
1208
|
+
await historyWriter.checkpoint(checkpoint, latestTools);
|
|
1130
1209
|
await saveModelRetry(session, {
|
|
1131
1210
|
version: 1,
|
|
1132
1211
|
sessionId: session.id,
|
|
@@ -1157,7 +1236,7 @@ async function runAgent(context, session, prompt, messageId, controller, interru
|
|
|
1157
1236
|
currentTurnMessages,
|
|
1158
1237
|
})
|
|
1159
1238
|
: undefined;
|
|
1160
|
-
await
|
|
1239
|
+
await historyWriter.finalize(deliveredResult.messages, metrics, latestTools);
|
|
1161
1240
|
if (result.status === "success" || controller.signal.aborted) {
|
|
1162
1241
|
if (interruptionGeneration !== undefined &&
|
|
1163
1242
|
session.interruptionGeneration === interruptionGeneration) {
|
|
@@ -1487,8 +1566,12 @@ async function undoLastTurn(config, request, response, session) {
|
|
|
1487
1566
|
});
|
|
1488
1567
|
return;
|
|
1489
1568
|
}
|
|
1569
|
+
const checkpointHistory = await loadStoredHistoryState(sessionUndoHistoryPath(session));
|
|
1570
|
+
const checkpointMessages = checkpointHistory?.messages || [];
|
|
1571
|
+
const checkpointMetrics = checkpointHistory?.metrics ?? null;
|
|
1490
1572
|
await restoreUndoWorkspace(session);
|
|
1491
|
-
await saveHistory(session,
|
|
1573
|
+
await saveHistory(session, checkpointMessages, config, checkpointMetrics, checkpointHistory?.tools, checkpointHistory?.session_memory ?? null);
|
|
1574
|
+
session.sessionMemory = {};
|
|
1492
1575
|
await clearModelRetry(session);
|
|
1493
1576
|
session.pendingInterruption = false;
|
|
1494
1577
|
session.activePrompt = null;
|
|
@@ -1496,13 +1579,14 @@ async function undoLastTurn(config, request, response, session) {
|
|
|
1496
1579
|
await saveSessionMetadata(session);
|
|
1497
1580
|
let turnStart = -1;
|
|
1498
1581
|
for (let index = session.events.length - 1; index >= 0; index -= 1) {
|
|
1499
|
-
if (session.events[index]?.
|
|
1582
|
+
if (session.events[index]?.type === "start") {
|
|
1500
1583
|
turnStart = index;
|
|
1501
1584
|
break;
|
|
1502
1585
|
}
|
|
1503
1586
|
}
|
|
1504
1587
|
if (turnStart >= 0)
|
|
1505
1588
|
session.events.splice(turnStart);
|
|
1589
|
+
session.eventBytes = session.events.reduce((total, stored) => total + stored.bytes, 0);
|
|
1506
1590
|
session.turnStartEventId = session.events.at(-1)?.id || "0";
|
|
1507
1591
|
const event = emit(session, {
|
|
1508
1592
|
type: "data-turn-undone",
|
|
@@ -1510,8 +1594,7 @@ async function undoLastTurn(config, request, response, session) {
|
|
|
1510
1594
|
messageId: checkpoint.messageId,
|
|
1511
1595
|
input: checkpoint.input,
|
|
1512
1596
|
attachments: checkpoint.attachments,
|
|
1513
|
-
|
|
1514
|
-
metrics: checkpoint.metrics ?? null,
|
|
1597
|
+
historyUpdated: true,
|
|
1515
1598
|
canUndo: false,
|
|
1516
1599
|
},
|
|
1517
1600
|
});
|
|
@@ -1522,8 +1605,8 @@ async function undoLastTurn(config, request, response, session) {
|
|
|
1522
1605
|
messageId: checkpoint.messageId,
|
|
1523
1606
|
input: checkpoint.input,
|
|
1524
1607
|
attachments: checkpoint.attachments,
|
|
1525
|
-
messages:
|
|
1526
|
-
metrics:
|
|
1608
|
+
messages: checkpointMessages,
|
|
1609
|
+
metrics: checkpointMetrics,
|
|
1527
1610
|
lastEventId: event.id,
|
|
1528
1611
|
canUndo: false,
|
|
1529
1612
|
});
|