@caupulican/pi-agent-core 0.90.12 → 0.91.3
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 +28 -8
- package/dist/agent-loop.js.map +1 -1
- package/dist/degenerate-assistant-text.d.ts +27 -0
- package/dist/degenerate-assistant-text.d.ts.map +1 -0
- package/dist/degenerate-assistant-text.js +150 -0
- package/dist/degenerate-assistant-text.js.map +1 -0
- package/dist/tool-failure-memory.d.ts +2 -4
- package/dist/tool-failure-memory.d.ts.map +1 -1
- package/dist/tool-failure-memory.js +49 -3
- package/dist/tool-failure-memory.js.map +1 -1
- package/dist/tool-failure-recovery-gate.d.ts.map +1 -1
- package/dist/tool-failure-recovery-gate.js +7 -3
- package/dist/tool-failure-recovery-gate.js.map +1 -1
- package/dist/utils/truncate.d.ts +19 -0
- package/dist/utils/truncate.d.ts.map +1 -1
- package/dist/utils/truncate.js +124 -0
- package/dist/utils/truncate.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AssistantMessage } from "@caupulican/pi-ai/types";
|
|
2
|
+
/** Consecutive identical non-empty units (lines or sentences) at or above this run count are degeneration. */
|
|
3
|
+
export declare const DEGENERATE_REPEATED_LINE_MIN = 4;
|
|
4
|
+
/** Mid-stream abort once a generation loop is already this long; cheaper than waiting for `done`. */
|
|
5
|
+
export declare const DEGENERATE_STREAM_ABORT_RUN = 8;
|
|
6
|
+
/** Shortest unit that may be an exact tiled status sentence (`Foo.Foo.` with no space). */
|
|
7
|
+
export declare const DEGENERATE_EXACT_REPEAT_MIN = 24;
|
|
8
|
+
/** Smallest power-of-two prose tile that repeats to `text` (`Foo.Foo.` / `Foo.`×4). */
|
|
9
|
+
export declare function exactTiledRepeat(text: string): {
|
|
10
|
+
unit: string;
|
|
11
|
+
times: number;
|
|
12
|
+
} | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Collapse consecutive identical assistant lines, period-2 ABAB line runs, and the same
|
|
15
|
+
* sentence repeated inside one paragraph. Session 01a0016f stored 551 copies of one
|
|
16
|
+
* sentence as a single line; newline-only collapse cannot see that.
|
|
17
|
+
* Session 01a00337 stored the same status sentence concatenated with no space (`Foo.Foo.`)
|
|
18
|
+
* because Responses deltas replayed the full sentence; whitespace split cannot see that.
|
|
19
|
+
*/
|
|
20
|
+
export declare function collapseRepeatedLines(text: string): string;
|
|
21
|
+
export declare function isDegenerateRepeatedText(text: string): boolean;
|
|
22
|
+
export declare function shouldAbortDegenerateStream(text: string): boolean;
|
|
23
|
+
export declare function collapseDegenerateAssistantMessage(message: AssistantMessage): AssistantMessage;
|
|
24
|
+
/** True when this message is (or was collapsed from) a generation loop. */
|
|
25
|
+
export declare function isCollapsedDegenerateAssistantMessage(message: AssistantMessage): boolean;
|
|
26
|
+
export declare function assistantMessageText(message: AssistantMessage): string;
|
|
27
|
+
//# sourceMappingURL=degenerate-assistant-text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"degenerate-assistant-text.d.ts","sourceRoot":"","sources":["../src/degenerate-assistant-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,8GAA8G;AAC9G,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,qGAAqG;AACrG,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,2FAA2F;AAC3F,eAAO,MAAM,2BAA2B,KAAK,CAAC;AA6D9C,uFAAuF;AACvF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAY1F;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAW1D;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOjE;AAID,wBAAgB,kCAAkC,CAAC,OAAO,EAAE,gBAAgB,GAAG,gBAAgB,CAsB9F;AAED,2EAA2E;AAC3E,wBAAgB,qCAAqC,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAExF;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAKtE"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/** Consecutive identical non-empty units (lines or sentences) at or above this run count are degeneration. */
|
|
2
|
+
export const DEGENERATE_REPEATED_LINE_MIN = 4;
|
|
3
|
+
/** Mid-stream abort once a generation loop is already this long; cheaper than waiting for `done`. */
|
|
4
|
+
export const DEGENERATE_STREAM_ABORT_RUN = 8;
|
|
5
|
+
/** Shortest unit that may be an exact tiled status sentence (`Foo.Foo.` with no space). */
|
|
6
|
+
export const DEGENERATE_EXACT_REPEAT_MIN = 24;
|
|
7
|
+
function collapseRepeatedUnits(units, joinWith) {
|
|
8
|
+
if (units.length < DEGENERATE_REPEATED_LINE_MIN)
|
|
9
|
+
return units.join(joinWith);
|
|
10
|
+
const out = [];
|
|
11
|
+
let index = 0;
|
|
12
|
+
while (index < units.length) {
|
|
13
|
+
const unit = units[index];
|
|
14
|
+
let run = 1;
|
|
15
|
+
while (index + run < units.length && units[index + run] === unit)
|
|
16
|
+
run++;
|
|
17
|
+
if (unit.trim() !== "" && run >= DEGENERATE_REPEATED_LINE_MIN) {
|
|
18
|
+
out.push(unit);
|
|
19
|
+
index += run;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (index + 1 < units.length) {
|
|
23
|
+
const next = units[index + 1];
|
|
24
|
+
if (unit.trim() !== "" && next.trim() !== "" && unit !== next) {
|
|
25
|
+
let pairs = 1;
|
|
26
|
+
while (index + (pairs + 1) * 2 <= units.length &&
|
|
27
|
+
units[index + pairs * 2] === unit &&
|
|
28
|
+
units[index + pairs * 2 + 1] === next) {
|
|
29
|
+
pairs++;
|
|
30
|
+
}
|
|
31
|
+
if (pairs >= DEGENERATE_REPEATED_LINE_MIN) {
|
|
32
|
+
out.push(unit, next);
|
|
33
|
+
index += pairs * 2;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
out.push(unit);
|
|
39
|
+
index++;
|
|
40
|
+
}
|
|
41
|
+
return out.join(joinWith);
|
|
42
|
+
}
|
|
43
|
+
function maxRepeatedUnitRun(units) {
|
|
44
|
+
let maxRun = 1;
|
|
45
|
+
let run = 1;
|
|
46
|
+
for (let index = 1; index < units.length; index++) {
|
|
47
|
+
if (units[index] === units[index - 1] && units[index].trim() !== "") {
|
|
48
|
+
run++;
|
|
49
|
+
if (run > maxRun)
|
|
50
|
+
maxRun = run;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
run = 1;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return units.length === 0 ? 0 : maxRun;
|
|
57
|
+
}
|
|
58
|
+
function splitSentences(text) {
|
|
59
|
+
return text.split(/(?<=[.!?])\s+/);
|
|
60
|
+
}
|
|
61
|
+
function isProseTile(unit) {
|
|
62
|
+
return /[.!?]/.test(unit) || /\s/.test(unit);
|
|
63
|
+
}
|
|
64
|
+
/** Smallest power-of-two prose tile that repeats to `text` (`Foo.Foo.` / `Foo.`×4). */
|
|
65
|
+
export function exactTiledRepeat(text) {
|
|
66
|
+
if (text.length < DEGENERATE_EXACT_REPEAT_MIN * 2)
|
|
67
|
+
return undefined;
|
|
68
|
+
let unit = text;
|
|
69
|
+
let times = 1;
|
|
70
|
+
while (unit.length >= DEGENERATE_EXACT_REPEAT_MIN * 2 && unit.length % 2 === 0) {
|
|
71
|
+
const half = unit.length / 2;
|
|
72
|
+
const next = unit.slice(0, half);
|
|
73
|
+
if (!isProseTile(next) || next !== unit.slice(half))
|
|
74
|
+
break;
|
|
75
|
+
unit = next;
|
|
76
|
+
times *= 2;
|
|
77
|
+
}
|
|
78
|
+
return times > 1 ? { unit, times } : undefined;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Collapse consecutive identical assistant lines, period-2 ABAB line runs, and the same
|
|
82
|
+
* sentence repeated inside one paragraph. Session 01a0016f stored 551 copies of one
|
|
83
|
+
* sentence as a single line; newline-only collapse cannot see that.
|
|
84
|
+
* Session 01a00337 stored the same status sentence concatenated with no space (`Foo.Foo.`)
|
|
85
|
+
* because Responses deltas replayed the full sentence; whitespace split cannot see that.
|
|
86
|
+
*/
|
|
87
|
+
export function collapseRepeatedLines(text) {
|
|
88
|
+
const tiled = exactTiledRepeat(text);
|
|
89
|
+
const source = tiled ? tiled.unit : text;
|
|
90
|
+
const lineCollapsed = collapseRepeatedUnits(source.split("\n"), "\n");
|
|
91
|
+
return lineCollapsed
|
|
92
|
+
.split("\n")
|
|
93
|
+
.map((line) => {
|
|
94
|
+
const lineTile = exactTiledRepeat(line);
|
|
95
|
+
return collapseRepeatedUnits(splitSentences(lineTile ? lineTile.unit : line), " ");
|
|
96
|
+
})
|
|
97
|
+
.join("\n");
|
|
98
|
+
}
|
|
99
|
+
export function isDegenerateRepeatedText(text) {
|
|
100
|
+
return collapseRepeatedLines(text) !== text;
|
|
101
|
+
}
|
|
102
|
+
export function shouldAbortDegenerateStream(text) {
|
|
103
|
+
if (text.length < 400)
|
|
104
|
+
return false;
|
|
105
|
+
const tiled = exactTiledRepeat(text);
|
|
106
|
+
if (tiled && tiled.times >= DEGENERATE_STREAM_ABORT_RUN)
|
|
107
|
+
return true;
|
|
108
|
+
const sentences = splitSentences(text);
|
|
109
|
+
if (maxRepeatedUnitRun(sentences) >= DEGENERATE_STREAM_ABORT_RUN)
|
|
110
|
+
return true;
|
|
111
|
+
return maxRepeatedUnitRun(text.split("\n")) >= DEGENERATE_STREAM_ABORT_RUN;
|
|
112
|
+
}
|
|
113
|
+
const collapsedDegenerateMessages = new WeakSet();
|
|
114
|
+
export function collapseDegenerateAssistantMessage(message) {
|
|
115
|
+
let changed = false;
|
|
116
|
+
const seenText = new Set();
|
|
117
|
+
const content = [];
|
|
118
|
+
for (const block of message.content) {
|
|
119
|
+
if (block.type !== "text") {
|
|
120
|
+
content.push(block);
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const collapsed = collapseRepeatedLines(block.text);
|
|
124
|
+
if (collapsed !== block.text)
|
|
125
|
+
changed = true;
|
|
126
|
+
if (collapsed.trim() !== "" && seenText.has(collapsed)) {
|
|
127
|
+
changed = true;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (collapsed.trim() !== "")
|
|
131
|
+
seenText.add(collapsed);
|
|
132
|
+
content.push(collapsed === block.text ? block : { ...block, text: collapsed });
|
|
133
|
+
}
|
|
134
|
+
if (!changed)
|
|
135
|
+
return message;
|
|
136
|
+
const next = { ...message, content };
|
|
137
|
+
collapsedDegenerateMessages.add(next);
|
|
138
|
+
return next;
|
|
139
|
+
}
|
|
140
|
+
/** True when this message is (or was collapsed from) a generation loop. */
|
|
141
|
+
export function isCollapsedDegenerateAssistantMessage(message) {
|
|
142
|
+
return collapsedDegenerateMessages.has(message);
|
|
143
|
+
}
|
|
144
|
+
export function assistantMessageText(message) {
|
|
145
|
+
return message.content
|
|
146
|
+
.filter((block) => block.type === "text")
|
|
147
|
+
.map((block) => block.text)
|
|
148
|
+
.join("\n");
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=degenerate-assistant-text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"degenerate-assistant-text.js","sourceRoot":"","sources":["../src/degenerate-assistant-text.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"@caupulican/pi-ai/types\";\n\n/** Consecutive identical non-empty units (lines or sentences) at or above this run count are degeneration. */\nexport const DEGENERATE_REPEATED_LINE_MIN = 4;\n\n/** Mid-stream abort once a generation loop is already this long; cheaper than waiting for `done`. */\nexport const DEGENERATE_STREAM_ABORT_RUN = 8;\n\n/** Shortest unit that may be an exact tiled status sentence (`Foo.Foo.` with no space). */\nexport const DEGENERATE_EXACT_REPEAT_MIN = 24;\n\nfunction collapseRepeatedUnits(units: readonly string[], joinWith: string): string {\n\tif (units.length < DEGENERATE_REPEATED_LINE_MIN) return units.join(joinWith);\n\tconst out: string[] = [];\n\tlet index = 0;\n\twhile (index < units.length) {\n\t\tconst unit = units[index];\n\t\tlet run = 1;\n\t\twhile (index + run < units.length && units[index + run] === unit) run++;\n\t\tif (unit.trim() !== \"\" && run >= DEGENERATE_REPEATED_LINE_MIN) {\n\t\t\tout.push(unit);\n\t\t\tindex += run;\n\t\t\tcontinue;\n\t\t}\n\t\tif (index + 1 < units.length) {\n\t\t\tconst next = units[index + 1];\n\t\t\tif (unit.trim() !== \"\" && next.trim() !== \"\" && unit !== next) {\n\t\t\t\tlet pairs = 1;\n\t\t\t\twhile (\n\t\t\t\t\tindex + (pairs + 1) * 2 <= units.length &&\n\t\t\t\t\tunits[index + pairs * 2] === unit &&\n\t\t\t\t\tunits[index + pairs * 2 + 1] === next\n\t\t\t\t) {\n\t\t\t\t\tpairs++;\n\t\t\t\t}\n\t\t\t\tif (pairs >= DEGENERATE_REPEATED_LINE_MIN) {\n\t\t\t\t\tout.push(unit, next);\n\t\t\t\t\tindex += pairs * 2;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tout.push(unit);\n\t\tindex++;\n\t}\n\treturn out.join(joinWith);\n}\n\nfunction maxRepeatedUnitRun(units: readonly string[]): number {\n\tlet maxRun = 1;\n\tlet run = 1;\n\tfor (let index = 1; index < units.length; index++) {\n\t\tif (units[index] === units[index - 1] && units[index].trim() !== \"\") {\n\t\t\trun++;\n\t\t\tif (run > maxRun) maxRun = run;\n\t\t} else {\n\t\t\trun = 1;\n\t\t}\n\t}\n\treturn units.length === 0 ? 0 : maxRun;\n}\n\nfunction splitSentences(text: string): string[] {\n\treturn text.split(/(?<=[.!?])\\s+/);\n}\n\nfunction isProseTile(unit: string): boolean {\n\treturn /[.!?]/.test(unit) || /\\s/.test(unit);\n}\n\n/** Smallest power-of-two prose tile that repeats to `text` (`Foo.Foo.` / `Foo.`×4). */\nexport function exactTiledRepeat(text: string): { unit: string; times: number } | undefined {\n\tif (text.length < DEGENERATE_EXACT_REPEAT_MIN * 2) return undefined;\n\tlet unit = text;\n\tlet times = 1;\n\twhile (unit.length >= DEGENERATE_EXACT_REPEAT_MIN * 2 && unit.length % 2 === 0) {\n\t\tconst half = unit.length / 2;\n\t\tconst next = unit.slice(0, half);\n\t\tif (!isProseTile(next) || next !== unit.slice(half)) break;\n\t\tunit = next;\n\t\ttimes *= 2;\n\t}\n\treturn times > 1 ? { unit, times } : undefined;\n}\n\n/**\n * Collapse consecutive identical assistant lines, period-2 ABAB line runs, and the same\n * sentence repeated inside one paragraph. Session 01a0016f stored 551 copies of one\n * sentence as a single line; newline-only collapse cannot see that.\n * Session 01a00337 stored the same status sentence concatenated with no space (`Foo.Foo.`)\n * because Responses deltas replayed the full sentence; whitespace split cannot see that.\n */\nexport function collapseRepeatedLines(text: string): string {\n\tconst tiled = exactTiledRepeat(text);\n\tconst source = tiled ? tiled.unit : text;\n\tconst lineCollapsed = collapseRepeatedUnits(source.split(\"\\n\"), \"\\n\");\n\treturn lineCollapsed\n\t\t.split(\"\\n\")\n\t\t.map((line) => {\n\t\t\tconst lineTile = exactTiledRepeat(line);\n\t\t\treturn collapseRepeatedUnits(splitSentences(lineTile ? lineTile.unit : line), \" \");\n\t\t})\n\t\t.join(\"\\n\");\n}\n\nexport function isDegenerateRepeatedText(text: string): boolean {\n\treturn collapseRepeatedLines(text) !== text;\n}\n\nexport function shouldAbortDegenerateStream(text: string): boolean {\n\tif (text.length < 400) return false;\n\tconst tiled = exactTiledRepeat(text);\n\tif (tiled && tiled.times >= DEGENERATE_STREAM_ABORT_RUN) return true;\n\tconst sentences = splitSentences(text);\n\tif (maxRepeatedUnitRun(sentences) >= DEGENERATE_STREAM_ABORT_RUN) return true;\n\treturn maxRepeatedUnitRun(text.split(\"\\n\")) >= DEGENERATE_STREAM_ABORT_RUN;\n}\n\nconst collapsedDegenerateMessages = new WeakSet<AssistantMessage>();\n\nexport function collapseDegenerateAssistantMessage(message: AssistantMessage): AssistantMessage {\n\tlet changed = false;\n\tconst seenText = new Set<string>();\n\tconst content: AssistantMessage[\"content\"] = [];\n\tfor (const block of message.content) {\n\t\tif (block.type !== \"text\") {\n\t\t\tcontent.push(block);\n\t\t\tcontinue;\n\t\t}\n\t\tconst collapsed = collapseRepeatedLines(block.text);\n\t\tif (collapsed !== block.text) changed = true;\n\t\tif (collapsed.trim() !== \"\" && seenText.has(collapsed)) {\n\t\t\tchanged = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (collapsed.trim() !== \"\") seenText.add(collapsed);\n\t\tcontent.push(collapsed === block.text ? block : { ...block, text: collapsed });\n\t}\n\tif (!changed) return message;\n\tconst next = { ...message, content };\n\tcollapsedDegenerateMessages.add(next);\n\treturn next;\n}\n\n/** True when this message is (or was collapsed from) a generation loop. */\nexport function isCollapsedDegenerateAssistantMessage(message: AssistantMessage): boolean {\n\treturn collapsedDegenerateMessages.has(message);\n}\n\nexport function assistantMessageText(message: AssistantMessage): string {\n\treturn message.content\n\t\t.filter((block) => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(\"\\n\");\n}\n"]}
|
|
@@ -37,16 +37,14 @@ export interface ToolFailureDirectiveDetails {
|
|
|
37
37
|
}
|
|
38
38
|
export type ToolFailureResultDetails = ToolFailureMemoryDetails | ToolFailureDirectiveDetails;
|
|
39
39
|
export type ToolFailureMemoryTracker = Map<string, ToolFailureMemoryRecord>;
|
|
40
|
-
/**
|
|
41
|
-
* Fingerprint a tool operation without materializing or retaining its serialized payload.
|
|
42
|
-
* Volatile identifiers normalize before hashing; short numbers and ordinary paths remain significant.
|
|
43
|
-
*/
|
|
44
40
|
export declare function normalizeToolSignature(pairs: Array<[string, unknown]>): string;
|
|
45
41
|
export declare function getToolExecutionKey(tool: string, args: unknown): string;
|
|
46
42
|
export declare function getToolFailureRecordExecutionKey(record: ToolFailureMemoryRecord): string | undefined;
|
|
47
43
|
export declare function getUnresolvedToolFailure(tracker: ToolFailureMemoryTracker, tool: string, args: unknown): ToolFailureMemoryRecord | undefined;
|
|
48
44
|
export declare function readVisibleToolFailureCode(result: ToolResultMessage): string | undefined;
|
|
49
45
|
export declare function isClosedOperationFailureCode(code: string | undefined): boolean;
|
|
46
|
+
/** Failures that only a new owner prompt can clear. Do not restore their circuit across user turns. */
|
|
47
|
+
export declare function isPromptScopedFailureCode(code: string | undefined): boolean;
|
|
50
48
|
export declare function restoreToolFailureRecord(result: ToolResultMessage, tool: string, args: unknown): ToolFailureMemoryRecord;
|
|
51
49
|
export interface PairedToolResult {
|
|
52
50
|
tool: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-failure-memory.d.ts","sourceRoot":"","sources":["../src/tool-failure-memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,KAAK,gBAAgB,EACrB,MAAM,wCAAwC,CAAC;AAChD,OAAO,KAAK,EAAoB,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAKnF,OAAO,KAAK,EAAE,YAAY,EAAiB,eAAe,EAAE,MAAM,YAAY,CAAC;AAG/E,QAAA,MAAM,2BAA2B,IAAI,CAAC;AACtC,QAAA,MAAM,8BAA8B,IAAI,CAAC;AACzC,QAAA,MAAM,0BAA0B,eAAoC,CAAC;AAiBrE,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,UAAU,CAAC;AAErD,MAAM,WAAW,uBAAuB;IACvC,OAAO,EAAE,OAAO,2BAA2B,CAAC;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,qFAAqF;IACrF,QAAQ,CAAC,CAAC,0BAA0B,CAAC,CAAC,EAAE,MAAM,CAAC;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,gBAAgB,CAAC;IACxB,KAAK,EAAE,gBAAgB,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,SAAS,CAAC;CAC1B;AAED,MAAM,WAAW,wBAAwB;IACxC,mBAAmB,EAAE,uBAAuB,CAAC;CAC7C;AAED,MAAM,WAAW,2BAA2B;IAC3C,sBAAsB,EAAE;QACvB,OAAO,EAAE,OAAO,8BAA8B,CAAC;QAC/C,KAAK,EAAE,gBAAgB,CAAC;QACxB,KAAK,EAAE,gBAAgB,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;KACnB,CAAC;CACF;AAED,MAAM,MAAM,wBAAwB,GAAG,wBAAwB,GAAG,2BAA2B,CAAC;AAE9F,MAAM,MAAM,wBAAwB,GAAG,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"tool-failure-memory.d.ts","sourceRoot":"","sources":["../src/tool-failure-memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,KAAK,gBAAgB,EACrB,MAAM,wCAAwC,CAAC;AAChD,OAAO,KAAK,EAAoB,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAKnF,OAAO,KAAK,EAAE,YAAY,EAAiB,eAAe,EAAE,MAAM,YAAY,CAAC;AAG/E,QAAA,MAAM,2BAA2B,IAAI,CAAC;AACtC,QAAA,MAAM,8BAA8B,IAAI,CAAC;AACzC,QAAA,MAAM,0BAA0B,eAAoC,CAAC;AAiBrE,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,UAAU,CAAC;AAErD,MAAM,WAAW,uBAAuB;IACvC,OAAO,EAAE,OAAO,2BAA2B,CAAC;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,qFAAqF;IACrF,QAAQ,CAAC,CAAC,0BAA0B,CAAC,CAAC,EAAE,MAAM,CAAC;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,gBAAgB,CAAC;IACxB,KAAK,EAAE,gBAAgB,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,SAAS,CAAC;CAC1B;AAED,MAAM,WAAW,wBAAwB;IACxC,mBAAmB,EAAE,uBAAuB,CAAC;CAC7C;AAED,MAAM,WAAW,2BAA2B;IAC3C,sBAAsB,EAAE;QACvB,OAAO,EAAE,OAAO,8BAA8B,CAAC;QAC/C,KAAK,EAAE,gBAAgB,CAAC;QACxB,KAAK,EAAE,gBAAgB,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;KACnB,CAAC;CACF;AAED,MAAM,MAAM,wBAAwB,GAAG,wBAAwB,GAAG,2BAA2B,CAAC;AAE9F,MAAM,MAAM,wBAAwB,GAAG,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;AAgT5E,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAK9E;AA8BD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAEvE;AAED,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,uBAAuB,GAAG,MAAM,GAAG,SAAS,CAEpG;AAED,wBAAgB,wBAAwB,CACvC,OAAO,EAAE,wBAAwB,EACjC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,GACX,uBAAuB,GAAG,SAAS,CAErC;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,GAAG,SAAS,CAOxF;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAE9E;AAED,uGAAuG;AACvG,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAE3E;AAED,wBAAgB,wBAAwB,CACvC,MAAM,EAAE,iBAAiB,EACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,GACX,uBAAuB,CAsBzB;AAED,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,iBAAiB,CAAC;CAC1B;AAED,wBAAgB,uBAAuB,CACtC,QAAQ,EAAE,SAAS,YAAY,EAAE,EACjC,KAAK,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,OAAO,GAAG,SAAS,GACpD,IAAI,CAyBN;AAED,wBAAgB,gCAAgC,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,GAAG,OAAO,CAY3F;AA+BD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAOhF;AAqDD,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,gBAAgB,EACvB,KAAK,GAAE,gBAAoE,GACzE,MAAM,CAKR;AAqDD,MAAM,WAAW,qBAAqB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,gBAAgB,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,SAAS,CAAC;CAC1B;AAED,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,gBAAgB,EACvB,UAAU,CAAC,EAAE,MAAM,GACjB,qBAAqB,CAsBvB;AA+ED,MAAM,WAAW,oBAAoB;IACpC,KAAK,EAAE,gBAAgB,CAAC;IACxB,KAAK,EAAE,gBAAgB,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,gHAAgH;AAChH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,oBAAoB,GAAG,SAAS,CAoB3F;AA4LD,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,wBAAwB,CAEjG;AAED,wBAAgB,mBAAmB,CAClC,OAAO,EAAE,wBAAwB,EACjC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,gBAAgB,EACvB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM,EACnB,KAAK,GAAE,gBAA4D,GACjE,uBAAuB,CAqDzB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,wBAAwB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAKrG;AA2BD,wBAAgB,uBAAuB,CACtC,MAAM,EAAE,uBAAuB,EAC/B,SAAS,CAAC,EAAE,OAAO,GACjB,eAAe,CAAC,wBAAwB,CAAC,CAuB3C;AAED,wBAAgB,+BAA+B,CAC9C,MAAM,EAAE,uBAAuB,GAC7B,eAAe,CAAC,wBAAwB,CAAC,CAsB3C;AAED,wBAAgB,wCAAwC,CACvD,MAAM,EAAE,uBAAuB,EAC/B,UAAU,EAAE,MAAM,GAChB,eAAe,CAAC,wBAAwB,CAAC,CAiB3C;AAED,wBAAgB,yCAAyC,CACxD,MAAM,EAAE,uBAAuB,EAC/B,UAAU,EAAE,MAAM,GAChB,eAAe,CAAC,wBAAwB,CAAC,CAkB3C;AAcD,wBAAgB,0BAA0B,CACzC,QAAQ,EAAE,YAAY,EAAE,EACxB,YAAY,EAAE,MAAM,GAClB;IAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAqCpD"}
|
|
@@ -243,10 +243,49 @@ function boundedJsonPreview(value, maxChars) {
|
|
|
243
243
|
* Fingerprint a tool operation without materializing or retaining its serialized payload.
|
|
244
244
|
* Volatile identifiers normalize before hashing; short numbers and ordinary paths remain significant.
|
|
245
245
|
*/
|
|
246
|
+
/**
|
|
247
|
+
* Resource-envelope fields are not the operation. Changing `timeout` (or a sibling wait bound)
|
|
248
|
+
* must not mint a new execution identity — that is how a failed command is replayed forever.
|
|
249
|
+
*/
|
|
250
|
+
const OPERATION_ENVELOPE_KEYS = new Set([
|
|
251
|
+
"timeout",
|
|
252
|
+
"timeoutms",
|
|
253
|
+
"timeout_ms",
|
|
254
|
+
"timeoutsec",
|
|
255
|
+
"timeout_sec",
|
|
256
|
+
"timeoutseconds",
|
|
257
|
+
"timeout_seconds",
|
|
258
|
+
"maxwait",
|
|
259
|
+
"max_wait",
|
|
260
|
+
"maxwaitms",
|
|
261
|
+
"max_wait_ms",
|
|
262
|
+
"waitms",
|
|
263
|
+
"wait_ms",
|
|
264
|
+
"waitsec",
|
|
265
|
+
"wait_sec",
|
|
266
|
+
"waitseconds",
|
|
267
|
+
"wait_seconds",
|
|
268
|
+
]);
|
|
269
|
+
function omitOperationEnvelopeFields(value) {
|
|
270
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
271
|
+
return value;
|
|
272
|
+
const record = value;
|
|
273
|
+
let changed = false;
|
|
274
|
+
const next = {};
|
|
275
|
+
for (const [key, entry] of Object.entries(record)) {
|
|
276
|
+
if (OPERATION_ENVELOPE_KEYS.has(key.toLowerCase())) {
|
|
277
|
+
changed = true;
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
next[key] = entry;
|
|
281
|
+
}
|
|
282
|
+
return changed ? next : value;
|
|
283
|
+
}
|
|
246
284
|
export function normalizeToolSignature(pairs) {
|
|
247
|
-
return structuredHash(pairs, true);
|
|
285
|
+
return structuredHash(pairs.map(([name, args]) => [name, omitOperationEnvelopeFields(args)]), true);
|
|
248
286
|
}
|
|
249
287
|
function toolOperationKey(tool, args, normalizeVolatile) {
|
|
288
|
+
const identityArgs = omitOperationEnvelopeFields(args);
|
|
250
289
|
const boundedTool = truncate(tool, MAX_TOOL_NAME_CHARS);
|
|
251
290
|
const hash = createSignatureHash();
|
|
252
291
|
const updateHashString = normalizeVolatile ? updateNormalizedHashString : updateExactHashString;
|
|
@@ -254,7 +293,7 @@ function toolOperationKey(tool, args, normalizeVolatile) {
|
|
|
254
293
|
// Preserve the stable structured-hash wire identity without allocating the two synthetic arrays.
|
|
255
294
|
updateHashRange(hash, "array:1[array:2[");
|
|
256
295
|
updateStructuredHash(hash, tool, active, 2, updateHashString);
|
|
257
|
-
updateStructuredHash(hash,
|
|
296
|
+
updateStructuredHash(hash, identityArgs, active, 2, updateHashString);
|
|
258
297
|
updateHashRange(hash, "];];");
|
|
259
298
|
const signature = renderSignatureHash(hash);
|
|
260
299
|
return `${boundedTool}:${signature}`;
|
|
@@ -292,6 +331,10 @@ export function readVisibleToolFailureCode(result) {
|
|
|
292
331
|
export function isClosedOperationFailureCode(code) {
|
|
293
332
|
return code === "operation_recovery_exhausted" || code === "recovery_exhausted";
|
|
294
333
|
}
|
|
334
|
+
/** Failures that only a new owner prompt can clear. Do not restore their circuit across user turns. */
|
|
335
|
+
export function isPromptScopedFailureCode(code) {
|
|
336
|
+
return code === "owner_authorization_required";
|
|
337
|
+
}
|
|
295
338
|
export function restoreToolFailureRecord(result, tool, args) {
|
|
296
339
|
const executionKey = getToolExecutionKey(tool, args);
|
|
297
340
|
const persisted = readFailureRecord(result.details);
|
|
@@ -404,8 +447,11 @@ function inferToolFailurePhase(state, failureCode) {
|
|
|
404
447
|
if (failureCode === "malformed_call" || failureCode === "unknown_tool" || failureCode === "invalid_arguments") {
|
|
405
448
|
return "validation";
|
|
406
449
|
}
|
|
407
|
-
if (failureCode === "blocked" ||
|
|
450
|
+
if (failureCode === "blocked" ||
|
|
451
|
+
failureCode === "permission_denied" ||
|
|
452
|
+
failureCode === "owner_authorization_required") {
|
|
408
453
|
return "policy";
|
|
454
|
+
}
|
|
409
455
|
if (failureCode === "preflight_error")
|
|
410
456
|
return "preflight";
|
|
411
457
|
if (failureCode === "aborted" || failureCode === "cancelled")
|