flavor-code 1.3.13 → 1.3.16
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/agent/loop.d.ts +10 -1
- package/dist/agent/types.d.ts +1 -1
- package/dist/{app-2SBDQ6NS.js → app-6SEGTMMC.js} +136 -31
- package/dist/chunk-CIVPKHF4.js +53 -0
- package/dist/{chunk-JFKRX2KG.js → chunk-HJOCNKPN.js} +1 -1
- package/dist/{chunk-EYCTP5JB.js → chunk-LMFN2QEA.js} +1 -1
- package/dist/{chunk-W2D2MLY2.js → chunk-S525EOFQ.js} +182 -34
- package/dist/cli-main.js +1037 -0
- package/dist/cli.js +84 -1000
- package/dist/context/manager.d.ts +7 -0
- package/dist/desktop/main.js +360 -194
- package/dist/desktop-renderer/assets/{index-BiDVkW9t.js → index-C3JpD2_B.js} +6 -6
- package/dist/desktop-renderer/assets/index-ZZsUx916.css +1 -0
- package/dist/desktop-renderer/assets/{interactive-terminal-CKHHiGNG.js → interactive-terminal-f1PNniPO.js} +1 -1
- package/dist/desktop-renderer/index.html +2 -2
- package/dist/{load-LTTKVPJZ.js → load-DELQW42K.js} +1 -1
- package/dist/sdk/index.js +4 -3
- package/dist/utils/memory-restart.d.ts +33 -0
- package/package.json +3 -1
- package/dist/desktop-renderer/assets/index-DHTr_Acb.css +0 -1
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from "node:module"; const require = createRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
MEMORY_RESTART_EXIT_CODE,
|
|
5
|
+
memoryRestartMarkerPath,
|
|
6
|
+
nextMemoryRestartMarker,
|
|
7
|
+
parseMemoryRestartMarker
|
|
8
|
+
} from "./chunk-CIVPKHF4.js";
|
|
3
9
|
import {
|
|
4
10
|
PERMISSION_MODES,
|
|
5
11
|
PermissionModeSchema,
|
|
@@ -12,7 +18,7 @@ import {
|
|
|
12
18
|
redactConfig,
|
|
13
19
|
setProjectMcpServerDisabled,
|
|
14
20
|
updateProtectedFile
|
|
15
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-HJOCNKPN.js";
|
|
16
22
|
import {
|
|
17
23
|
AuditLogger,
|
|
18
24
|
appendUsageLog,
|
|
@@ -5326,9 +5332,10 @@ async function ensureOnce(options) {
|
|
|
5326
5332
|
|
|
5327
5333
|
// src/production.ts
|
|
5328
5334
|
import { readFile as readFile22 } from "fs/promises";
|
|
5335
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync } from "fs";
|
|
5329
5336
|
import { createHash as createHash18, randomUUID as randomUUID20 } from "crypto";
|
|
5330
5337
|
import { homedir as homedir2, release as osRelease, tmpdir as tmpdir4, version as osVersion } from "os";
|
|
5331
|
-
import { basename as basename6, join as join26, relative as relative20, resolve as resolve28, sep as sep20 } from "path";
|
|
5338
|
+
import { basename as basename6, dirname as dirname19, join as join26, relative as relative20, resolve as resolve28, sep as sep20 } from "path";
|
|
5332
5339
|
|
|
5333
5340
|
// src/agent/subagents.ts
|
|
5334
5341
|
import { z as z5 } from "zod";
|
|
@@ -5877,7 +5884,9 @@ import { createHash as createHash4, randomUUID as randomUUID6 } from "crypto";
|
|
|
5877
5884
|
var DEFAULT_COMPACTION_POLICY = {
|
|
5878
5885
|
windowTokens: 2e5,
|
|
5879
5886
|
reservedOutputTokens: 2e4,
|
|
5880
|
-
|
|
5887
|
+
// 85% of the effective window (180_000 - 27_000 = 153_000): compaction used
|
|
5888
|
+
// to trigger at ~92.8%, which let sessions ride the threshold into heap OOM.
|
|
5889
|
+
autoCompactBufferTokens: 27e3,
|
|
5881
5890
|
warningBufferTokens: 2e4,
|
|
5882
5891
|
blockingBufferTokens: 3e3,
|
|
5883
5892
|
microcompactKeepRecentToolResults: 5,
|
|
@@ -6087,6 +6096,13 @@ var ContextManager = class _ContextManager {
|
|
|
6087
6096
|
#epoch;
|
|
6088
6097
|
#visibilityLog = [];
|
|
6089
6098
|
#activeTransientSystem = /* @__PURE__ */ new Map();
|
|
6099
|
+
/**
|
|
6100
|
+
* The visibility audit log persists every transient system admission and is
|
|
6101
|
+
* serialized in full on every session save. Bound both dimensions or a long
|
|
6102
|
+
* subagent-driven run grows it into hundreds of megabytes (heap OOM).
|
|
6103
|
+
*/
|
|
6104
|
+
static VISIBILITY_LOG_MAX_ENTRIES = 1e3;
|
|
6105
|
+
static VISIBILITY_RECORD_CONTENT_LIMIT = 2048;
|
|
6090
6106
|
constructor(options) {
|
|
6091
6107
|
if (options.compactAtChars !== void 0 && options.compactAtChars <= 0) throw new Error("compactAtChars must be positive");
|
|
6092
6108
|
if (options.toolOutputChars <= 0) throw new Error("toolOutputChars must be positive");
|
|
@@ -6182,11 +6198,14 @@ var ContextManager = class _ContextManager {
|
|
|
6182
6198
|
const record = {
|
|
6183
6199
|
id,
|
|
6184
6200
|
role: "system",
|
|
6185
|
-
content,
|
|
6201
|
+
content: limitVisibilityContent(content),
|
|
6186
6202
|
admittedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6187
6203
|
scope: "run"
|
|
6188
6204
|
};
|
|
6189
6205
|
this.#visibilityLog.push(record);
|
|
6206
|
+
if (this.#visibilityLog.length > _ContextManager.VISIBILITY_LOG_MAX_ENTRIES) {
|
|
6207
|
+
this.#visibilityLog = this.#visibilityLog.slice(-_ContextManager.VISIBILITY_LOG_MAX_ENTRIES);
|
|
6208
|
+
}
|
|
6190
6209
|
this.#activeTransientSystem.set(id, { role: "system", content });
|
|
6191
6210
|
return id;
|
|
6192
6211
|
}
|
|
@@ -6210,8 +6229,9 @@ var ContextManager = class _ContextManager {
|
|
|
6210
6229
|
const currentStableHash = currentStable === void 0 ? this.#epoch.stableSourceHash : hashMessages(currentStable);
|
|
6211
6230
|
if (currentStable !== void 0 && currentStableHash !== this.#epoch.stableSourceHash) {
|
|
6212
6231
|
const value = currentStable.map((message2) => message2.content).join("\n\n");
|
|
6232
|
+
const previous = this.#epoch.sources["system-baseline"] ?? this.#epoch.stableMessages.map((message2) => message2.content).join("\n\n");
|
|
6213
6233
|
if (this.#epoch.sources["system-baseline"] !== value) {
|
|
6214
|
-
updates.push(contextUpdateMessage("system-baseline", value));
|
|
6234
|
+
updates.push(contextUpdateMessage("system-baseline", deltaSourceValue(previous, value)));
|
|
6215
6235
|
this.#epoch.sources["system-baseline"] = value;
|
|
6216
6236
|
}
|
|
6217
6237
|
} else if (currentStable !== void 0 && this.#epoch.sources["system-baseline"] !== void 0) {
|
|
@@ -6222,7 +6242,7 @@ var ContextManager = class _ContextManager {
|
|
|
6222
6242
|
for (const key of DYNAMIC_SOURCE_ORDER) {
|
|
6223
6243
|
const value = next[key];
|
|
6224
6244
|
if (value === void 0 || value === this.#epoch.sources[key]) continue;
|
|
6225
|
-
updates.push(contextUpdateMessage(key, displaySourceValue(key, value)));
|
|
6245
|
+
updates.push(contextUpdateMessage(key, deltaSourceValue(this.#epoch.sources[key], displaySourceValue(key, value))));
|
|
6226
6246
|
this.#epoch.sources[key] = value;
|
|
6227
6247
|
}
|
|
6228
6248
|
for (const key of DYNAMIC_SOURCE_ORDER) {
|
|
@@ -6249,7 +6269,7 @@ var ContextManager = class _ContextManager {
|
|
|
6249
6269
|
const legacySummary = snapshot4.summary?.role === "system" && snapshot4.summary.content.startsWith("Conversation summary\n") ? snapshot4.summary.content.slice("Conversation summary\n".length) : void 0;
|
|
6250
6270
|
this.#compact = snapshot4.compact === void 0 ? legacySummary === void 0 ? void 0 : { summary: legacySummary, compactedAt: (/* @__PURE__ */ new Date(0)).toISOString() } : { ...snapshot4.compact };
|
|
6251
6271
|
if (snapshot4.epoch !== void 0) this.#epoch = cloneEpoch(snapshot4.epoch);
|
|
6252
|
-
this.#visibilityLog = snapshot4.visibilityLog
|
|
6272
|
+
this.#visibilityLog = boundVisibilityLog(snapshot4.visibilityLog);
|
|
6253
6273
|
this.#activeTransientSystem.clear();
|
|
6254
6274
|
this.#messages = messages.map((message2) => message2.role === "tool" ? { ...message2, content: truncateToolOutput(message2.content, this.#toolOutputChars) } : cloneMessage2(message2));
|
|
6255
6275
|
this.#lastRecordedInputTokens = void 0;
|
|
@@ -6293,6 +6313,10 @@ var ContextManager = class _ContextManager {
|
|
|
6293
6313
|
async prepareForModelCall(signal = new AbortController().signal) {
|
|
6294
6314
|
signal.throwIfAborted();
|
|
6295
6315
|
this.refreshContextSources();
|
|
6316
|
+
if (this.#dropStaleContextUpdates()) {
|
|
6317
|
+
this.#lastRecordedInputTokens = void 0;
|
|
6318
|
+
this.#estimatedTokensAtLastRecordedUsage = void 0;
|
|
6319
|
+
}
|
|
6296
6320
|
if (!this.needsCompaction()) return false;
|
|
6297
6321
|
const originalMessages = this.#messages;
|
|
6298
6322
|
const originalRecordedUsage = this.#lastRecordedInputTokens;
|
|
@@ -6392,6 +6416,26 @@ var ContextManager = class _ContextManager {
|
|
|
6392
6416
|
this.#reportCompactProgress(100);
|
|
6393
6417
|
return true;
|
|
6394
6418
|
}
|
|
6419
|
+
#dropStaleContextUpdates() {
|
|
6420
|
+
const latestBySource = /* @__PURE__ */ new Map();
|
|
6421
|
+
for (let index = this.#messages.length - 1; index >= 0; index -= 1) {
|
|
6422
|
+
const source = contextUpdateSource(this.#messages[index]);
|
|
6423
|
+
if (source === void 0 || latestBySource.has(source)) continue;
|
|
6424
|
+
latestBySource.set(source, index);
|
|
6425
|
+
}
|
|
6426
|
+
const next = [];
|
|
6427
|
+
let changed = false;
|
|
6428
|
+
this.#messages.forEach((message2, index) => {
|
|
6429
|
+
const source = contextUpdateSource(message2);
|
|
6430
|
+
if (source !== void 0 && latestBySource.get(source) !== index) {
|
|
6431
|
+
changed = true;
|
|
6432
|
+
return;
|
|
6433
|
+
}
|
|
6434
|
+
next.push(message2);
|
|
6435
|
+
});
|
|
6436
|
+
if (changed) this.#messages = next;
|
|
6437
|
+
return changed;
|
|
6438
|
+
}
|
|
6395
6439
|
#reportCompactProgress(percentage) {
|
|
6396
6440
|
const normalized = Math.max(0, Math.min(100, Math.floor(percentage / 10) * 10));
|
|
6397
6441
|
if (normalized === this.#lastCompactProgress) return;
|
|
@@ -6503,6 +6547,33 @@ function contextUpdateMessage(source, content) {
|
|
|
6503
6547
|
return { role: "system", content: `Context update [${source}]
|
|
6504
6548
|
${content}` };
|
|
6505
6549
|
}
|
|
6550
|
+
var CONTEXT_UPDATE_PREFIX = "Context update [";
|
|
6551
|
+
function contextUpdateSource(message2) {
|
|
6552
|
+
if (message2.role !== "system" || typeof message2.content !== "string") return void 0;
|
|
6553
|
+
if (!message2.content.startsWith(CONTEXT_UPDATE_PREFIX)) return void 0;
|
|
6554
|
+
const end = message2.content.indexOf("]\n", CONTEXT_UPDATE_PREFIX.length);
|
|
6555
|
+
if (end < 0) return void 0;
|
|
6556
|
+
return message2.content.slice(CONTEXT_UPDATE_PREFIX.length, end);
|
|
6557
|
+
}
|
|
6558
|
+
function deltaSourceValue(previous, display) {
|
|
6559
|
+
if (previous === void 0 || !display.startsWith(previous)) return display;
|
|
6560
|
+
return display.slice(previous.length).replace(/^\s+/, "") || display;
|
|
6561
|
+
}
|
|
6562
|
+
function limitVisibilityContent(content) {
|
|
6563
|
+
const limit = ContextManager.VISIBILITY_RECORD_CONTENT_LIMIT;
|
|
6564
|
+
if (content.length <= limit) return content;
|
|
6565
|
+
return `${content.slice(0, limit)}
|
|
6566
|
+
...[truncated; original length: ${content.length} characters]...`;
|
|
6567
|
+
}
|
|
6568
|
+
function boundVisibilityLog(records) {
|
|
6569
|
+
if (records === void 0) return [];
|
|
6570
|
+
const limit = ContextManager.VISIBILITY_RECORD_CONTENT_LIMIT;
|
|
6571
|
+
const bounded2 = records.map((item) => ({
|
|
6572
|
+
...item,
|
|
6573
|
+
...item.content.length <= limit ? {} : { content: limitVisibilityContent(item.content) }
|
|
6574
|
+
}));
|
|
6575
|
+
return bounded2.length > ContextManager.VISIBILITY_LOG_MAX_ENTRIES ? bounded2.slice(-ContextManager.VISIBILITY_LOG_MAX_ENTRIES) : bounded2;
|
|
6576
|
+
}
|
|
6506
6577
|
function cloneEpoch(epoch) {
|
|
6507
6578
|
return {
|
|
6508
6579
|
...epoch,
|
|
@@ -6797,6 +6868,9 @@ function reportProgress(callback, percentage) {
|
|
|
6797
6868
|
}
|
|
6798
6869
|
}
|
|
6799
6870
|
|
|
6871
|
+
// src/agent/loop.ts
|
|
6872
|
+
import { getHeapStatistics } from "v8";
|
|
6873
|
+
|
|
6800
6874
|
// src/models/structured.ts
|
|
6801
6875
|
import { z as z7 } from "zod";
|
|
6802
6876
|
var DEFAULT_RETRY_DELAYS = [1e3, 2e3, 4e3];
|
|
@@ -7214,6 +7288,18 @@ function envMaxIterations() {
|
|
|
7214
7288
|
if (!Number.isInteger(parsed) || parsed <= 0) return void 0;
|
|
7215
7289
|
return parsed;
|
|
7216
7290
|
}
|
|
7291
|
+
var MEMORY_PRESSURE_HEAP_RATIO = 0.8;
|
|
7292
|
+
function memoryPressureError(heapUsed, heapLimit) {
|
|
7293
|
+
if (heapLimit <= 0 || heapUsed < heapLimit * MEMORY_PRESSURE_HEAP_RATIO) return void 0;
|
|
7294
|
+
const mb = (bytes) => Math.round(bytes / 1048576);
|
|
7295
|
+
return {
|
|
7296
|
+
code: "memory_pressure",
|
|
7297
|
+
message: `Heap usage reached ${Math.round(heapUsed / heapLimit * 100)}% of the V8 limit (${mb(heapUsed)}MB of ${mb(heapLimit)}MB); stopping to avoid a crash. The session is saved and will resume after restart.`
|
|
7298
|
+
};
|
|
7299
|
+
}
|
|
7300
|
+
function currentMemoryPressure() {
|
|
7301
|
+
return memoryPressureError(process.memoryUsage().heapUsed, getHeapStatistics().heap_size_limit);
|
|
7302
|
+
}
|
|
7217
7303
|
var AgentLoop = class {
|
|
7218
7304
|
#options;
|
|
7219
7305
|
#iterationLimitMode = "standard";
|
|
@@ -7284,6 +7370,11 @@ var AgentLoop = class {
|
|
|
7284
7370
|
yield { type: "error", error: { code: "cancelled", message: abortMessage(request.signal) } };
|
|
7285
7371
|
return;
|
|
7286
7372
|
}
|
|
7373
|
+
const pressure = currentMemoryPressure();
|
|
7374
|
+
if (pressure !== void 0) {
|
|
7375
|
+
yield { type: "error", error: pressure };
|
|
7376
|
+
return;
|
|
7377
|
+
}
|
|
7287
7378
|
const softLimit = Math.floor(maxIterations * this.#options.softLimitFactor);
|
|
7288
7379
|
if (!warned && iteration >= softLimit) {
|
|
7289
7380
|
warned = true;
|
|
@@ -12679,7 +12770,8 @@ var BoundedOutput = class {
|
|
|
12679
12770
|
#headLimit;
|
|
12680
12771
|
#tailLimit;
|
|
12681
12772
|
#head = Buffer.alloc(0);
|
|
12682
|
-
#
|
|
12773
|
+
#tailChunks = [];
|
|
12774
|
+
#tailBytes = 0;
|
|
12683
12775
|
#complete = Buffer.alloc(0);
|
|
12684
12776
|
#bytes = 0;
|
|
12685
12777
|
constructor(limit) {
|
|
@@ -12699,15 +12791,24 @@ var BoundedOutput = class {
|
|
|
12699
12791
|
const count = Math.min(this.#headLimit - this.#head.length, chunk.length);
|
|
12700
12792
|
this.#head = Buffer.concat([this.#head, chunk.subarray(0, count)]);
|
|
12701
12793
|
}
|
|
12702
|
-
if (this.#tailLimit > 0)
|
|
12794
|
+
if (this.#tailLimit > 0) {
|
|
12795
|
+
this.#tailChunks.push(chunk);
|
|
12796
|
+
this.#tailBytes += chunk.length;
|
|
12797
|
+
if (this.#tailBytes >= this.#tailLimit * 2) {
|
|
12798
|
+
const merged = Buffer.concat(this.#tailChunks).subarray(-this.#tailLimit);
|
|
12799
|
+
this.#tailChunks = [merged];
|
|
12800
|
+
this.#tailBytes = merged.length;
|
|
12801
|
+
}
|
|
12802
|
+
}
|
|
12703
12803
|
}
|
|
12704
12804
|
metadata() {
|
|
12705
12805
|
return { truncated: this.truncated, originalBytes: this.#bytes, limitBytes: this.#limit };
|
|
12706
12806
|
}
|
|
12707
12807
|
text() {
|
|
12708
12808
|
if (!this.truncated) return decodeOutput(this.#complete);
|
|
12809
|
+
const tail = Buffer.concat(this.#tailChunks).subarray(-this.#tailLimit);
|
|
12709
12810
|
const encoding = classifyUtf8(this.#complete) === "invalid" && process.platform === "win32" ? "gb18030" : "utf-8";
|
|
12710
|
-
return `${decodePrefix(this.#head, encoding)}${ELLIPSIS}${decodeSuffix(
|
|
12811
|
+
return `${decodePrefix(this.#head, encoding)}${ELLIPSIS}${decodeSuffix(tail, encoding)}`;
|
|
12711
12812
|
}
|
|
12712
12813
|
};
|
|
12713
12814
|
var AdaptiveOutputDecoder = class {
|
|
@@ -21421,9 +21522,28 @@ async function createProductionRuntime(options) {
|
|
|
21421
21522
|
const recovered = options.resumeSession === void 0 ? void 0 : await sessionStore.load(options.resumeSession === true ? void 0 : options.resumeSession);
|
|
21422
21523
|
let timelineState = recovered === void 0 ? createTranscriptState() : restoreTranscriptState(recovered.timeline.state);
|
|
21423
21524
|
const restoredTranscript = restoreTranscriptState(timelineState);
|
|
21525
|
+
const pendingTimelineStreams = [];
|
|
21526
|
+
const flushTimelineStreams = () => {
|
|
21527
|
+
for (const pending of pendingTimelineStreams.splice(0)) {
|
|
21528
|
+
timelineState = transcriptReducer(timelineState, {
|
|
21529
|
+
type: "session",
|
|
21530
|
+
event: { type: pending.type, text: pending.chunks.join("") }
|
|
21531
|
+
});
|
|
21532
|
+
}
|
|
21533
|
+
};
|
|
21534
|
+
const recordTimelineEvent = (event) => {
|
|
21535
|
+
if (event.type === "text" || event.type === "thinking") {
|
|
21536
|
+
const last = pendingTimelineStreams.at(-1);
|
|
21537
|
+
if (last?.type === event.type) last.chunks.push(event.text);
|
|
21538
|
+
else pendingTimelineStreams.push({ type: event.type, chunks: [event.text] });
|
|
21539
|
+
return;
|
|
21540
|
+
}
|
|
21541
|
+
flushTimelineStreams();
|
|
21542
|
+
timelineState = transcriptReducer(timelineState, { type: "session", event });
|
|
21543
|
+
};
|
|
21424
21544
|
let ideSessionId;
|
|
21425
21545
|
const emitOutput = (event) => {
|
|
21426
|
-
|
|
21546
|
+
recordTimelineEvent(event);
|
|
21427
21547
|
options.output(event);
|
|
21428
21548
|
if (ideSessionId !== void 0) ide.publishEvent(ideSessionId, event);
|
|
21429
21549
|
};
|
|
@@ -21840,27 +21960,30 @@ async function createProductionRuntime(options) {
|
|
|
21840
21960
|
};
|
|
21841
21961
|
}
|
|
21842
21962
|
let persistTail = Promise.resolve();
|
|
21843
|
-
const sessionDocument = () =>
|
|
21844
|
-
|
|
21845
|
-
|
|
21846
|
-
|
|
21847
|
-
|
|
21848
|
-
|
|
21849
|
-
|
|
21850
|
-
|
|
21851
|
-
|
|
21852
|
-
|
|
21853
|
-
|
|
21854
|
-
|
|
21855
|
-
|
|
21856
|
-
|
|
21857
|
-
|
|
21858
|
-
|
|
21859
|
-
|
|
21860
|
-
|
|
21861
|
-
|
|
21862
|
-
|
|
21863
|
-
|
|
21963
|
+
const sessionDocument = () => {
|
|
21964
|
+
flushTimelineStreams();
|
|
21965
|
+
return {
|
|
21966
|
+
version: SESSION_VERSION,
|
|
21967
|
+
sessionId,
|
|
21968
|
+
createdAt,
|
|
21969
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21970
|
+
workspace: { path: workspace },
|
|
21971
|
+
conversation: storedConversation(harness.main.context.snapshot()),
|
|
21972
|
+
tasks: {
|
|
21973
|
+
...taskPlan === void 0 ? {} : { plan: taskPlan },
|
|
21974
|
+
...taskGraph === void 0 ? {} : { graph: taskGraph },
|
|
21975
|
+
states: { ...taskStates },
|
|
21976
|
+
results: { ...taskResults }
|
|
21977
|
+
},
|
|
21978
|
+
// Persist the resolved decision, not the harness snapshot: after logout the
|
|
21979
|
+
// harness may still hold the old login model, and resuming from that stale
|
|
21980
|
+
// value is what made the welcome card show a previous service.
|
|
21981
|
+
models: { main: mainModel, subagent: childModel },
|
|
21982
|
+
permissionMode: harness.permissionMode,
|
|
21983
|
+
memory: memoryLifecycle,
|
|
21984
|
+
timeline: { version: 1, state: timelineState }
|
|
21985
|
+
};
|
|
21986
|
+
};
|
|
21864
21987
|
let persistFailed = false;
|
|
21865
21988
|
const persist = () => {
|
|
21866
21989
|
persistTail = persistTail.catch(() => void 0).then(
|
|
@@ -22612,7 +22735,7 @@ async function createProductionRuntime(options) {
|
|
|
22612
22735
|
contextEpoch: harness.main.context.snapshot().epoch?.id ?? "legacy"
|
|
22613
22736
|
});
|
|
22614
22737
|
const turnId = harnessJournal.startTurn(turnConfig, { prompt, initialUserMessage: runOptions?.initialUserMessage });
|
|
22615
|
-
return durableTurn(persistAndCheckpointAfter(runMain(
|
|
22738
|
+
return monitorMemoryRestart(durableTurn(persistAndCheckpointAfter(runMain(
|
|
22616
22739
|
harness,
|
|
22617
22740
|
skills,
|
|
22618
22741
|
prompt,
|
|
@@ -22632,7 +22755,7 @@ async function createProductionRuntime(options) {
|
|
|
22632
22755
|
prompt,
|
|
22633
22756
|
context: harness.main.context.snapshot(),
|
|
22634
22757
|
label: `turn: ${prompt.slice(0, 80)}`
|
|
22635
|
-
})), harnessJournal, turnId, turnConfig);
|
|
22758
|
+
})), harnessJournal, turnId, turnConfig), () => requestMemoryRestart(workspace, sessionId, emitOutput));
|
|
22636
22759
|
},
|
|
22637
22760
|
runSkill: (skill, prompt, signal) => persistAfter(
|
|
22638
22761
|
runExplicitSkill(harness, skills, skill, prompt, signal, selectedModels.mainError),
|
|
@@ -23381,6 +23504,31 @@ async function* durableTurn(source, journal, turnId, config) {
|
|
|
23381
23504
|
}
|
|
23382
23505
|
}
|
|
23383
23506
|
}
|
|
23507
|
+
async function* monitorMemoryRestart(source, onRestartNeeded) {
|
|
23508
|
+
let pressure = false;
|
|
23509
|
+
for await (const event of source) {
|
|
23510
|
+
if (event.type === "error" && event.error.code === "memory_pressure") pressure = true;
|
|
23511
|
+
yield event;
|
|
23512
|
+
}
|
|
23513
|
+
if (pressure) onRestartNeeded();
|
|
23514
|
+
}
|
|
23515
|
+
function requestMemoryRestart(workspace, sessionId, emitOutput) {
|
|
23516
|
+
try {
|
|
23517
|
+
const markerPath = memoryRestartMarkerPath(workspace);
|
|
23518
|
+
let previous;
|
|
23519
|
+
try {
|
|
23520
|
+
previous = parseMemoryRestartMarker(readFileSync3(markerPath, "utf8"));
|
|
23521
|
+
} catch {
|
|
23522
|
+
}
|
|
23523
|
+
mkdirSync3(dirname19(markerPath), { recursive: true });
|
|
23524
|
+
writeFileSync(markerPath, `${JSON.stringify(nextMemoryRestartMarker(previous, sessionId, /* @__PURE__ */ new Date()))}
|
|
23525
|
+
`, "utf8");
|
|
23526
|
+
} catch {
|
|
23527
|
+
}
|
|
23528
|
+
process.exitCode = MEMORY_RESTART_EXIT_CODE;
|
|
23529
|
+
emitOutput({ type: "notice", message: "Memory watermark reached; the session is saved and Flavor is restarting with a fresh heap." });
|
|
23530
|
+
emitOutput({ type: "exit" });
|
|
23531
|
+
}
|
|
23384
23532
|
async function runGitCommit(deps, hint, signal) {
|
|
23385
23533
|
if (!await isGitRepository(deps.workspace)) return "Not a git repository \u2014 /commit needs git.";
|
|
23386
23534
|
let summary2 = await changeSummary(deps.workspace);
|