@caupulican/pi-agent-core 0.93.16 → 0.93.18
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/dist/compaction/compaction.d.ts +22 -8
- package/dist/compaction/compaction.d.ts.map +1 -1
- package/dist/compaction/compaction.js +96 -27
- package/dist/compaction/compaction.js.map +1 -1
- package/dist/degenerate-assistant-text.d.ts.map +1 -1
- package/dist/degenerate-assistant-text.js +20 -8
- package/dist/degenerate-assistant-text.js.map +1 -1
- package/dist/reliability/watchdogs.d.ts +7 -0
- package/dist/reliability/watchdogs.d.ts.map +1 -1
- package/dist/reliability/watchdogs.js +15 -2
- package/dist/reliability/watchdogs.js.map +1 -1
- package/dist/session/session-manager.d.ts +9 -1
- package/dist/session/session-manager.d.ts.map +1 -1
- package/dist/session/session-manager.js +53 -27
- package/dist/session/session-manager.js.map +1 -1
- package/package.json +2 -2
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Pure functions for compaction logic. The session manager handles I/O,
|
|
5
5
|
* and after compaction the session is reloaded.
|
|
6
6
|
*/
|
|
7
|
-
import type { AssistantMessage, Context, Model, SimpleStreamOptions, Usage } from "@caupulican/pi-ai/types";
|
|
8
|
-
import { type SessionEntry } from "../session/session-manager.ts";
|
|
7
|
+
import type { AssistantMessage, CacheRetention, Context, Model, SimpleStreamOptions, Usage } from "@caupulican/pi-ai/types";
|
|
8
|
+
import { type CompactionRetention, type SessionEntry } from "../session/session-manager.ts";
|
|
9
9
|
import type { AgentMessage, StreamFn, ThinkingLevel } from "../types.ts";
|
|
10
10
|
import { type CompactionFacts } from "./extraction.ts";
|
|
11
11
|
import { type FileOperations } from "./utils.ts";
|
|
@@ -33,6 +33,8 @@ export interface CompactionResult<T = unknown> {
|
|
|
33
33
|
summary: string;
|
|
34
34
|
firstKeptEntryId: string;
|
|
35
35
|
tokensBefore: number;
|
|
36
|
+
/** Sparse history retained when compaction atomically replaces the provider-visible session. */
|
|
37
|
+
retention?: CompactionRetention;
|
|
36
38
|
/** Provider usage spent generating this checkpoint, including chunk and verification retries. */
|
|
37
39
|
usage?: Usage;
|
|
38
40
|
/** Extension-specific data (e.g., ArtifactIndex, version markers for structured compaction) */
|
|
@@ -43,6 +45,17 @@ export interface CompactionResult<T = unknown> {
|
|
|
43
45
|
}
|
|
44
46
|
/** Host-owned provider boundary for shared compaction request enforcement and accounting. */
|
|
45
47
|
export type CompactionCompletion = (model: Model<any>, context: Context, options: SimpleStreamOptions) => Promise<AssistantMessage>;
|
|
48
|
+
/** Existing provider-visible prefix reused by a session-replacement summary request. */
|
|
49
|
+
export interface StructuredCompactionRequest {
|
|
50
|
+
context: Context;
|
|
51
|
+
sessionId: string;
|
|
52
|
+
cacheRetention: Exclude<CacheRetention, "none">;
|
|
53
|
+
}
|
|
54
|
+
export interface CompactionExecutionOptions {
|
|
55
|
+
chunked?: boolean;
|
|
56
|
+
completion?: CompactionCompletion;
|
|
57
|
+
structuredRequest?: StructuredCompactionRequest;
|
|
58
|
+
}
|
|
46
59
|
/**
|
|
47
60
|
* Carry failed LLM verification attempts into the result that the retry ladder eventually applies.
|
|
48
61
|
* Only bounded numeric/check identifiers are persisted in details; raw facts stay in the in-memory reports.
|
|
@@ -60,6 +73,8 @@ export interface CompactionSettings {
|
|
|
60
73
|
* reserve-based behavior while large windows compact earlier. `0`/`1`+ disables the fractional cap.
|
|
61
74
|
*/
|
|
62
75
|
triggerPercent?: number;
|
|
76
|
+
/** Provider-neutral request/history strategy selected by the host adapter. */
|
|
77
|
+
strategy?: "session-replacement";
|
|
63
78
|
}
|
|
64
79
|
export declare const DEFAULT_COMPACTION_SETTINGS: CompactionSettings;
|
|
65
80
|
/**
|
|
@@ -161,8 +176,8 @@ export declare function findCutPoint(entries: SessionEntry[], startIndex: number
|
|
|
161
176
|
* the same message span across multiple attempts (a verification-gate retry), compute this once
|
|
162
177
|
* via {@link prepareSummarizationConversationText} and pass it to every attempt.
|
|
163
178
|
*/
|
|
164
|
-
export declare function generateSummary(currentMessages: AgentMessage[], model: Model<any>, reserveTokens: number, apiKey: string | undefined, headers?: Record<string, string>, signal?: AbortSignal, customInstructions?: string, previousSummary?: string, thinkingLevel?: ThinkingLevel, streamFn?: StreamFn, preDigest?: (conversationText: string, signal?: AbortSignal) => Promise<string>, factsBlock?: string, chunked?: boolean, precomputedConversationText?: string, completion?: CompactionCompletion): Promise<string>;
|
|
165
|
-
export declare function generateSummaryWithUsage(currentMessages: AgentMessage[], model: Model<any>, reserveTokens: number, apiKey: string | undefined, headers?: Record<string, string>, signal?: AbortSignal, customInstructions?: string, previousSummary?: string, thinkingLevel?: ThinkingLevel, streamFn?: StreamFn, preDigest?: (conversationText: string, signal?: AbortSignal) => Promise<string>, factsBlock?: string, chunked?: boolean, precomputedConversationText?: string, completion?: CompactionCompletion): Promise<{
|
|
179
|
+
export declare function generateSummary(currentMessages: AgentMessage[], model: Model<any>, reserveTokens: number, apiKey: string | undefined, headers?: Record<string, string>, signal?: AbortSignal, customInstructions?: string, previousSummary?: string, thinkingLevel?: ThinkingLevel, streamFn?: StreamFn, preDigest?: (conversationText: string, signal?: AbortSignal) => Promise<string>, factsBlock?: string, chunked?: boolean, precomputedConversationText?: string, completion?: CompactionCompletion, structuredRequest?: StructuredCompactionRequest): Promise<string>;
|
|
180
|
+
export declare function generateSummaryWithUsage(currentMessages: AgentMessage[], model: Model<any>, reserveTokens: number, apiKey: string | undefined, headers?: Record<string, string>, signal?: AbortSignal, customInstructions?: string, previousSummary?: string, thinkingLevel?: ThinkingLevel, streamFn?: StreamFn, preDigest?: (conversationText: string, signal?: AbortSignal) => Promise<string>, factsBlock?: string, chunked?: boolean, precomputedConversationText?: string, completion?: CompactionCompletion, structuredRequest?: StructuredCompactionRequest): Promise<{
|
|
166
181
|
text: string;
|
|
167
182
|
usage: Usage;
|
|
168
183
|
}>;
|
|
@@ -191,6 +206,8 @@ export interface CompactionPreparation {
|
|
|
191
206
|
tokensBefore: number;
|
|
192
207
|
/** Summary from previous compaction, for iterative update */
|
|
193
208
|
previousSummary?: string;
|
|
209
|
+
/** Sparse history contract persisted with a session-replacement checkpoint. */
|
|
210
|
+
retention?: CompactionRetention;
|
|
194
211
|
/** File operations extracted from messagesToSummarize */
|
|
195
212
|
fileOps: FileOperations;
|
|
196
213
|
/** Facts extracted from the compacted span for verification gating */
|
|
@@ -208,9 +225,6 @@ export declare function prepareCompaction(pathEntries: SessionEntry[], settings:
|
|
|
208
225
|
* @param preparation - Pre-calculated preparation from prepareCompaction()
|
|
209
226
|
* @param customInstructions - Optional custom focus for the summary
|
|
210
227
|
*/
|
|
211
|
-
export declare function compact(preparation: CompactionPreparation, model: Model<any>, apiKey: string | undefined, headers?: Record<string, string>, customInstructions?: string, signal?: AbortSignal, thinkingLevel?: ThinkingLevel, streamFn?: StreamFn, preDigest?: (conversationText: string, signal?: AbortSignal) => Promise<string>, executionOptions?:
|
|
212
|
-
chunked?: boolean;
|
|
213
|
-
completion?: CompactionCompletion;
|
|
214
|
-
}): Promise<CompactionResult>;
|
|
228
|
+
export declare function compact(preparation: CompactionPreparation, model: Model<any>, apiKey: string | undefined, headers?: Record<string, string>, customInstructions?: string, signal?: AbortSignal, thinkingLevel?: ThinkingLevel, streamFn?: StreamFn, preDigest?: (conversationText: string, signal?: AbortSignal) => Promise<string>, executionOptions?: CompactionExecutionOptions): Promise<CompactionResult>;
|
|
215
229
|
export declare function createDeterministicCompaction(preparation: CompactionPreparation): CompactionResult;
|
|
216
230
|
//# sourceMappingURL=compaction.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../src/compaction/compaction.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../src/compaction/compaction.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
import { completeSimple } from "@caupulican/pi-ai/stream";
|
|
8
8
|
import { uuidv7 } from "@caupulican/pi-ai/uuid";
|
|
9
9
|
import { convertToLlm, createBranchSummaryMessage, createCompactionSummaryMessage, createCustomMessage, } from "../messages.js";
|
|
10
|
-
import { ESTIMATED_IMAGE_CHARS } from "../provider-request-estimator.js";
|
|
11
|
-
import { buildSessionContext } from "../session/session-manager.js";
|
|
10
|
+
import { ESTIMATED_IMAGE_CHARS, estimateProviderRequestTokens } from "../provider-request-estimator.js";
|
|
11
|
+
import { buildSessionContext, } from "../session/session-manager.js";
|
|
12
12
|
import { addUsage, createEmptyUsage } from "../usage.js";
|
|
13
13
|
import { ACTIVE_TASK_SOURCE_MAX_CHARS, extractCompactionFacts, mergePersistentCompactionUserFacts, renderFactsBlock, } from "./extraction.js";
|
|
14
14
|
import { addPersistedFileOperations, computeFileLists, createFileOps, extractFileOpsFromMessage, isPlainRecord, SUMMARIZATION_PROMPT, SUMMARIZATION_SYSTEM_PROMPT, serializeConversation, UPDATE_SUMMARIZATION_PROMPT, } from "./utils.js";
|
|
@@ -445,22 +445,39 @@ export function findCutPoint(entries, startIndex, endIndex, keepRecentTokens) {
|
|
|
445
445
|
// ============================================================================
|
|
446
446
|
// Summarization
|
|
447
447
|
// ============================================================================
|
|
448
|
-
function createSummarizationOptions(model, maxTokens, apiKey, headers, signal, thinkingLevel) {
|
|
449
|
-
//
|
|
450
|
-
//
|
|
448
|
+
function createSummarizationOptions(model, maxTokens, apiKey, headers, signal, thinkingLevel, affinity) {
|
|
449
|
+
// Standalone summaries are isolated one-shot prompts. A session-replacement request deliberately
|
|
450
|
+
// reuses the live affinity so the provider can reuse and validate the exact structured prefix.
|
|
451
451
|
const options = {
|
|
452
452
|
maxTokens,
|
|
453
453
|
signal,
|
|
454
454
|
apiKey,
|
|
455
455
|
headers,
|
|
456
|
-
cacheRetention: "none",
|
|
457
|
-
sessionId: uuidv7(),
|
|
456
|
+
cacheRetention: affinity?.cacheRetention ?? "none",
|
|
457
|
+
sessionId: affinity?.sessionId ?? uuidv7(),
|
|
458
458
|
};
|
|
459
459
|
if (model.reasoning && thinkingLevel && thinkingLevel !== "off") {
|
|
460
460
|
options.reasoning = thinkingLevel;
|
|
461
461
|
}
|
|
462
462
|
return options;
|
|
463
463
|
}
|
|
464
|
+
const STRUCTURED_SUMMARIZATION_CONTROL = `Create a replacement checkpoint for the conversation above.
|
|
465
|
+
The preceding messages are source history; this final temporary message is control data and must not appear in the checkpoint.
|
|
466
|
+
Do not continue the task and do not call tools. Return only the checkpoint.
|
|
467
|
+
Preserve the owner's exact active request and prohibitions, durable decisions, paths, commands, errors, completed work, pending work, and immediate next step. Never include secrets, credentials, or tokens; write [REDACTED].`;
|
|
468
|
+
function buildStructuredSummarizationContext(promptText, request) {
|
|
469
|
+
return {
|
|
470
|
+
...request.context,
|
|
471
|
+
messages: [
|
|
472
|
+
...request.context.messages,
|
|
473
|
+
{
|
|
474
|
+
role: "user",
|
|
475
|
+
content: [{ type: "text", text: `${STRUCTURED_SUMMARIZATION_CONTROL}\n\n${promptText}` }],
|
|
476
|
+
timestamp: Date.now(),
|
|
477
|
+
},
|
|
478
|
+
],
|
|
479
|
+
};
|
|
480
|
+
}
|
|
464
481
|
async function completeSummarization(model, context, options, streamFn, completion) {
|
|
465
482
|
if (completion)
|
|
466
483
|
return completion(model, context, options);
|
|
@@ -470,6 +487,14 @@ async function completeSummarization(model, context, options, streamFn, completi
|
|
|
470
487
|
const stream = await streamFn(model, context, options);
|
|
471
488
|
return stream.result();
|
|
472
489
|
}
|
|
490
|
+
function accountAndValidateSummarization(response, usage, failureLabel) {
|
|
491
|
+
if (usage)
|
|
492
|
+
addUsage(usage, response.usage);
|
|
493
|
+
if (response.stopReason === "error") {
|
|
494
|
+
throw new Error(`${failureLabel} failed: ${response.errorMessage || "Unknown error"}`);
|
|
495
|
+
}
|
|
496
|
+
return response;
|
|
497
|
+
}
|
|
473
498
|
async function completeSummarizationPrompt(promptText, model, maxTokens, apiKey, headers, signal, thinkingLevel, streamFn, completion, usage, failureLabel = "Summarization") {
|
|
474
499
|
const response = await completeSummarization(model, {
|
|
475
500
|
systemPrompt: SUMMARIZATION_SYSTEM_PROMPT,
|
|
@@ -481,12 +506,19 @@ async function completeSummarizationPrompt(promptText, model, maxTokens, apiKey,
|
|
|
481
506
|
},
|
|
482
507
|
],
|
|
483
508
|
}, createSummarizationOptions(model, maxTokens, apiKey, headers, signal, thinkingLevel), streamFn, completion);
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
509
|
+
return accountAndValidateSummarization(response, usage, failureLabel);
|
|
510
|
+
}
|
|
511
|
+
async function completeStructuredSummarizationPrompt(context, request, model, maxTokens, apiKey, headers, signal, thinkingLevel, streamFn, completion, usage) {
|
|
512
|
+
const response = await completeSummarization(model, context, createSummarizationOptions(model, maxTokens, apiKey, headers, signal, thinkingLevel, request), streamFn, completion);
|
|
513
|
+
return accountAndValidateSummarization(response, usage, "Summarization");
|
|
514
|
+
}
|
|
515
|
+
function finalizeSummaryResponse(response, summaryBudget, usage) {
|
|
516
|
+
// A length-stopped checkpoint silently lost its tail sections — gating it as if complete
|
|
517
|
+
// guarantees a verification failure. Fail loudly so the compaction ladder escalates instead.
|
|
518
|
+
if (response.stopReason === "length") {
|
|
519
|
+
throw new Error("summary-length-stop: summarizer hit its output cap before completing the checkpoint");
|
|
488
520
|
}
|
|
489
|
-
return response;
|
|
521
|
+
return { text: truncateSummaryToBudget(extractTextContent(response), summaryBudget), usage };
|
|
490
522
|
}
|
|
491
523
|
/**
|
|
492
524
|
* Serialize messages to conversation text and, if a `preDigest` callback is supplied, run it
|
|
@@ -520,10 +552,10 @@ async function prepareSummarizationConversationText(currentMessages, preDigest,
|
|
|
520
552
|
* the same message span across multiple attempts (a verification-gate retry), compute this once
|
|
521
553
|
* via {@link prepareSummarizationConversationText} and pass it to every attempt.
|
|
522
554
|
*/
|
|
523
|
-
export async function generateSummary(currentMessages, model, reserveTokens, apiKey, headers, signal, customInstructions, previousSummary, thinkingLevel, streamFn, preDigest, factsBlock = "verification demands:\nfiles-modified-recall (must appear in ## Files):\nfiles-read-recall (must appear as exact paths in ## Files, path recall threshold applies):\nworking-set-recall (must appear in ## Working Set):\nopen-errors-recall (must appear in ## Open Problems):\nactions-recall (must appear in ## Done):\nmandatory-rules-recall (must appear in ### Mandatory Rules):\nactive-task-containment (must appear in ## Active Task):\ncancelled-work-dropped (must NOT appear outside ### Mandatory Rules):", chunked = false, precomputedConversationText, completion) {
|
|
524
|
-
return (await generateSummaryWithUsage(currentMessages, model, reserveTokens, apiKey, headers, signal, customInstructions, previousSummary, thinkingLevel, streamFn, preDigest, factsBlock, chunked, precomputedConversationText, completion)).text;
|
|
555
|
+
export async function generateSummary(currentMessages, model, reserveTokens, apiKey, headers, signal, customInstructions, previousSummary, thinkingLevel, streamFn, preDigest, factsBlock = "verification demands:\nfiles-modified-recall (must appear in ## Files):\nfiles-read-recall (must appear as exact paths in ## Files, path recall threshold applies):\nworking-set-recall (must appear in ## Working Set):\nopen-errors-recall (must appear in ## Open Problems):\nactions-recall (must appear in ## Done):\nmandatory-rules-recall (must appear in ### Mandatory Rules):\nactive-task-containment (must appear in ## Active Task):\ncancelled-work-dropped (must NOT appear outside ### Mandatory Rules):", chunked = false, precomputedConversationText, completion, structuredRequest) {
|
|
556
|
+
return (await generateSummaryWithUsage(currentMessages, model, reserveTokens, apiKey, headers, signal, customInstructions, previousSummary, thinkingLevel, streamFn, preDigest, factsBlock, chunked, precomputedConversationText, completion, structuredRequest)).text;
|
|
525
557
|
}
|
|
526
|
-
export async function generateSummaryWithUsage(currentMessages, model, reserveTokens, apiKey, headers, signal, customInstructions, previousSummary, thinkingLevel, streamFn, preDigest, factsBlock = "verification demands:\nfiles-modified-recall (must appear in ## Files):\nfiles-read-recall (must appear as exact paths in ## Files, path recall threshold applies):\nworking-set-recall (must appear in ## Working Set):\nopen-errors-recall (must appear in ## Open Problems):\nactions-recall (must appear in ## Done):\nmandatory-rules-recall (must appear in ### Mandatory Rules):\nactive-task-containment (must appear in ## Active Task):\ncancelled-work-dropped (must NOT appear outside ### Mandatory Rules):", chunked = false, precomputedConversationText, completion) {
|
|
558
|
+
export async function generateSummaryWithUsage(currentMessages, model, reserveTokens, apiKey, headers, signal, customInstructions, previousSummary, thinkingLevel, streamFn, preDigest, factsBlock = "verification demands:\nfiles-modified-recall (must appear in ## Files):\nfiles-read-recall (must appear as exact paths in ## Files, path recall threshold applies):\nworking-set-recall (must appear in ## Working Set):\nopen-errors-recall (must appear in ## Open Problems):\nactions-recall (must appear in ## Done):\nmandatory-rules-recall (must appear in ### Mandatory Rules):\nactive-task-containment (must appear in ## Active Task):\ncancelled-work-dropped (must NOT appear outside ### Mandatory Rules):", chunked = false, precomputedConversationText, completion, structuredRequest) {
|
|
527
559
|
const usage = createEmptyUsage();
|
|
528
560
|
const summaryBudget = getSummaryBudget(reserveTokens, model, factsBlock);
|
|
529
561
|
const maxTokens = summaryBudget;
|
|
@@ -531,10 +563,20 @@ export async function generateSummaryWithUsage(currentMessages, model, reserveTo
|
|
|
531
563
|
if (customInstructions) {
|
|
532
564
|
promptSuffix = `${promptSuffix}\n\nAdditional focus: ${customInstructions}`;
|
|
533
565
|
}
|
|
566
|
+
const inputBound = getSummarizerInputBound(model, maxTokens);
|
|
567
|
+
if (structuredRequest) {
|
|
568
|
+
const structuredContext = buildStructuredSummarizationContext(promptSuffix, structuredRequest);
|
|
569
|
+
if (estimateProviderRequestTokens(structuredContext, model) <= inputBound) {
|
|
570
|
+
const response = await completeStructuredSummarizationPrompt(structuredContext, structuredRequest, model, maxTokens, apiKey, headers, signal, thinkingLevel, streamFn, completion, usage);
|
|
571
|
+
return finalizeSummaryResponse(response, summaryBudget, usage);
|
|
572
|
+
}
|
|
573
|
+
if (!chunked) {
|
|
574
|
+
throw new Error("input-overflow: structured summarization request exceeds summarizer window");
|
|
575
|
+
}
|
|
576
|
+
}
|
|
534
577
|
let conversationText = precomputedConversationText !== undefined
|
|
535
578
|
? precomputedConversationText
|
|
536
579
|
: await prepareSummarizationConversationText(currentMessages, preDigest, signal);
|
|
537
|
-
const inputBound = getSummarizerInputBound(model, maxTokens);
|
|
538
580
|
const initialPromptText = buildSummarizationPrompt(conversationText, previousSummary, promptSuffix);
|
|
539
581
|
if (estimateStringTokens(initialPromptText) > inputBound) {
|
|
540
582
|
if (!chunked) {
|
|
@@ -547,12 +589,7 @@ export async function generateSummaryWithUsage(currentMessages, model, reserveTo
|
|
|
547
589
|
throw new Error("input-overflow: chunked summarization merge still exceeds summarizer window");
|
|
548
590
|
}
|
|
549
591
|
const response = await completeSummarizationPrompt(promptText, model, maxTokens, apiKey, headers, signal, thinkingLevel, streamFn, completion, usage);
|
|
550
|
-
|
|
551
|
-
// guarantees a verification failure. Fail loudly so the compaction ladder escalates instead.
|
|
552
|
-
if (response.stopReason === "length") {
|
|
553
|
-
throw new Error("summary-length-stop: summarizer hit its output cap before completing the checkpoint");
|
|
554
|
-
}
|
|
555
|
-
return { text: truncateSummaryToBudget(extractTextContent(response), summaryBudget), usage };
|
|
592
|
+
return finalizeSummaryResponse(response, summaryBudget, usage);
|
|
556
593
|
}
|
|
557
594
|
function fillPromptTemplate(template, factsBlock, budget) {
|
|
558
595
|
return template.replaceAll("{FACTS_BLOCK}", factsBlock).replaceAll("{BUDGET}", String(budget));
|
|
@@ -716,7 +753,34 @@ export function prepareCompaction(pathEntries, settings, options) {
|
|
|
716
753
|
const boundaryEnd = options?.allowTrailingCompactionAsPrevious && pathEntries[pathEntries.length - 1]?.type === "compaction"
|
|
717
754
|
? pathEntries.length - 1
|
|
718
755
|
: pathEntries.length;
|
|
719
|
-
const
|
|
756
|
+
const liveMessages = buildSessionContext(pathEntries).messages;
|
|
757
|
+
const tokensBefore = estimateContextTokens(liveMessages).tokens;
|
|
758
|
+
if (settings.strategy === "session-replacement") {
|
|
759
|
+
const previousRetention = prevCompactionIndex >= 0 ? pathEntries[prevCompactionIndex].retention : undefined;
|
|
760
|
+
const originalUserEntry = pathEntries.find((entry) => entry.type === "message" &&
|
|
761
|
+
entry.message.role === "user" &&
|
|
762
|
+
(previousRetention?.mode !== "original-user" || entry.id === previousRetention.userEntryId));
|
|
763
|
+
if (!originalUserEntry?.id)
|
|
764
|
+
return undefined;
|
|
765
|
+
const fileOps = extractFileOperations(liveMessages, pathEntries, prevCompactionIndex);
|
|
766
|
+
const factStart = prevCompactionIndex >= 0 ? prevCompactionIndex + 1 : 0;
|
|
767
|
+
let facts = extractCompactionFacts(pathEntries, factStart, boundaryEnd);
|
|
768
|
+
if (prevCompactionIndex >= 0) {
|
|
769
|
+
const persistedUserFacts = previousUserFacts ?? extractCompactionFacts(pathEntries, 0, boundaryEnd);
|
|
770
|
+
facts = mergePersistentCompactionUserFacts(facts, persistedUserFacts);
|
|
771
|
+
}
|
|
772
|
+
return {
|
|
773
|
+
firstKeptEntryId: originalUserEntry.id,
|
|
774
|
+
messagesToSummarize: liveMessages,
|
|
775
|
+
turnPrefixMessages: [],
|
|
776
|
+
isSplitTurn: false,
|
|
777
|
+
tokensBefore,
|
|
778
|
+
retention: { mode: "original-user", userEntryId: originalUserEntry.id },
|
|
779
|
+
fileOps,
|
|
780
|
+
facts,
|
|
781
|
+
settings,
|
|
782
|
+
};
|
|
783
|
+
}
|
|
720
784
|
const cutPoint = findCutPoint(pathEntries, boundaryStart, boundaryEnd, settings.keepRecentTokens);
|
|
721
785
|
// Get UUID of first kept entry
|
|
722
786
|
const firstKeptEntry = pathEntries[cutPoint.firstKeptEntryIndex];
|
|
@@ -772,9 +836,11 @@ async function generateVerifiedSummary(options) {
|
|
|
772
836
|
let retryInstructions = options.customInstructions;
|
|
773
837
|
const usage = createEmptyUsage();
|
|
774
838
|
const verificationGateFailures = [];
|
|
775
|
-
const precomputedConversationText =
|
|
839
|
+
const precomputedConversationText = options.structuredRequest
|
|
840
|
+
? undefined
|
|
841
|
+
: await prepareSummarizationConversationText(options.messages, options.preDigest, options.signal);
|
|
776
842
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
777
|
-
const generated = await generateSummaryWithUsage(options.messages, options.model, options.reserveTokens, options.apiKey, options.headers, options.signal, retryInstructions, options.previousSummary, options.thinkingLevel, options.streamFn, options.preDigest, options.factsBlock, options.chunked, precomputedConversationText, options.completion);
|
|
843
|
+
const generated = await generateSummaryWithUsage(options.messages, options.model, options.reserveTokens, options.apiKey, options.headers, options.signal, retryInstructions, options.previousSummary, options.thinkingLevel, options.streamFn, options.preDigest, options.factsBlock, options.chunked, precomputedConversationText, options.completion, options.structuredRequest);
|
|
778
844
|
addUsage(usage, generated.usage);
|
|
779
845
|
const summary = generated.text;
|
|
780
846
|
const verification = verifySummary(summary, options.facts);
|
|
@@ -810,7 +876,7 @@ async function generateVerifiedSummary(options) {
|
|
|
810
876
|
* @param customInstructions - Optional custom focus for the summary
|
|
811
877
|
*/
|
|
812
878
|
export async function compact(preparation, model, apiKey, headers, customInstructions, signal, thinkingLevel, streamFn, preDigest, executionOptions) {
|
|
813
|
-
const { firstKeptEntryId, messagesToSummarize, turnPrefixMessages, isSplitTurn, tokensBefore, previousSummary, fileOps, settings, facts: factsFromPreparation, } = preparation;
|
|
879
|
+
const { firstKeptEntryId, messagesToSummarize, turnPrefixMessages, isSplitTurn, tokensBefore, previousSummary, retention, fileOps, settings, facts: factsFromPreparation, } = preparation;
|
|
814
880
|
const facts = factsFromPreparation ?? {
|
|
815
881
|
files: [],
|
|
816
882
|
workingSet: [],
|
|
@@ -834,6 +900,7 @@ export async function compact(preparation, model, apiKey, headers, customInstruc
|
|
|
834
900
|
thinkingLevel,
|
|
835
901
|
streamFn,
|
|
836
902
|
completion: executionOptions?.completion,
|
|
903
|
+
structuredRequest: executionOptions?.structuredRequest,
|
|
837
904
|
preDigest,
|
|
838
905
|
facts,
|
|
839
906
|
factsBlock,
|
|
@@ -852,6 +919,7 @@ export async function compact(preparation, model, apiKey, headers, customInstruc
|
|
|
852
919
|
summary,
|
|
853
920
|
firstKeptEntryId,
|
|
854
921
|
tokensBefore,
|
|
922
|
+
retention,
|
|
855
923
|
usage: summaryUsage,
|
|
856
924
|
details: {
|
|
857
925
|
readFiles,
|
|
@@ -867,7 +935,7 @@ export async function compact(preparation, model, apiKey, headers, customInstruc
|
|
|
867
935
|
}, verified.verificationGateFailures);
|
|
868
936
|
}
|
|
869
937
|
export function createDeterministicCompaction(preparation) {
|
|
870
|
-
const { firstKeptEntryId, tokensBefore, fileOps, facts } = preparation;
|
|
938
|
+
const { firstKeptEntryId, tokensBefore, retention, fileOps, facts } = preparation;
|
|
871
939
|
if (!firstKeptEntryId) {
|
|
872
940
|
throw new Error("First kept entry has no UUID - session may need migration");
|
|
873
941
|
}
|
|
@@ -935,6 +1003,7 @@ export function createDeterministicCompaction(preparation) {
|
|
|
935
1003
|
summary,
|
|
936
1004
|
firstKeptEntryId,
|
|
937
1005
|
tokensBefore,
|
|
1006
|
+
retention,
|
|
938
1007
|
details: {
|
|
939
1008
|
readFiles,
|
|
940
1009
|
modifiedFiles,
|