@agimon-ai/po-autocompact 0.0.0-alpha.2 → 0.0.0-alpha.21
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/LICENSE +149 -21
- package/README.md +4 -4
- package/dist/apiContracts.cjs +1 -1
- package/dist/apiContracts.cjs.map +1 -1
- package/dist/apiContracts.d.mts +1 -1
- package/dist/apiContracts.mjs +1 -1
- package/dist/apiContracts.mjs.map +1 -1
- package/dist/{compactionPolicy-BIJJHcBP.cjs → compactionPolicy-C76UDULA.cjs} +20 -14
- package/dist/compactionPolicy-C76UDULA.cjs.map +1 -0
- package/dist/{compactionPolicy-CDCYTj2b.mjs → compactionPolicy-_WTvdEQ2.mjs} +15 -15
- package/dist/compactionPolicy-_WTvdEQ2.mjs.map +1 -0
- package/dist/extensions/server.cjs +288 -68
- package/dist/extensions/server.cjs.map +1 -1
- package/dist/extensions/server.d.mts +2 -2
- package/dist/extensions/server.d.mts.map +1 -1
- package/dist/extensions/server.mjs +291 -71
- package/dist/extensions/server.mjs.map +1 -1
- package/dist/extensions/web.mjs +1 -1
- package/dist/extensions/web.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -2
- package/package.json +13 -12
- package/dist/compactionPolicy-BIJJHcBP.cjs.map +0 -1
- package/dist/compactionPolicy-CDCYTj2b.mjs.map +0 -1
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { composeServerProviderOverrides, defineServerPlugin } from "@agimon-ai/po-core/
|
|
3
|
-
import { composeRootHooks, defineHook, defineRoot } from "@agimon-ai/po-core/extensionFile";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
1
|
+
import { C as STATE_CUSTOM_TYPE, S as RUNTIME_STATE_MESSAGE_TYPE, a as createInitialState, b as CONTEXT_MESSAGE_TYPE, c as effectiveThresholds, d as isStructuredCheckpoint, f as latestCheckpointArtifactEntry, g as projectContextMessages, h as parseState, i as contextDetailsFromUnknown, l as fileDetailsFromUnknown, m as parseCheckpointDecision, n as checkpointRequestDetails, o as createRequestId, p as mergeFileDetails, r as checkpointSummaryFromEntry, s as customMessage, t as baselineUsageIsSettled, u as fileOperationsFromMessages, v as withCanonicalFileSections, x as RESUME_MESSAGE_TYPE, y as CHECKPOINT_MESSAGE_TYPE } from "../compactionPolicy-_WTvdEQ2.mjs";
|
|
2
|
+
import { composeServerProviderOverrides, defineServerPlugin } from "@agimon-ai/po-core/serverPlugin";
|
|
3
|
+
import { composeRootHooks, composeRootInjects, defineHook, defineRoot } from "@agimon-ai/po-core/extensionFile";
|
|
4
|
+
import { ArtifactAccessError, COMPACTION_ARTIFACT_DIRECTORY, artifactRoot, listArtifacts, openArtifact, readArtifactBytes, removeArtifact, writeArtifactText } from "@agimon-ai/po-artifact/artifactFiles";
|
|
5
|
+
import { PO_CONTEXT_CONTRIBUTIONS_SERVICE, requirePoContextContributions } from "@agimon-ai/po-core/contextContributions";
|
|
6
|
+
import { PO_UI_HUB_SERVICE, requirePoUiHub } from "@agimon-ai/po-core/uiHub";
|
|
7
|
+
import { loadPoConfig } from "@agimon-ai/po-config";
|
|
8
|
+
import { createPoTelemetry } from "@agimon-ai/po-telemetry";
|
|
8
9
|
import { minimatch } from "minimatch";
|
|
9
|
-
const FOOTER_SOURCE = "
|
|
10
|
-
const STATUS_KEY = "
|
|
10
|
+
const FOOTER_SOURCE = "po-autocompact";
|
|
11
|
+
const STATUS_KEY = "po-autocompact";
|
|
11
12
|
//#endregion
|
|
12
13
|
//#region src/services/autocompactRuntime/index.ts
|
|
13
14
|
function errorMessage(error) {
|
|
@@ -37,7 +38,7 @@ function readContextContributionsSnapshot(service) {
|
|
|
37
38
|
return {
|
|
38
39
|
entries: [],
|
|
39
40
|
errors: [{
|
|
40
|
-
source:
|
|
41
|
+
source: PO_CONTEXT_CONTRIBUTIONS_SERVICE,
|
|
41
42
|
id: "service-snapshot",
|
|
42
43
|
label: "Context contributions",
|
|
43
44
|
order: 0,
|
|
@@ -63,7 +64,7 @@ function formatRuntimeState(snapshot) {
|
|
|
63
64
|
return `<compaction-runtime-state>
|
|
64
65
|
Authoritative runtime state captured when compaction committed. Use it to resume coordination without reconstructing state from the summary.
|
|
65
66
|
<active-plan>
|
|
66
|
-
${snapshot.planPath ? `Source: ${snapshot.planPath}\nExact plan content is restored separately by
|
|
67
|
+
${snapshot.planPath ? `Source: ${snapshot.planPath}\nExact plan content is restored separately by Po Plan.` : "(no active plan document)"}
|
|
67
68
|
</active-plan>
|
|
68
69
|
<context-contributions>
|
|
69
70
|
${formatContextContributions({
|
|
@@ -93,7 +94,7 @@ ${importantContext.length > 0 ? importantContext.join("\n") : "(none recorded ou
|
|
|
93
94
|
}
|
|
94
95
|
function checkpointInstructions(pass, steering) {
|
|
95
96
|
const decision = pass === 2 ? "Start with exactly <shouldCompact>true</shouldCompact> or <shouldCompact>false</shouldCompact>. Use true when the staged summary safely retains the important parent context. Use false only when it is not yet sufficient for safe compaction.\n\n" : "";
|
|
96
|
-
return `Create
|
|
97
|
+
return `Create Po autocompact checkpoint pass ${pass}.
|
|
97
98
|
|
|
98
99
|
${steeringEnvelope(steering)}
|
|
99
100
|
|
|
@@ -117,7 +118,7 @@ const DEFAULT_RUNTIME_CONFIG = {
|
|
|
117
118
|
overrides: []
|
|
118
119
|
};
|
|
119
120
|
/**
|
|
120
|
-
* What the
|
|
121
|
+
* What the Po config says about this package.
|
|
121
122
|
*
|
|
122
123
|
* `modes.autocompact` is read first and `modes.planning.subagents` is the
|
|
123
124
|
* fallback, because summarization borrowed the planning subagent model before
|
|
@@ -126,9 +127,9 @@ const DEFAULT_RUNTIME_CONFIG = {
|
|
|
126
127
|
function autocompactRuntimeConfig(root, onLoadFailure) {
|
|
127
128
|
let modes;
|
|
128
129
|
try {
|
|
129
|
-
modes =
|
|
130
|
+
modes = loadPoConfig(root).modes;
|
|
130
131
|
} catch (error) {
|
|
131
|
-
process.emitWarning("
|
|
132
|
+
process.emitWarning("Po autocompact configuration could not be loaded; using the active session model instead.");
|
|
132
133
|
onLoadFailure?.(error);
|
|
133
134
|
return DEFAULT_RUNTIME_CONFIG;
|
|
134
135
|
}
|
|
@@ -151,23 +152,24 @@ function autocompactRuntimeConfig(root, onLoadFailure) {
|
|
|
151
152
|
}
|
|
152
153
|
//#endregion
|
|
153
154
|
//#region src/services/autocompactTelemetry/index.ts
|
|
154
|
-
const SERVICE_NAME = "
|
|
155
|
+
const SERVICE_NAME = "po-autocompact";
|
|
155
156
|
const PACKAGE_NAME = "@agimon-ai/po-autocompact";
|
|
156
157
|
const AUTOCOMPACT_EVENT = {
|
|
157
|
-
checkpointStarted: "
|
|
158
|
-
checkpointCompleted: "
|
|
159
|
-
checkpointFailed: "
|
|
160
|
-
checkpointInvalid: "
|
|
161
|
-
configurationLoadFailed: "
|
|
162
|
-
contextContributionDegraded: "
|
|
163
|
-
contextCommitted: "
|
|
164
|
-
contextApplied: "
|
|
165
|
-
contextMarkerInvalid: "
|
|
166
|
-
contextHookSlow: "
|
|
167
|
-
nativeCompactionCompleted: "
|
|
158
|
+
checkpointStarted: "po_autocompact.checkpoint_started",
|
|
159
|
+
checkpointCompleted: "po_autocompact.checkpoint_completed",
|
|
160
|
+
checkpointFailed: "po_autocompact.checkpoint_failed",
|
|
161
|
+
checkpointInvalid: "po_autocompact.checkpoint_invalid",
|
|
162
|
+
configurationLoadFailed: "po_autocompact.configuration_load_failed",
|
|
163
|
+
contextContributionDegraded: "po_autocompact.context_contribution_degraded",
|
|
164
|
+
contextCommitted: "po_autocompact.context_committed",
|
|
165
|
+
contextApplied: "po_autocompact.context_applied",
|
|
166
|
+
contextMarkerInvalid: "po_autocompact.context_marker_invalid",
|
|
167
|
+
contextHookSlow: "po_autocompact.context_hook_slow",
|
|
168
|
+
nativeCompactionCompleted: "po_autocompact.native_compaction_completed",
|
|
169
|
+
historyWriteFailed: "po_autocompact.history_write_failed"
|
|
168
170
|
};
|
|
169
171
|
function createAutocompactTelemetry(options = {}) {
|
|
170
|
-
const telemetry =
|
|
172
|
+
const telemetry = createPoTelemetry({
|
|
171
173
|
serviceName: SERVICE_NAME,
|
|
172
174
|
packageName: PACKAGE_NAME,
|
|
173
175
|
cwd: options.cwd,
|
|
@@ -188,6 +190,119 @@ function createAutocompactTelemetry(options = {}) {
|
|
|
188
190
|
};
|
|
189
191
|
}
|
|
190
192
|
//#endregion
|
|
193
|
+
//#region src/services/compactionHistory/index.ts
|
|
194
|
+
const FORMAT = "po-compaction/1";
|
|
195
|
+
const HEADER = `---\nformat: ${JSON.stringify(FORMAT)}\n`;
|
|
196
|
+
const HISTORY_PATH = new RegExp(`^${COMPACTION_ARTIFACT_DIRECTORY}/(?:epoch-\\d+/(?:summary|checkpoint-\\d+)|in-epoch/checkpoint-\\d+)\\.md$`);
|
|
197
|
+
const NATIVE_PREFIX = "The conversation history before this point was compacted into the following summary:\n\n<summary>\n";
|
|
198
|
+
const NATIVE_SUFFIX = "\n</summary>";
|
|
199
|
+
function historyFile(path, fields, body) {
|
|
200
|
+
const header = Object.entries({
|
|
201
|
+
format: FORMAT,
|
|
202
|
+
...fields
|
|
203
|
+
}).flatMap(([key, value]) => value === void 0 ? [] : [`${key}: ${JSON.stringify(value)}`]);
|
|
204
|
+
return {
|
|
205
|
+
path: `${COMPACTION_ARTIFACT_DIRECTORY}/${path}`,
|
|
206
|
+
text: `---\n${header.join("\n")}\n---\n\n${body}\n`
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function isoTime(value) {
|
|
210
|
+
const time = new Date(value);
|
|
211
|
+
return Number.isFinite(time.getTime()) ? time.toISOString() : void 0;
|
|
212
|
+
}
|
|
213
|
+
function passOf(value) {
|
|
214
|
+
if (typeof value !== "object" || value === null || !("pass" in value)) return void 0;
|
|
215
|
+
return value.pass === 1 || value.pass === 2 || value.pass === 3 ? value.pass : void 0;
|
|
216
|
+
}
|
|
217
|
+
function committedFields(entry) {
|
|
218
|
+
if (entry.type === "compaction") {
|
|
219
|
+
const summary = entry.summary.trim();
|
|
220
|
+
return {
|
|
221
|
+
body: summary.startsWith(NATIVE_PREFIX) && summary.endsWith(NATIVE_SUFFIX) ? summary.slice(96, -11).trim() : summary,
|
|
222
|
+
fields: {
|
|
223
|
+
source: "compact",
|
|
224
|
+
tokensBefore: entry.tokensBefore > 0 ? entry.tokensBefore : void 0
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
const marker = customMessage(entry);
|
|
229
|
+
const details = marker?.customType === "po-autocompact-context" ? contextDetailsFromUnknown(marker.details) : void 0;
|
|
230
|
+
if (!details) return void 0;
|
|
231
|
+
return {
|
|
232
|
+
body: checkpointSummaryFromEntry(entry) ?? "",
|
|
233
|
+
fields: {
|
|
234
|
+
source: "autocompact",
|
|
235
|
+
pass: details.poAutocompact.pass,
|
|
236
|
+
tokensBefore: details.poAutocompact.tokensBefore
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
/** Number commits along the active branch so a rewind rewrites the same epoch folders. */
|
|
241
|
+
function wantedHistory(entries) {
|
|
242
|
+
const files = [];
|
|
243
|
+
let staged = [];
|
|
244
|
+
let epoch = 1;
|
|
245
|
+
const checkpoints = (folder) => staged.map(({ entry, summary, pass }, index) => historyFile(`${folder}/checkpoint-${index + 1}.md`, {
|
|
246
|
+
kind: "checkpoint",
|
|
247
|
+
epoch,
|
|
248
|
+
checkpoint: index + 1,
|
|
249
|
+
entryId: entry.id,
|
|
250
|
+
source: "autocompact",
|
|
251
|
+
pass,
|
|
252
|
+
timestamp: isoTime(entry.timestamp)
|
|
253
|
+
}, summary));
|
|
254
|
+
for (const entry of entries) {
|
|
255
|
+
const marker = customMessage(entry);
|
|
256
|
+
if (entry.type === "custom" && entry.customType === "po-autocompact-checkpoint" || marker?.customType === "po-autocompact-checkpoint") {
|
|
257
|
+
const summary = checkpointSummaryFromEntry(entry);
|
|
258
|
+
if (summary) staged.push({
|
|
259
|
+
entry,
|
|
260
|
+
summary,
|
|
261
|
+
pass: passOf(entry.type === "custom" ? entry.data : marker?.details)
|
|
262
|
+
});
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
const committed = committedFields(entry);
|
|
266
|
+
if (!committed) continue;
|
|
267
|
+
files.push(...checkpoints(`epoch-${epoch}`), historyFile(`epoch-${epoch}/summary.md`, {
|
|
268
|
+
kind: "summary",
|
|
269
|
+
epoch,
|
|
270
|
+
entryId: entry.id,
|
|
271
|
+
...committed.fields,
|
|
272
|
+
timestamp: isoTime(entry.timestamp)
|
|
273
|
+
}, committed.body));
|
|
274
|
+
staged = [];
|
|
275
|
+
epoch += 1;
|
|
276
|
+
}
|
|
277
|
+
files.push(...checkpoints("in-epoch"));
|
|
278
|
+
return files;
|
|
279
|
+
}
|
|
280
|
+
async function ownedHistory(root, path) {
|
|
281
|
+
const file = await openArtifact(root, path).catch((error) => {
|
|
282
|
+
if (error instanceof ArtifactAccessError && error.status === 404) return void 0;
|
|
283
|
+
throw error;
|
|
284
|
+
});
|
|
285
|
+
if (!file) return false;
|
|
286
|
+
try {
|
|
287
|
+
const bytes = await readArtifactBytes(file.handle, Math.min(file.stat.size, HEADER.length));
|
|
288
|
+
return new TextDecoder().decode(bytes) === HEADER;
|
|
289
|
+
} finally {
|
|
290
|
+
await file.handle.close();
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/** Mirror history into the session artifact folder. Pruning touches only files carrying this mirror's header. */
|
|
294
|
+
async function mirrorCompactionHistory(root, entries) {
|
|
295
|
+
const files = wantedHistory(entries);
|
|
296
|
+
if (files.length === 0) return;
|
|
297
|
+
for (const file of files) await writeArtifactText(root, file.path, file.text);
|
|
298
|
+
const listed = await listArtifacts(root);
|
|
299
|
+
if (listed.error) throw new Error(listed.error);
|
|
300
|
+
const wanted = new Set(files.map((file) => file.path));
|
|
301
|
+
const stale = listed.items.filter((item) => HISTORY_PATH.test(item.path) && !wanted.has(item.path));
|
|
302
|
+
for (const item of stale) if (await ownedHistory(root, item.path)) await removeArtifact(root, item.path);
|
|
303
|
+
for (const folder of new Set(stale.map((item) => item.path.slice(0, item.path.lastIndexOf("/"))))) await removeArtifact(root, folder);
|
|
304
|
+
}
|
|
305
|
+
//#endregion
|
|
191
306
|
//#region src/services/modelOverrides/index.ts
|
|
192
307
|
/**
|
|
193
308
|
* A pattern naming a provider is matched against `provider/id`, anything else
|
|
@@ -233,7 +348,7 @@ function tailAfter(snapshot, current) {
|
|
|
233
348
|
return current.slice(snapshot.length);
|
|
234
349
|
}
|
|
235
350
|
function leaf(entries) {
|
|
236
|
-
return entries.findLast((entry) => entry.type !== "custom" || entry.customType !== "
|
|
351
|
+
return entries.findLast((entry) => entry.type !== "custom" || entry.customType !== "po-autocompact-state" && entry.customType !== "po-autocompact-checkpoint")?.id ?? "root";
|
|
237
352
|
}
|
|
238
353
|
function createNativeAutocompact(dependencies = {}) {
|
|
239
354
|
const telemetry = dependencies.telemetry ?? createAutocompactTelemetry();
|
|
@@ -252,8 +367,11 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
252
367
|
let configFailureReported = false;
|
|
253
368
|
let footer;
|
|
254
369
|
let navigating = false;
|
|
370
|
+
let degraded = false;
|
|
255
371
|
let lastNativeCompactionId;
|
|
256
372
|
let checkpointBoundary;
|
|
373
|
+
let mirrorQueued = false;
|
|
374
|
+
let historyWarnedSession;
|
|
257
375
|
const attributes = () => ({
|
|
258
376
|
"pi.session.id": context?.sessionId ?? "",
|
|
259
377
|
"autocompact.cycle": state.cycle,
|
|
@@ -289,8 +407,6 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
289
407
|
if (!alive(version)) return;
|
|
290
408
|
await execution.session.appendCustomEntry(STATE_CUSTOM_TYPE, {
|
|
291
409
|
...state,
|
|
292
|
-
nativeSnapshot: snapshot,
|
|
293
|
-
nativePreviousSnapshot: previousSnapshot,
|
|
294
410
|
nativeLastCompactionId: lastNativeCompactionId
|
|
295
411
|
});
|
|
296
412
|
if (alive(version)) refreshStatus(execution);
|
|
@@ -305,6 +421,7 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
305
421
|
};
|
|
306
422
|
const fail = async (execution, version, error, malformed = false) => {
|
|
307
423
|
if (!alive(version)) return;
|
|
424
|
+
degraded = true;
|
|
308
425
|
const eventAttributes = attributes();
|
|
309
426
|
const attempts = state.invalidAttempts + 1;
|
|
310
427
|
const pass = state.pass;
|
|
@@ -318,28 +435,51 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
318
435
|
state.phase = "waiting";
|
|
319
436
|
clear();
|
|
320
437
|
state.lastAttemptLeafId = failedLeaf;
|
|
321
|
-
|
|
438
|
+
const errors = [error];
|
|
439
|
+
try {
|
|
440
|
+
await persist(execution, version);
|
|
441
|
+
} catch (persistError) {
|
|
442
|
+
errors.push(persistError);
|
|
443
|
+
}
|
|
322
444
|
if (!alive(version)) return;
|
|
323
|
-
await execution.client.notify({
|
|
324
|
-
body: `
|
|
445
|
+
await Promise.allSettled([Promise.resolve().then(() => execution.client.notify({
|
|
446
|
+
body: `Po autocompact summarization pass ${pass} failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
325
447
|
level: "error"
|
|
326
|
-
})
|
|
327
|
-
await telemetry.recordError(malformed ? AUTOCOMPACT_EVENT.checkpointInvalid : AUTOCOMPACT_EVENT.checkpointFailed, error, {
|
|
448
|
+
})), ...errors.map((failure) => Promise.resolve().then(() => telemetry.recordError(malformed ? AUTOCOMPACT_EVENT.checkpointInvalid : AUTOCOMPACT_EVENT.checkpointFailed, failure, {
|
|
328
449
|
...eventAttributes,
|
|
329
450
|
"autocompact.checkpoint.attempts": attempts,
|
|
330
451
|
"autocompact.checkpoint.exhausted": attempts >= 3
|
|
331
|
-
});
|
|
452
|
+
})))]);
|
|
332
453
|
};
|
|
333
454
|
const branch = async (execution) => await execution.session.entries();
|
|
334
455
|
const canonical = async (execution, entries) => {
|
|
335
456
|
if (!execution.session.contextMessages) throw new Error("Canonical context is unavailable for autocompact.");
|
|
336
457
|
return projectContextMessages(await execution.session.contextMessages(), entries).messages;
|
|
337
458
|
};
|
|
459
|
+
const scheduleMirror = (execution) => {
|
|
460
|
+
if (mirrorQueued) return;
|
|
461
|
+
mirrorQueued = true;
|
|
462
|
+
enqueue(async () => {
|
|
463
|
+
mirrorQueued = false;
|
|
464
|
+
try {
|
|
465
|
+
await mirrorCompactionHistory(artifactRoot(execution.sessionId, execution.environment), await branch(execution));
|
|
466
|
+
} catch (error) {
|
|
467
|
+
const warn = historyWarnedSession !== execution.sessionId;
|
|
468
|
+
historyWarnedSession = execution.sessionId;
|
|
469
|
+
await Promise.allSettled([Promise.resolve().then(() => telemetry.recordWarning(AUTOCOMPACT_EVENT.historyWriteFailed, error, attributes())), ...warn ? [Promise.resolve().then(() => execution.client.notify({
|
|
470
|
+
body: `Po autocompact could not save compaction history: ${error instanceof Error ? error.message : String(error)}`,
|
|
471
|
+
level: "warning"
|
|
472
|
+
}))] : []]);
|
|
473
|
+
}
|
|
474
|
+
}).finally(() => {
|
|
475
|
+
mirrorQueued = false;
|
|
476
|
+
});
|
|
477
|
+
};
|
|
338
478
|
const contributionSnapshot = async (execution) => {
|
|
339
479
|
const result = readContextContributionsSnapshot(contributions);
|
|
340
480
|
for (const error of result.errors) {
|
|
341
481
|
await execution.client.notify({
|
|
342
|
-
body: `
|
|
482
|
+
body: `Po autocompact context contribution degraded (${error.source}/${error.id}): ${error.message}`,
|
|
343
483
|
level: "warning"
|
|
344
484
|
});
|
|
345
485
|
await telemetry.recordWarning(AUTOCOMPACT_EVENT.contextContributionDegraded, new Error(error.message), {
|
|
@@ -369,6 +509,54 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
369
509
|
"autocompact.runtime.contribution_error_count": saved.contributionErrors.length
|
|
370
510
|
};
|
|
371
511
|
};
|
|
512
|
+
const summaryModel = async (execution, configuration) => {
|
|
513
|
+
const ownReference = configuration.agent?.model ? parseModelReference(configuration.agent.model) : void 0;
|
|
514
|
+
const candidate = ownReference ? `${ownReference.provider}/${ownReference.modelId}` : void 0;
|
|
515
|
+
const reference = candidate && execution.textCompletion.available(candidate) ? candidate : execution.model ? `${execution.model.provider}/${execution.model.id}` : "";
|
|
516
|
+
return {
|
|
517
|
+
reference,
|
|
518
|
+
thinking: configuration.agent?.thinking ?? (reference === candidate ? ownReference?.thinking : void 0) ?? (await execution.session.readModelSettings?.())?.thinkingLevel
|
|
519
|
+
};
|
|
520
|
+
};
|
|
521
|
+
const manualCompaction = async (event, execution) => {
|
|
522
|
+
const configuration = configured(execution);
|
|
523
|
+
if (!configuration.enabled || !execution.textCompletion?.summarize) return;
|
|
524
|
+
try {
|
|
525
|
+
const entries = await branch(execution);
|
|
526
|
+
const messages = await canonical(execution, entries);
|
|
527
|
+
const delta = state.pass > 1 && previousSnapshot ? tailAfter(previousSnapshot, messages) : void 0;
|
|
528
|
+
const previous = state.pass > 1 ? checkpointSummaryFromEntry(latestCheckpointArtifactEntry(entries)) : void 0;
|
|
529
|
+
const { reference, thinking } = await summaryModel(execution, configuration);
|
|
530
|
+
const instructions = checkpointInstructions(3, {
|
|
531
|
+
plan: latestPlanSnapshot(entries),
|
|
532
|
+
contextContributions: await contributionSnapshot(execution),
|
|
533
|
+
readFiles: state.readFiles,
|
|
534
|
+
modifiedFiles: state.modifiedFiles
|
|
535
|
+
});
|
|
536
|
+
const { summary } = parseCheckpointDecision(await execution.textCompletion.summarize(reference, {
|
|
537
|
+
messages: delta ?? messages,
|
|
538
|
+
instructions: typeof event.instructions === "string" && event.instructions.trim() ? `${instructions}\n\n${event.instructions}` : instructions,
|
|
539
|
+
...previous ? { previousSummary: previous } : {},
|
|
540
|
+
...thinking ? { thinkingLevel: thinking } : {},
|
|
541
|
+
...execution.signal ? { signal: execution.signal } : {}
|
|
542
|
+
}));
|
|
543
|
+
if (!isStructuredCheckpoint(summary)) throw new Error("Summarization returned an incomplete checkpoint.");
|
|
544
|
+
const files = mergeFileDetails(state, fileOperationsFromMessages(messages));
|
|
545
|
+
const usage = await execution.session.contextUsage?.();
|
|
546
|
+
return { compaction: {
|
|
547
|
+
summary: withCanonicalFileSections(summary, files),
|
|
548
|
+
tokensBefore: usage?.tokens ?? 0,
|
|
549
|
+
retainedTail: [],
|
|
550
|
+
details: files
|
|
551
|
+
} };
|
|
552
|
+
} catch (error) {
|
|
553
|
+
await execution.client.notify({
|
|
554
|
+
body: `Po autocompact manual compaction failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
555
|
+
level: "error"
|
|
556
|
+
});
|
|
557
|
+
throw error;
|
|
558
|
+
}
|
|
559
|
+
};
|
|
372
560
|
const resetCycle = () => {
|
|
373
561
|
state.phase = "waiting";
|
|
374
562
|
state.checkpointQueue = [];
|
|
@@ -412,13 +600,14 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
412
600
|
state.invalidAttempts = 0;
|
|
413
601
|
clear();
|
|
414
602
|
await persist(execution, version);
|
|
603
|
+
scheduleMirror(execution);
|
|
415
604
|
return false;
|
|
416
605
|
}
|
|
417
606
|
if (!execution.session.appendMessage) throw new Error("Checkpoint messages are unavailable.");
|
|
418
607
|
const files = mergeFileDetails(state, fileOperationsFromMessages(messages));
|
|
419
608
|
const details = {
|
|
420
609
|
...files,
|
|
421
|
-
|
|
610
|
+
poAutocompact: {
|
|
422
611
|
version: 2,
|
|
423
612
|
cycle: state.cycle,
|
|
424
613
|
pass,
|
|
@@ -446,6 +635,7 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
446
635
|
state.modifiedFiles = files.modifiedFiles;
|
|
447
636
|
resetCycle();
|
|
448
637
|
await persist(execution, version);
|
|
638
|
+
scheduleMirror(execution);
|
|
449
639
|
if (!alive(version)) return false;
|
|
450
640
|
await telemetry.recordEvent(AUTOCOMPACT_EVENT.contextCommitted, {
|
|
451
641
|
...committedAttributes,
|
|
@@ -454,10 +644,19 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
454
644
|
"autocompact.apply_mode": idle ? "idle" : "turn_end",
|
|
455
645
|
...runtimeAttributes
|
|
456
646
|
});
|
|
457
|
-
if (idle && alive(version)) await execution.session.admitPrompt?.("Asynchronous compaction completed. Continue from the compacted checkpoint's immediate next action without repeating completed work.", "steer", void 0, `${RESUME_MESSAGE_TYPE}:${details.
|
|
647
|
+
if (idle && alive(version)) await execution.session.admitPrompt?.("Asynchronous compaction completed. Continue from the compacted checkpoint's immediate next action without repeating completed work.", "steer", void 0, `${RESUME_MESSAGE_TYPE}:${details.poAutocompact.requestId}`);
|
|
458
648
|
return true;
|
|
459
649
|
};
|
|
460
|
-
const
|
|
650
|
+
const ensureCheckpointBoundary = (execution) => {
|
|
651
|
+
if (checkpointBoundary) return;
|
|
652
|
+
if (!execution.session.registerCheckpointBoundary) throw new Error("Native checkpoint boundaries are unavailable.");
|
|
653
|
+
checkpointBoundary = execution.session.registerCheckpointBoundary(async (boundary) => {
|
|
654
|
+
if (!active || navigating || boundary.signal?.aborted) return;
|
|
655
|
+
const current = context ?? execution;
|
|
656
|
+
await enqueue(() => boundary.signal?.aborted ? Promise.resolve() : progress(current, true, boundary.appendMessage.bind(boundary)));
|
|
657
|
+
});
|
|
658
|
+
};
|
|
659
|
+
const advance = async (execution, allowBusy = false, appendMessage = checkpointBoundary?.appendMessage.bind(checkpointBoundary)) => {
|
|
461
660
|
const version = generation;
|
|
462
661
|
context = execution;
|
|
463
662
|
const activity = await execution.session.activity();
|
|
@@ -510,20 +709,18 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
510
709
|
delete state.pendingCheckpoint;
|
|
511
710
|
await persist(execution, version);
|
|
512
711
|
if (!alive(version)) return;
|
|
712
|
+
degraded = false;
|
|
513
713
|
controller?.abort();
|
|
514
714
|
controller = new AbortController();
|
|
515
715
|
const signal = controller.signal;
|
|
516
|
-
const ownReference = configuration.agent?.model ? parseModelReference(configuration.agent.model) : void 0;
|
|
517
|
-
const candidate = ownReference ? `${ownReference.provider}/${ownReference.modelId}` : void 0;
|
|
518
|
-
const reference = candidate && execution.textCompletion.available(candidate) ? candidate : execution.model ? `${execution.model.provider}/${execution.model.id}` : "";
|
|
519
|
-
const thinking = configuration.agent?.thinking ?? (reference === candidate ? ownReference?.thinking : void 0) ?? (await execution.session.readModelSettings?.())?.thinkingLevel;
|
|
520
|
-
if (!alive(version)) return;
|
|
521
716
|
const requestAttributes = {
|
|
522
717
|
...attributes(),
|
|
523
718
|
"autocompact.message_count.before": messages.length
|
|
524
719
|
};
|
|
525
720
|
const delta = previousSnapshot ? tailAfter(previousSnapshot, messages) : void 0;
|
|
526
|
-
const completion = telemetry.runInSpan("
|
|
721
|
+
const completion = telemetry.runInSpan("po_autocompact.checkpoint", requestAttributes, async () => {
|
|
722
|
+
const { reference, thinking } = await summaryModel(execution, configuration);
|
|
723
|
+
if (!alive(version) || signal.aborted) return "";
|
|
527
724
|
await telemetry.recordEvent(AUTOCOMPACT_EVENT.checkpointStarted, requestAttributes);
|
|
528
725
|
return execution.textCompletion.summarize(reference, {
|
|
529
726
|
messages: pass > 1 && delta ? delta : messages,
|
|
@@ -562,16 +759,21 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
562
759
|
work.add(completion);
|
|
563
760
|
completion.then(() => work.delete(completion), () => work.delete(completion));
|
|
564
761
|
};
|
|
565
|
-
const
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
await
|
|
573
|
-
}
|
|
762
|
+
const progress = async (execution, allowBusy = false, appendMessage) => {
|
|
763
|
+
const version = generation;
|
|
764
|
+
try {
|
|
765
|
+
ensureCheckpointBoundary(execution);
|
|
766
|
+
await advance(execution, allowBusy, appendMessage);
|
|
767
|
+
} catch (error) {
|
|
768
|
+
try {
|
|
769
|
+
await fail(execution, version, error);
|
|
770
|
+
} finally {
|
|
771
|
+
if (alive(version)) delete state.lastAttemptLeafId;
|
|
772
|
+
}
|
|
574
773
|
}
|
|
774
|
+
};
|
|
775
|
+
const load = async (execution) => {
|
|
776
|
+
if (!active) return;
|
|
575
777
|
navigating = false;
|
|
576
778
|
generation += 1;
|
|
577
779
|
const version = generation;
|
|
@@ -582,7 +784,7 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
582
784
|
invalid.clear();
|
|
583
785
|
const entries = await branch(execution);
|
|
584
786
|
if (!alive(version)) return;
|
|
585
|
-
const entry = entries.findLast((item) => item.type === "custom" && item.customType === "
|
|
787
|
+
const entry = entries.findLast((item) => item.type === "custom" && item.customType === "po-autocompact-state");
|
|
586
788
|
const data = entry?.type === "custom" && entry.data && typeof entry.data === "object" ? entry.data : void 0;
|
|
587
789
|
state = parseState(data) ?? createInitialState();
|
|
588
790
|
lastNativeCompactionId = typeof data?.nativeLastCompactionId === "string" ? data.nativeLastCompactionId : void 0;
|
|
@@ -593,9 +795,9 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
593
795
|
const artifacts = entries.slice(entry ? entries.indexOf(entry) + 1 : 0);
|
|
594
796
|
const committed = artifacts.findLast((item) => {
|
|
595
797
|
const message = item.type === "message" ? item.message : void 0;
|
|
596
|
-
if (message?.role !== "custom" || message.customType !== "
|
|
798
|
+
if (message?.role !== "custom" || message.customType !== "po-autocompact-context") return false;
|
|
597
799
|
const details = contextDetailsFromUnknown(message.details);
|
|
598
|
-
return details !== void 0 && details.
|
|
800
|
+
return details !== void 0 && details.poAutocompact.requestId === state.requestId && details.poAutocompact.cycle === state.cycle && details.poAutocompact.pass === state.pass && details.poAutocompact.snapshotLeafId === state.snapshotLeafId && isStructuredCheckpoint(checkpointSummaryFromEntry(item) ?? "");
|
|
599
801
|
});
|
|
600
802
|
if (committed?.type === "message" && committed.message.role === "custom") {
|
|
601
803
|
const details = contextDetailsFromUnknown(committed.message.details);
|
|
@@ -604,7 +806,7 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
604
806
|
resetCycle();
|
|
605
807
|
await persist(execution, version);
|
|
606
808
|
} else if (artifacts.findLast((item) => {
|
|
607
|
-
if (item.type !== "custom" || item.customType !== "
|
|
809
|
+
if (item.type !== "custom" || item.customType !== "po-autocompact-checkpoint") return false;
|
|
608
810
|
const details = item.data;
|
|
609
811
|
return details?.version === 2 && details.requestId === state.requestId && details.cycle === state.cycle && details.pass === state.pass && isStructuredCheckpoint(checkpointSummaryFromEntry(item) ?? "");
|
|
610
812
|
}) && (state.pass === 1 || state.pass === 2)) {
|
|
@@ -618,12 +820,24 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
618
820
|
await persist(execution, version);
|
|
619
821
|
}
|
|
620
822
|
}
|
|
621
|
-
if (state.phase !== "waiting" && state.phase !== "checkpoint_ready") {
|
|
823
|
+
if (state.phase !== "waiting" && (state.phase !== "checkpoint_ready" || !snapshot)) {
|
|
622
824
|
state.phase = "waiting";
|
|
623
825
|
clear();
|
|
826
|
+
delete state.lastAttemptLeafId;
|
|
624
827
|
await persist(execution, version);
|
|
625
828
|
}
|
|
626
|
-
if (alive(version))
|
|
829
|
+
if (!alive(version)) return;
|
|
830
|
+
const progressed = enqueue(() => progress(execution));
|
|
831
|
+
scheduleMirror(execution);
|
|
832
|
+
await progressed;
|
|
833
|
+
};
|
|
834
|
+
const restore = async (execution) => {
|
|
835
|
+
const version = generation + 1;
|
|
836
|
+
try {
|
|
837
|
+
await load(execution);
|
|
838
|
+
} catch (error) {
|
|
839
|
+
await fail(execution, version, error);
|
|
840
|
+
}
|
|
627
841
|
};
|
|
628
842
|
return {
|
|
629
843
|
hooks: [
|
|
@@ -654,7 +868,11 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
654
868
|
},
|
|
655
869
|
{
|
|
656
870
|
event: "session_before_compact",
|
|
657
|
-
handle: (event, execution) =>
|
|
871
|
+
handle: (event, execution) => {
|
|
872
|
+
if (!active || navigating) return;
|
|
873
|
+
if (event.reason === "manual") return manualCompaction(event, execution);
|
|
874
|
+
return !degraded && configured(execution).enabled && event.reason === "threshold" && (state.phase === "checkpoint_pending" || state.phase === "checkpoint_ready") ? { cancel: true } : void 0;
|
|
875
|
+
}
|
|
658
876
|
},
|
|
659
877
|
{
|
|
660
878
|
event: "context",
|
|
@@ -670,7 +888,7 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
670
888
|
const id = leaf(entries);
|
|
671
889
|
if (!invalid.has(id)) {
|
|
672
890
|
invalid.add(id);
|
|
673
|
-
await telemetry.recordError(AUTOCOMPACT_EVENT.contextMarkerInvalid, /* @__PURE__ */ new Error("
|
|
891
|
+
await telemetry.recordError(AUTOCOMPACT_EVENT.contextMarkerInvalid, /* @__PURE__ */ new Error("Po autocompact context marker is malformed."), {
|
|
674
892
|
...attributes(),
|
|
675
893
|
"autocompact.leaf_id": id
|
|
676
894
|
});
|
|
@@ -727,6 +945,7 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
727
945
|
const nativeAttributes = attributes();
|
|
728
946
|
resetCycle();
|
|
729
947
|
await persist(execution, version);
|
|
948
|
+
scheduleMirror(execution);
|
|
730
949
|
if (alive(version)) await telemetry.recordEvent(AUTOCOMPACT_EVENT.nativeCompactionCompleted, {
|
|
731
950
|
...nativeAttributes,
|
|
732
951
|
"autocompact.native.reason": typeof event.reason === "string" ? event.reason : "unknown",
|
|
@@ -739,8 +958,8 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
739
958
|
}
|
|
740
959
|
],
|
|
741
960
|
plugin(cordis) {
|
|
742
|
-
cordis.inject([
|
|
743
|
-
const contribution =
|
|
961
|
+
cordis.inject([PO_UI_HUB_SERVICE], (injected) => {
|
|
962
|
+
const contribution = requirePoUiHub(injected).registerFooter({
|
|
744
963
|
source: FOOTER_SOURCE,
|
|
745
964
|
id: "autocompact",
|
|
746
965
|
order: 20
|
|
@@ -752,8 +971,8 @@ function createNativeAutocompact(dependencies = {}) {
|
|
|
752
971
|
if (footer === contribution) footer = void 0;
|
|
753
972
|
};
|
|
754
973
|
});
|
|
755
|
-
cordis.inject([
|
|
756
|
-
const service =
|
|
974
|
+
cordis.inject([PO_CONTEXT_CONTRIBUTIONS_SERVICE], (injected) => {
|
|
975
|
+
const service = requirePoContextContributions(injected);
|
|
757
976
|
contributions = service;
|
|
758
977
|
return () => {
|
|
759
978
|
if (contributions === service) contributions = void 0;
|
|
@@ -815,11 +1034,12 @@ const via = (identity, value) => value === void 0 ? void 0 : {
|
|
|
815
1034
|
...identity,
|
|
816
1035
|
...value
|
|
817
1036
|
};
|
|
818
|
-
const
|
|
1037
|
+
const serverPlugin = defineServerPlugin({
|
|
819
1038
|
name: "@agimon-ai/po-autocompact",
|
|
820
1039
|
providerOverrides: composeServerProviderOverrides(root_server_default),
|
|
1040
|
+
injects: composeRootInjects({ session: [root_server_default] }),
|
|
821
1041
|
session: async (context) => {
|
|
822
|
-
const scopeSession = await root_server_default
|
|
1042
|
+
const scopeSession = await context.scopeRoot("session", root_server_default, context);
|
|
823
1043
|
const contextSession = {
|
|
824
1044
|
...context,
|
|
825
1045
|
root: scopeSession.value
|
|
@@ -845,6 +1065,6 @@ const facet = defineServerPlugin({
|
|
|
845
1065
|
}
|
|
846
1066
|
});
|
|
847
1067
|
//#endregion
|
|
848
|
-
export {
|
|
1068
|
+
export { serverPlugin as default, serverPlugin };
|
|
849
1069
|
|
|
850
1070
|
//# sourceMappingURL=server.mjs.map
|