@caupulican/pi-agent-core 0.90.11 → 0.91.2

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.
@@ -0,0 +1,18 @@
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
+ /**
7
+ * Collapse consecutive identical assistant lines, period-2 ABAB line runs, and the same
8
+ * sentence repeated inside one paragraph. Session 01a0016f stored 551 copies of one
9
+ * sentence as a single line; newline-only collapse cannot see that.
10
+ */
11
+ export declare function collapseRepeatedLines(text: string): string;
12
+ export declare function isDegenerateRepeatedText(text: string): boolean;
13
+ export declare function shouldAbortDegenerateStream(text: string): boolean;
14
+ export declare function collapseDegenerateAssistantMessage(message: AssistantMessage): AssistantMessage;
15
+ /** True when this message is (or was collapsed from) a generation loop. */
16
+ export declare function isCollapsedDegenerateAssistantMessage(message: AssistantMessage): boolean;
17
+ export declare function assistantMessageText(message: AssistantMessage): string;
18
+ //# 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;AAyD7C;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAKjE;AAID,wBAAgB,kCAAkC,CAAC,OAAO,EAAE,gBAAgB,GAAG,gBAAgB,CAa9F;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,110 @@
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
+ function collapseRepeatedUnits(units, joinWith) {
6
+ if (units.length < DEGENERATE_REPEATED_LINE_MIN)
7
+ return units.join(joinWith);
8
+ const out = [];
9
+ let index = 0;
10
+ while (index < units.length) {
11
+ const unit = units[index];
12
+ let run = 1;
13
+ while (index + run < units.length && units[index + run] === unit)
14
+ run++;
15
+ if (unit.trim() !== "" && run >= DEGENERATE_REPEATED_LINE_MIN) {
16
+ out.push(unit);
17
+ index += run;
18
+ continue;
19
+ }
20
+ if (index + 1 < units.length) {
21
+ const next = units[index + 1];
22
+ if (unit.trim() !== "" && next.trim() !== "" && unit !== next) {
23
+ let pairs = 1;
24
+ while (index + (pairs + 1) * 2 <= units.length &&
25
+ units[index + pairs * 2] === unit &&
26
+ units[index + pairs * 2 + 1] === next) {
27
+ pairs++;
28
+ }
29
+ if (pairs >= DEGENERATE_REPEATED_LINE_MIN) {
30
+ out.push(unit, next);
31
+ index += pairs * 2;
32
+ continue;
33
+ }
34
+ }
35
+ }
36
+ out.push(unit);
37
+ index++;
38
+ }
39
+ return out.join(joinWith);
40
+ }
41
+ function maxRepeatedUnitRun(units) {
42
+ let maxRun = 1;
43
+ let run = 1;
44
+ for (let index = 1; index < units.length; index++) {
45
+ if (units[index] === units[index - 1] && units[index].trim() !== "") {
46
+ run++;
47
+ if (run > maxRun)
48
+ maxRun = run;
49
+ }
50
+ else {
51
+ run = 1;
52
+ }
53
+ }
54
+ return units.length === 0 ? 0 : maxRun;
55
+ }
56
+ function splitSentences(text) {
57
+ return text.split(/(?<=[.!?])\s+/);
58
+ }
59
+ /**
60
+ * Collapse consecutive identical assistant lines, period-2 ABAB line runs, and the same
61
+ * sentence repeated inside one paragraph. Session 01a0016f stored 551 copies of one
62
+ * sentence as a single line; newline-only collapse cannot see that.
63
+ */
64
+ export function collapseRepeatedLines(text) {
65
+ const lineCollapsed = collapseRepeatedUnits(text.split("\n"), "\n");
66
+ return lineCollapsed
67
+ .split("\n")
68
+ .map((line) => collapseRepeatedUnits(splitSentences(line), " "))
69
+ .join("\n");
70
+ }
71
+ export function isDegenerateRepeatedText(text) {
72
+ return collapseRepeatedLines(text) !== text;
73
+ }
74
+ export function shouldAbortDegenerateStream(text) {
75
+ if (text.length < 400)
76
+ return false;
77
+ const sentences = splitSentences(text);
78
+ if (maxRepeatedUnitRun(sentences) >= DEGENERATE_STREAM_ABORT_RUN)
79
+ return true;
80
+ return maxRepeatedUnitRun(text.split("\n")) >= DEGENERATE_STREAM_ABORT_RUN;
81
+ }
82
+ const collapsedDegenerateMessages = new WeakSet();
83
+ export function collapseDegenerateAssistantMessage(message) {
84
+ let changed = false;
85
+ const content = message.content.map((block) => {
86
+ if (block.type !== "text")
87
+ return block;
88
+ const collapsed = collapseRepeatedLines(block.text);
89
+ if (collapsed === block.text)
90
+ return block;
91
+ changed = true;
92
+ return { ...block, text: collapsed };
93
+ });
94
+ if (!changed)
95
+ return message;
96
+ const next = { ...message, content };
97
+ collapsedDegenerateMessages.add(next);
98
+ return next;
99
+ }
100
+ /** True when this message is (or was collapsed from) a generation loop. */
101
+ export function isCollapsedDegenerateAssistantMessage(message) {
102
+ return collapsedDegenerateMessages.has(message);
103
+ }
104
+ export function assistantMessageText(message) {
105
+ return message.content
106
+ .filter((block) => block.type === "text")
107
+ .map((block) => block.text)
108
+ .join("\n");
109
+ }
110
+ //# 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\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\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 */\nexport function collapseRepeatedLines(text: string): string {\n\tconst lineCollapsed = collapseRepeatedUnits(text.split(\"\\n\"), \"\\n\");\n\treturn lineCollapsed\n\t\t.split(\"\\n\")\n\t\t.map((line) => collapseRepeatedUnits(splitSentences(line), \" \"))\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 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 content = message.content.map((block) => {\n\t\tif (block.type !== \"text\") return block;\n\t\tconst collapsed = collapseRepeatedLines(block.text);\n\t\tif (collapsed === block.text) return block;\n\t\tchanged = true;\n\t\treturn { ...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"]}
@@ -1,4 +1,5 @@
1
1
  import { type ToolFailurePhase } from "@caupulican/pi-ai/tool-repair-registry";
2
+ import type { ToolResultMessage } from "@caupulican/pi-ai/types";
2
3
  import type { AgentMessage, AgentToolResult } from "./types.ts";
3
4
  declare const TOOL_FAILURE_MEMORY_VERSION = 1;
4
5
  declare const TOOL_FAILURE_DIRECTIVE_VERSION = 1;
@@ -36,14 +37,23 @@ export interface ToolFailureDirectiveDetails {
36
37
  }
37
38
  export type ToolFailureResultDetails = ToolFailureMemoryDetails | ToolFailureDirectiveDetails;
38
39
  export type ToolFailureMemoryTracker = Map<string, ToolFailureMemoryRecord>;
39
- /**
40
- * Fingerprint a tool operation without materializing or retaining its serialized payload.
41
- * Volatile identifiers normalize before hashing; short numbers and ordinary paths remain significant.
42
- */
43
40
  export declare function normalizeToolSignature(pairs: Array<[string, unknown]>): string;
44
41
  export declare function getToolExecutionKey(tool: string, args: unknown): string;
45
42
  export declare function getToolFailureRecordExecutionKey(record: ToolFailureMemoryRecord): string | undefined;
46
43
  export declare function getUnresolvedToolFailure(tracker: ToolFailureMemoryTracker, tool: string, args: unknown): ToolFailureMemoryRecord | undefined;
44
+ export declare function readVisibleToolFailureCode(result: ToolResultMessage): string | undefined;
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;
48
+ export declare function restoreToolFailureRecord(result: ToolResultMessage, tool: string, args: unknown): ToolFailureMemoryRecord;
49
+ export interface PairedToolResult {
50
+ tool: string;
51
+ args: unknown;
52
+ executionKey: string;
53
+ result: ToolResultMessage;
54
+ }
55
+ export declare function forEachPairedToolResult(messages: readonly AgentMessage[], visit: (pair: PairedToolResult) => boolean | undefined): void;
56
+ export declare function transcriptHasClosedToolOperation(messages: readonly AgentMessage[]): boolean;
47
57
  export declare function classifyToolFailure(message: string, errorClass?: string): string;
48
58
  export declare function toolFailureCorrection(message: string, state: ToolFailureState, phase?: ToolFailurePhase): string;
49
59
  export interface ToolFailureAssessment {
@@ -1 +1 @@
1
- {"version":3,"file":"tool-failure-memory.d.ts","sourceRoot":"","sources":["../src/tool-failure-memory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tool-failure-memory.d.ts","sourceRoot":"","sources":["../src/tool-failure-memory.ts"],"names":[],"mappings":"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"}
@@ -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, args, active, 2, updateHashString);
296
+ updateStructuredHash(hash, identityArgs, active, 2, updateHashString);
258
297
  updateHashRange(hash, "];];");
259
298
  const signature = renderSignatureHash(hash);
260
299
  return `${boundedTool}:${signature}`;
@@ -279,6 +318,85 @@ export function getToolFailureRecordExecutionKey(record) {
279
318
  export function getUnresolvedToolFailure(tracker, tool, args) {
280
319
  return tracker.get(getToolFailureKey(tool, args));
281
320
  }
321
+ export function readVisibleToolFailureCode(result) {
322
+ for (const block of result.content) {
323
+ if (block.type !== "text")
324
+ continue;
325
+ const match = /"failure_code"\s*:\s*"([^"]+)"/.exec(block.text);
326
+ if (match)
327
+ return match[1];
328
+ }
329
+ return undefined;
330
+ }
331
+ export function isClosedOperationFailureCode(code) {
332
+ return code === "operation_recovery_exhausted" || code === "recovery_exhausted";
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
+ }
338
+ export function restoreToolFailureRecord(result, tool, args) {
339
+ const executionKey = getToolExecutionKey(tool, args);
340
+ const persisted = readFailureRecord(result.details);
341
+ if (persisted) {
342
+ return {
343
+ ...persisted,
344
+ [TOOL_FAILURE_EXECUTION_KEY]: getToolFailureRecordExecutionKey(persisted) ?? executionKey,
345
+ };
346
+ }
347
+ const identity = operationIdentity(tool, args);
348
+ return {
349
+ version: TOOL_FAILURE_MEMORY_VERSION,
350
+ failureKey: identity.failureKey,
351
+ [TOOL_FAILURE_EXECUTION_KEY]: executionKey,
352
+ tool: identity.tool,
353
+ operation: identity.operation,
354
+ occurrence: 1,
355
+ state: "failed",
356
+ phase: "execution",
357
+ failureCode: boundedFailureCode(readVisibleToolFailureCode(result) ?? "tool_error"),
358
+ correction: fallbackFailureGuidance("failed", false, "execution"),
359
+ };
360
+ }
361
+ export function forEachPairedToolResult(messages, visit) {
362
+ const callsById = new Map();
363
+ for (const message of messages) {
364
+ if (message.role === "assistant") {
365
+ for (const block of message.content) {
366
+ if (block.type === "toolCall") {
367
+ callsById.set(block.id, { name: block.name, args: block.arguments });
368
+ }
369
+ }
370
+ continue;
371
+ }
372
+ if (message.role !== "toolResult")
373
+ continue;
374
+ const call = callsById.get(message.toolCallId);
375
+ if (!call)
376
+ continue;
377
+ if (visit({
378
+ tool: call.name,
379
+ args: call.args,
380
+ executionKey: getToolExecutionKey(call.name, call.args),
381
+ result: message,
382
+ }) === false) {
383
+ return;
384
+ }
385
+ }
386
+ }
387
+ export function transcriptHasClosedToolOperation(messages) {
388
+ const closedByExecutionKey = new Map();
389
+ forEachPairedToolResult(messages, ({ executionKey, result }) => {
390
+ if (!result.isError) {
391
+ closedByExecutionKey.delete(executionKey);
392
+ return;
393
+ }
394
+ if (isClosedOperationFailureCode(readVisibleToolFailureCode(result))) {
395
+ closedByExecutionKey.set(executionKey, true);
396
+ }
397
+ });
398
+ return closedByExecutionKey.size > 0;
399
+ }
282
400
  function boundedFailureCode(value) {
283
401
  const normalized = value
284
402
  .trim()
@@ -329,8 +447,11 @@ function inferToolFailurePhase(state, failureCode) {
329
447
  if (failureCode === "malformed_call" || failureCode === "unknown_tool" || failureCode === "invalid_arguments") {
330
448
  return "validation";
331
449
  }
332
- if (failureCode === "blocked" || failureCode === "permission_denied")
450
+ if (failureCode === "blocked" ||
451
+ failureCode === "permission_denied" ||
452
+ failureCode === "owner_authorization_required") {
333
453
  return "policy";
454
+ }
334
455
  if (failureCode === "preflight_error")
335
456
  return "preflight";
336
457
  if (failureCode === "aborted" || failureCode === "cancelled")