neuralos 3.8.8 → 3.8.9
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/bin/gybackend.cjs +108 -3
- package/package.json +1 -1
package/bin/gybackend.cjs
CHANGED
|
@@ -346328,6 +346328,7 @@ var AgentRunLedger = class {
|
|
|
346328
346328
|
var CHECKPOINT_STRING_CAP = 8 * 1024;
|
|
346329
346329
|
var CHECKPOINT_BYTES_CAP = 16 * 1024 * 1024;
|
|
346330
346330
|
var CHECKPOINT_MAX_MESSAGES = 40;
|
|
346331
|
+
var CHECKPOINT_RETENTION = 8;
|
|
346331
346332
|
function truncateString(input, max = CHECKPOINT_STRING_CAP) {
|
|
346332
346333
|
if (input.length <= max) return input;
|
|
346333
346334
|
const omitted = input.length - max;
|
|
@@ -346395,8 +346396,18 @@ function isAllocationError(error40) {
|
|
|
346395
346396
|
var SafeMemorySaver = class extends MemorySaver {
|
|
346396
346397
|
async put(config2, checkpoint, metadata) {
|
|
346397
346398
|
const pruned = pruneCheckpointForSaver(checkpoint);
|
|
346399
|
+
const threadId = config2?.configurable?.thread_id;
|
|
346400
|
+
const ns = config2?.configurable?.checkpoint_ns ?? "";
|
|
346401
|
+
const checkpointId = checkpoint?.id;
|
|
346402
|
+
if (threadId && checkpointId) {
|
|
346403
|
+
const order = this.putOrderFor(threadId, ns);
|
|
346404
|
+
order.push(checkpointId);
|
|
346405
|
+
this.setPutOrder(threadId, ns, order.slice(-CHECKPOINT_RETENTION * 4));
|
|
346406
|
+
}
|
|
346398
346407
|
try {
|
|
346399
|
-
|
|
346408
|
+
const result = await super.put(config2, pruned, pruneValue(metadata));
|
|
346409
|
+
this.evictOldCheckpoints(config2);
|
|
346410
|
+
return result;
|
|
346400
346411
|
} catch (error40) {
|
|
346401
346412
|
if (!isAllocationError(error40)) throw error40;
|
|
346402
346413
|
console.warn(
|
|
@@ -346409,12 +346420,15 @@ var SafeMemorySaver = class extends MemorySaver {
|
|
|
346409
346420
|
channels.messages = channels.messages.slice(-8);
|
|
346410
346421
|
}
|
|
346411
346422
|
tighter.channel_values = channels;
|
|
346412
|
-
|
|
346423
|
+
const result = await super.put(config2, tighter, { source: "oom-pruned" });
|
|
346424
|
+
this.evictOldCheckpoints(config2);
|
|
346425
|
+
return result;
|
|
346413
346426
|
} catch (retryError) {
|
|
346414
346427
|
if (!isAllocationError(retryError)) throw retryError;
|
|
346415
346428
|
console.warn(
|
|
346416
346429
|
"[SafeMemorySaver] checkpoint still too large \u2014 skipping persist so the run can finish"
|
|
346417
346430
|
);
|
|
346431
|
+
this.evictOldCheckpoints(config2);
|
|
346418
346432
|
return {
|
|
346419
346433
|
configurable: {
|
|
346420
346434
|
thread_id: config2?.configurable?.thread_id,
|
|
@@ -346425,6 +346439,46 @@ var SafeMemorySaver = class extends MemorySaver {
|
|
|
346425
346439
|
}
|
|
346426
346440
|
}
|
|
346427
346441
|
}
|
|
346442
|
+
/**
|
|
346443
|
+
* Keep only the newest CHECKPOINT_RETENTION checkpoints for the thread/ns
|
|
346444
|
+
* in this config. MemorySaver stores them as
|
|
346445
|
+
* storage[threadId][ns][checkpointId] = [serializedCheckpoint, metadata,
|
|
346446
|
+
* parentId]; there is no timestamp, but checkpoint ids from langgraph are
|
|
346447
|
+
* UUIDv4-orderable-ish in practice and — more reliably — the number of
|
|
346448
|
+
* entries is what matters for memory. We cannot know insertion order from
|
|
346449
|
+
* the object shape alone, so we track it ourselves: the ids we just put
|
|
346450
|
+
* are recorded, and anything beyond the newest window is dropped.
|
|
346451
|
+
*/
|
|
346452
|
+
evictOldCheckpoints(config2) {
|
|
346453
|
+
try {
|
|
346454
|
+
const threadId = config2?.configurable?.thread_id;
|
|
346455
|
+
const ns = config2?.configurable?.checkpoint_ns ?? "";
|
|
346456
|
+
if (!threadId) return;
|
|
346457
|
+
const storage = this.storage;
|
|
346458
|
+
const nsMap = storage?.[threadId]?.[ns];
|
|
346459
|
+
if (!nsMap) return;
|
|
346460
|
+
const ids = Object.keys(nsMap);
|
|
346461
|
+
if (ids.length <= CHECKPOINT_RETENTION) return;
|
|
346462
|
+
const order = this.putOrderFor(threadId, ns);
|
|
346463
|
+
const keep = new Set(order.slice(-CHECKPOINT_RETENTION));
|
|
346464
|
+
for (const id of ids) {
|
|
346465
|
+
if (!keep.has(id) && !order.includes(id)) keep.add(id);
|
|
346466
|
+
}
|
|
346467
|
+
for (const id of ids) {
|
|
346468
|
+
if (!keep.has(id)) delete nsMap[id];
|
|
346469
|
+
}
|
|
346470
|
+
const remaining = order.filter((id) => id in nsMap);
|
|
346471
|
+
this.setPutOrder(threadId, ns, remaining.slice(-CHECKPOINT_RETENTION * 2));
|
|
346472
|
+
} catch {
|
|
346473
|
+
}
|
|
346474
|
+
}
|
|
346475
|
+
putOrders = /* @__PURE__ */ new Map();
|
|
346476
|
+
putOrderFor(threadId, ns) {
|
|
346477
|
+
return this.putOrders.get(`${threadId}\0${ns}`) ?? [];
|
|
346478
|
+
}
|
|
346479
|
+
setPutOrder(threadId, ns, ids) {
|
|
346480
|
+
this.putOrders.set(`${threadId}\0${ns}`, ids);
|
|
346481
|
+
}
|
|
346428
346482
|
async putWrites(config2, writes, taskId) {
|
|
346429
346483
|
const prunedWrites = Array.isArray(writes) ? writes.map((w) => {
|
|
346430
346484
|
if (Array.isArray(w) && w.length >= 2) {
|
|
@@ -371792,6 +371846,23 @@ ${reminder}`;
|
|
|
371792
371846
|
baseMessages = mapStoredMessagesToChatMessages(
|
|
371793
371847
|
sanitizedStoredMessages.messages
|
|
371794
371848
|
);
|
|
371849
|
+
const interruptedRun = this.chatHistoryService.getRunMarker(sessionId);
|
|
371850
|
+
if (interruptedRun) {
|
|
371851
|
+
const minutesAgo = Math.max(
|
|
371852
|
+
0,
|
|
371853
|
+
Math.round((Date.now() - (interruptedRun.startedAt || 0)) / 6e4)
|
|
371854
|
+
);
|
|
371855
|
+
baseMessages.push(
|
|
371856
|
+
new SystemMessage(
|
|
371857
|
+
`[INTERRUPTION NOTICE] The previous task on this session was interrupted ${minutesAgo > 0 ? `${minutesAgo} minutes ` : ""}ago (the application stopped before the response completed \u2014 likely a force quit or crash). The last assistant response above may be PARTIAL: it can end mid-sentence, mid-tool-call, or before the task was actually finished. ` + (interruptedRun.inputPreview ? `The interrupted task began with: "${interruptedRun.inputPreview}"
|
|
371858
|
+
` : "") + `Do not assume the prior task completed. If the user's next message relates to it, offer to continue or finish the interrupted work rather than starting from scratch.`
|
|
371859
|
+
)
|
|
371860
|
+
);
|
|
371861
|
+
this.chatHistoryService.clearRunMarker(sessionId);
|
|
371862
|
+
console.warn(
|
|
371863
|
+
`[AgentService_v2] Restored session ${sessionId} after an interrupted run (${interruptedRun.runId}); injected interruption notice into context.`
|
|
371864
|
+
);
|
|
371865
|
+
}
|
|
371795
371866
|
}
|
|
371796
371867
|
const runExperimentalFlags = resolveRunExperimentalFlags(
|
|
371797
371868
|
context2,
|
|
@@ -371811,6 +371882,11 @@ ${reminder}`;
|
|
|
371811
371882
|
execCommandActionModelEnabled: runExperimentalFlags.execCommandActionModelEnabled,
|
|
371812
371883
|
writeStdinActionModelEnabled: runExperimentalFlags.writeStdinActionModelEnabled
|
|
371813
371884
|
};
|
|
371885
|
+
this.chatHistoryService.setRunMarker(sessionId, {
|
|
371886
|
+
runId: ledgerRunId,
|
|
371887
|
+
startedAt: Date.now(),
|
|
371888
|
+
inputPreview: ledgerInputPreview.slice(0, 500)
|
|
371889
|
+
});
|
|
371814
371890
|
try {
|
|
371815
371891
|
const result = await this.graph.invoke(initialState, {
|
|
371816
371892
|
recursionLimit,
|
|
@@ -371869,6 +371945,7 @@ ${reminder}`;
|
|
|
371869
371945
|
this.currentRunIdBySession.delete(sessionId);
|
|
371870
371946
|
this.agentRunLedger?.finishRun(ledgerRunId, ledgerExitStatus, ledgerExitError);
|
|
371871
371947
|
void this.recordCompoundingLessons(sessionId, ledgerRunId, ledgerExitStatus, ledgerExitError);
|
|
371948
|
+
this.chatHistoryService.clearRunMarker(sessionId);
|
|
371872
371949
|
await this.clearCheckpoint(sessionId);
|
|
371873
371950
|
}
|
|
371874
371951
|
}
|
|
@@ -373440,9 +373517,11 @@ var ChatHistoryService = class {
|
|
|
373440
373517
|
saveSession(session) {
|
|
373441
373518
|
const createdAt = this.store.getChatSessionCreatedAt(session.id);
|
|
373442
373519
|
const now = Date.now();
|
|
373520
|
+
const storedMeta = this.store.getChatSessionMeta(session.id);
|
|
373521
|
+
const title = storedMeta?.title ?? session.title;
|
|
373443
373522
|
this.store.saveChatSession({
|
|
373444
373523
|
id: session.id,
|
|
373445
|
-
title
|
|
373524
|
+
title,
|
|
373446
373525
|
messages: Array.from(session.messages.entries()).map(([id, message]) => ({
|
|
373447
373526
|
id,
|
|
373448
373527
|
type: message._getType ? message._getType() : "unknown",
|
|
@@ -373462,6 +373541,32 @@ var ChatHistoryService = class {
|
|
|
373462
373541
|
getSessionMeta(sessionId) {
|
|
373463
373542
|
return this.store.getChatSessionMeta(sessionId);
|
|
373464
373543
|
}
|
|
373544
|
+
// ─── v3.8.9: run interruption markers ─────────────────────────────────────
|
|
373545
|
+
// A marker is SET at run start and CLEARED in the run's finally block.
|
|
373546
|
+
// Only a hard kill (force quit, crash, power loss) skips the finally —
|
|
373547
|
+
// so a leftover marker is a durable, restart-surviving record that the
|
|
373548
|
+
// session's previous run was interrupted. Stored in the history_meta
|
|
373549
|
+
// table (plain SQLite, survives anything short of disk loss).
|
|
373550
|
+
runMarkerKey(sessionId) {
|
|
373551
|
+
return `run-marker:${sessionId}`;
|
|
373552
|
+
}
|
|
373553
|
+
setRunMarker(sessionId, marker) {
|
|
373554
|
+
this.store.setMeta(this.runMarkerKey(sessionId), JSON.stringify(marker));
|
|
373555
|
+
}
|
|
373556
|
+
getRunMarker(sessionId) {
|
|
373557
|
+
const raw = this.store.getMeta(this.runMarkerKey(sessionId));
|
|
373558
|
+
if (!raw) return null;
|
|
373559
|
+
try {
|
|
373560
|
+
const parsed = JSON.parse(raw);
|
|
373561
|
+
if (typeof parsed?.runId === "string") return parsed;
|
|
373562
|
+
return null;
|
|
373563
|
+
} catch {
|
|
373564
|
+
return null;
|
|
373565
|
+
}
|
|
373566
|
+
}
|
|
373567
|
+
clearRunMarker(sessionId) {
|
|
373568
|
+
this.store.setMeta(this.runMarkerKey(sessionId), "");
|
|
373569
|
+
}
|
|
373465
373570
|
loadSession(sessionId) {
|
|
373466
373571
|
const storedSession = this.store.loadChatSession(sessionId);
|
|
373467
373572
|
if (!storedSession) {
|