@caupulican/pi-agent-core 0.90.2 → 0.90.5
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/agent-loop.d.ts.map +1 -1
- package/dist/agent-loop.js +9 -3
- package/dist/agent-loop.js.map +1 -1
- package/dist/compaction/compaction.d.ts +3 -0
- package/dist/compaction/compaction.d.ts.map +1 -1
- package/dist/compaction/compaction.js +90 -67
- package/dist/compaction/compaction.js.map +1 -1
- package/dist/compaction/extraction.d.ts +5 -0
- package/dist/compaction/extraction.d.ts.map +1 -1
- package/dist/compaction/extraction.js +48 -2
- package/dist/compaction/extraction.js.map +1 -1
- package/dist/compaction/utils.d.ts +1 -1
- package/dist/compaction/utils.d.ts.map +1 -1
- package/dist/compaction/utils.js +2 -0
- package/dist/compaction/utils.js.map +1 -1
- package/dist/compaction/verification.d.ts +1 -1
- package/dist/compaction/verification.d.ts.map +1 -1
- package/dist/compaction/verification.js +23 -17
- package/dist/compaction/verification.js.map +1 -1
- package/dist/provider-tool-projection.d.ts.map +1 -1
- package/dist/provider-tool-projection.js +28 -1
- package/dist/provider-tool-projection.js.map +1 -1
- package/dist/tool-failure-memory.d.ts +1 -0
- package/dist/tool-failure-memory.d.ts.map +1 -1
- package/dist/tool-failure-memory.js +56 -13
- package/dist/tool-failure-memory.js.map +1 -1
- package/dist/tool-failure-recovery-gate.d.ts +7 -1
- package/dist/tool-failure-recovery-gate.d.ts.map +1 -1
- package/dist/tool-failure-recovery-gate.js +19 -3
- package/dist/tool-failure-recovery-gate.js.map +1 -1
- package/dist/tool-failure-recovery-protocol.js +5 -5
- package/dist/tool-failure-recovery-protocol.js.map +1 -1
- package/package.json +2 -2
|
@@ -8,10 +8,23 @@ 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
10
|
import { buildSessionContext } from "../session/session-manager.js";
|
|
11
|
-
import { addUsage,
|
|
12
|
-
import { extractCompactionFacts, renderFactsBlock } from "./extraction.js";
|
|
11
|
+
import { addUsage, createEmptyUsage } from "../usage.js";
|
|
12
|
+
import { ACTIVE_TASK_SOURCE_MAX_CHARS, extractCompactionFacts, mergePersistentCompactionUserFacts, renderFactsBlock, } from "./extraction.js";
|
|
13
13
|
import { addPersistedFileOperations, computeFileLists, createFileOps, extractFileOpsFromMessage, isPlainRecord, SUMMARIZATION_SYSTEM_PROMPT, serializeConversation, } from "./utils.js";
|
|
14
14
|
import { buildRetryPrompt, CompactionVerificationError, deterministicallyFillSummaryGaps, isCompactionSummaryStructurallyUsable, verifySummary, } from "./verification.js";
|
|
15
|
+
function readPersistedCompactionUserFacts(details) {
|
|
16
|
+
if (!isPlainRecord(details))
|
|
17
|
+
return undefined;
|
|
18
|
+
if (typeof details.activeTaskSource !== "string")
|
|
19
|
+
return undefined;
|
|
20
|
+
if (!Array.isArray(details.prohibitions) || !details.prohibitions.every((rule) => typeof rule === "string")) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
activeTaskSource: details.activeTaskSource.slice(0, ACTIVE_TASK_SOURCE_MAX_CHARS),
|
|
25
|
+
prohibitions: [...details.prohibitions],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
15
28
|
/**
|
|
16
29
|
* Extract file operations from messages and previous compaction entries.
|
|
17
30
|
*/
|
|
@@ -724,10 +737,12 @@ export function prepareCompaction(pathEntries, settings, options) {
|
|
|
724
737
|
}
|
|
725
738
|
}
|
|
726
739
|
let previousSummary;
|
|
740
|
+
let previousUserFacts;
|
|
727
741
|
let boundaryStart = 0;
|
|
728
742
|
if (prevCompactionIndex >= 0) {
|
|
729
743
|
const prevCompaction = pathEntries[prevCompactionIndex];
|
|
730
744
|
previousSummary = prevCompaction.summary;
|
|
745
|
+
previousUserFacts = readPersistedCompactionUserFacts(prevCompaction.details);
|
|
731
746
|
const firstKeptEntryIndex = pathEntries.findIndex((entry) => entry.id === prevCompaction.firstKeptEntryId);
|
|
732
747
|
boundaryStart = firstKeptEntryIndex >= 0 ? firstKeptEntryIndex : prevCompactionIndex + 1;
|
|
733
748
|
}
|
|
@@ -767,7 +782,13 @@ export function prepareCompaction(pathEntries, settings, options) {
|
|
|
767
782
|
extractFileOpsFromMessage(msg, fileOps);
|
|
768
783
|
}
|
|
769
784
|
}
|
|
770
|
-
|
|
785
|
+
let facts = extractCompactionFacts(pathEntries, boundaryStart, boundaryEnd);
|
|
786
|
+
if (prevCompactionIndex >= 0) {
|
|
787
|
+
// Older checkpoints did not persist these exact facts. Pay one linear migration scan, then
|
|
788
|
+
// persist the result below so later compactions stay incremental instead of becoming quadratic.
|
|
789
|
+
const persistedUserFacts = previousUserFacts ?? extractCompactionFacts(pathEntries, 0, boundaryEnd);
|
|
790
|
+
facts = mergePersistentCompactionUserFacts(facts, persistedUserFacts);
|
|
791
|
+
}
|
|
771
792
|
return {
|
|
772
793
|
firstKeptEntryId,
|
|
773
794
|
messagesToSummarize,
|
|
@@ -780,21 +801,6 @@ export function prepareCompaction(pathEntries, settings, options) {
|
|
|
780
801
|
settings,
|
|
781
802
|
};
|
|
782
803
|
}
|
|
783
|
-
// ============================================================================
|
|
784
|
-
// Main compaction function
|
|
785
|
-
// ============================================================================
|
|
786
|
-
const TURN_PREFIX_SUMMARIZATION_PROMPT = `Summarize discarded early part of split turn; recent suffix remains.
|
|
787
|
-
|
|
788
|
-
## Original Request
|
|
789
|
-
[User request]
|
|
790
|
-
|
|
791
|
-
## Early Progress
|
|
792
|
-
- [Decisions/work]
|
|
793
|
-
|
|
794
|
-
## Context for Suffix
|
|
795
|
-
- [Facts needed by retained work]
|
|
796
|
-
|
|
797
|
-
Only facts needed to understand suffix.`;
|
|
798
804
|
async function generateVerifiedSummary(options) {
|
|
799
805
|
let retryInstructions = options.customInstructions;
|
|
800
806
|
const usage = createEmptyUsage();
|
|
@@ -805,11 +811,8 @@ async function generateVerifiedSummary(options) {
|
|
|
805
811
|
addUsage(usage, generated.usage);
|
|
806
812
|
const summary = generated.text;
|
|
807
813
|
const verification = verifySummary(summary, options.facts);
|
|
808
|
-
if (verification.ok) {
|
|
809
|
-
return { summary, usage, verification, verificationGateFailures, deterministicGapFills: 0 };
|
|
810
|
-
}
|
|
811
|
-
verificationGateFailures.push(verification);
|
|
812
814
|
if (!isCompactionSummaryStructurallyUsable(summary)) {
|
|
815
|
+
verificationGateFailures.push(verification);
|
|
813
816
|
if (attempt >= 1)
|
|
814
817
|
throw new CompactionVerificationError(verificationGateFailures);
|
|
815
818
|
retryInstructions = buildRetryPrompt(verification, summary);
|
|
@@ -817,6 +820,8 @@ async function generateVerifiedSummary(options) {
|
|
|
817
820
|
}
|
|
818
821
|
const filled = deterministicallyFillSummaryGaps(summary, options.facts);
|
|
819
822
|
if (filled.verification.ok) {
|
|
823
|
+
if (!verification.ok)
|
|
824
|
+
verificationGateFailures.push(verification);
|
|
820
825
|
return {
|
|
821
826
|
summary: filled.summary,
|
|
822
827
|
usage,
|
|
@@ -825,6 +830,7 @@ async function generateVerifiedSummary(options) {
|
|
|
825
830
|
deterministicGapFills: filled.changed ? 1 : 0,
|
|
826
831
|
};
|
|
827
832
|
}
|
|
833
|
+
verificationGateFailures.push(verification);
|
|
828
834
|
throw new CompactionVerificationError(verificationGateFailures);
|
|
829
835
|
}
|
|
830
836
|
throw new CompactionVerificationError(verificationGateFailures);
|
|
@@ -849,31 +855,27 @@ export async function compact(preparation, model, apiKey, headers, customInstruc
|
|
|
849
855
|
delegatedWorkerFacts: [],
|
|
850
856
|
};
|
|
851
857
|
const factsBlock = renderFactsBlock(facts);
|
|
852
|
-
const verified =
|
|
853
|
-
?
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
let summary = verified?.summary ?? "No prior history.";
|
|
872
|
-
let summaryUsage = verified?.usage;
|
|
858
|
+
const verified = await generateVerifiedSummary({
|
|
859
|
+
messages: isSplitTurn && messagesToSummarize.length === 0 ? turnPrefixMessages : messagesToSummarize,
|
|
860
|
+
model,
|
|
861
|
+
reserveTokens: settings.reserveTokens,
|
|
862
|
+
apiKey,
|
|
863
|
+
headers,
|
|
864
|
+
signal,
|
|
865
|
+
customInstructions,
|
|
866
|
+
previousSummary,
|
|
867
|
+
thinkingLevel,
|
|
868
|
+
streamFn,
|
|
869
|
+
completion: executionOptions?.completion,
|
|
870
|
+
preDigest,
|
|
871
|
+
facts,
|
|
872
|
+
factsBlock,
|
|
873
|
+
chunked: executionOptions?.chunked ?? false,
|
|
874
|
+
});
|
|
875
|
+
let summary = verified.summary;
|
|
876
|
+
const summaryUsage = verified.usage;
|
|
873
877
|
if (isSplitTurn) {
|
|
874
|
-
|
|
875
|
-
summary = `${summary}\n\n---\n\n**Turn Context (split turn):**\n\n${turnPrefix.text}`;
|
|
876
|
-
summaryUsage = combineUsage(summaryUsage, turnPrefix.usage);
|
|
878
|
+
summary = `${summary}\n\n---\n\n**Turn Context (split turn):**\n\n${createTurnPrefixSummary(turnPrefixMessages)}`;
|
|
877
879
|
}
|
|
878
880
|
const { readFiles, modifiedFiles } = computeFileLists(fileOps);
|
|
879
881
|
if (!firstKeptEntryId) {
|
|
@@ -887,13 +889,15 @@ export async function compact(preparation, model, apiKey, headers, customInstruc
|
|
|
887
889
|
details: {
|
|
888
890
|
readFiles,
|
|
889
891
|
modifiedFiles,
|
|
892
|
+
activeTaskSource: facts.activeTaskSource,
|
|
893
|
+
prohibitions: [...facts.prohibitions],
|
|
890
894
|
verificationGateFailures: 0,
|
|
891
|
-
deterministicGapFills: verified
|
|
895
|
+
deterministicGapFills: verified.deterministicGapFills,
|
|
892
896
|
},
|
|
893
|
-
verification: verified
|
|
897
|
+
verification: verified.verification,
|
|
894
898
|
verificationGateFailures: [],
|
|
895
|
-
deterministicGapFills: verified
|
|
896
|
-
}, verified
|
|
899
|
+
deterministicGapFills: verified.deterministicGapFills,
|
|
900
|
+
}, verified.verificationGateFailures);
|
|
897
901
|
}
|
|
898
902
|
export function createDeterministicCompaction(preparation) {
|
|
899
903
|
const { firstKeptEntryId, tokensBefore, fileOps, facts } = preparation;
|
|
@@ -964,24 +968,43 @@ export function createDeterministicCompaction(preparation) {
|
|
|
964
968
|
summary,
|
|
965
969
|
firstKeptEntryId,
|
|
966
970
|
tokensBefore,
|
|
967
|
-
details: {
|
|
971
|
+
details: {
|
|
972
|
+
readFiles,
|
|
973
|
+
modifiedFiles,
|
|
974
|
+
activeTaskSource: facts?.activeTaskSource ?? "",
|
|
975
|
+
prohibitions: [...(facts?.prohibitions ?? [])],
|
|
976
|
+
verificationGateFailures: 0,
|
|
977
|
+
deterministicGapFills: 0,
|
|
978
|
+
},
|
|
968
979
|
};
|
|
969
980
|
}
|
|
970
|
-
/**
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
981
|
+
/** Split-turn context is intentionally mechanical: user intent is copied, never summarized. */
|
|
982
|
+
function createTurnPrefixSummary(messages) {
|
|
983
|
+
let originalRequest = "";
|
|
984
|
+
for (const message of messages) {
|
|
985
|
+
if (message.role !== "user")
|
|
986
|
+
continue;
|
|
987
|
+
if (typeof message.content === "string") {
|
|
988
|
+
originalRequest = message.content;
|
|
989
|
+
}
|
|
990
|
+
else {
|
|
991
|
+
originalRequest = message.content
|
|
992
|
+
.filter((block) => block.type === "text")
|
|
993
|
+
.map((block) => block.text)
|
|
994
|
+
.join("");
|
|
995
|
+
}
|
|
996
|
+
break;
|
|
997
|
+
}
|
|
998
|
+
const boundedRequest = originalRequest.slice(0, ACTIVE_TASK_SOURCE_MAX_CHARS) || "(none)";
|
|
999
|
+
return [
|
|
1000
|
+
"## Original Request",
|
|
1001
|
+
boundedRequest,
|
|
1002
|
+
"",
|
|
1003
|
+
"## Early Progress",
|
|
1004
|
+
`- ${messages.length} earlier message(s) compacted; durable facts are in the main checkpoint.`,
|
|
1005
|
+
"",
|
|
1006
|
+
"## Context for Suffix",
|
|
1007
|
+
"- Retained messages continue the original request.",
|
|
1008
|
+
].join("\n");
|
|
986
1009
|
}
|
|
987
1010
|
//# sourceMappingURL=compaction.js.map
|