@caupulican/pi-agent-core 0.93.7 → 0.93.9

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.
@@ -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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"}
@@ -1,5 +1,5 @@
1
1
  import { getToolExecutionAttemptMemory, getToolExecutionErrorPolicy, } from "@caupulican/pi-ai/tool-repair-registry";
2
- import { MANDATORY_TOOL_FAILURE_RECOVERY_PROTOCOL_PROMPT, mandatoryToolFailureRecoveryMetadata, } from "./tool-failure-recovery-protocol.js";
2
+ import { MANDATORY_TOOL_FAILURE_RECOVERY_PROTOCOL_PROMPT, mandatoryToolFailureRecoveryMetadata, TOOL_FAILURE_READMISSION_RULE, } from "./tool-failure-recovery-protocol.js";
3
3
  import { sanitizeBinaryOutput } from "./utils/shell-output.js";
4
4
  const TOOL_FAILURE_MEMORY_VERSION = 1;
5
5
  const TOOL_FAILURE_DIRECTIVE_VERSION = 1;
@@ -9,15 +9,16 @@ const MAX_FAILURE_CODE_CHARS = 48;
9
9
  const MAX_DIAGNOSTIC_CHARS = 240;
10
10
  const MAX_CORRECTION_CHARS = 480;
11
11
  const MAX_TOOL_FAILURE_EVIDENCE_CHARS = 1_600;
12
- const MAX_ACTIVE_FAILURE_EVIDENCE_CHARS = 2_400;
13
12
  const MAX_TOOL_NAME_CHARS = 64;
14
13
  const TOOL_SIGNATURE_HEX_CHARS = 32;
14
+ const TOOL_FALLBACK_OUTPUT_SIGNATURE_BASE62_CHARS = 22;
15
+ const TOOL_OUTPUT_SIGNATURE_BASE64URL_CHARS = 43;
16
+ const LEGACY_TOOL_OUTPUT_SIGNATURE_HEX_CHARS = 64;
15
17
  const MAX_ACTIVE_FAILURES = 8;
16
18
  const MAX_TRACKED_FAILURES = 64;
17
19
  const REPAIRABLE_REJECTION_CODES = new Set(["invalid_arguments", "malformed_call", "unknown_tool"]);
18
20
  const LEGACY_GENERIC_EXECUTION_CORRECTION = "Change the arguments or approach before retrying; do not resend the unchanged operation.";
19
- const BLOCKED_REPLAY_CAVEMAN_CORRECTION = "Blocked: this exact operation will not run again this session change the operation or continue other work.";
20
- const CLOSED_OPERATION_CAVEMAN_CORRECTION = "Closed: this exact operation was not executed and will not run again this session — use a different operation or continue other work.";
21
+ const BLOCKED_REPLAY_CORRECTION = `Not executed: its last result is already above. Do corrective work or use a different operation. ${TOOL_FAILURE_READMISSION_RULE}`;
21
22
  function truncate(value, maxChars) {
22
23
  if (value.length <= maxChars)
23
24
  return value;
@@ -165,10 +166,29 @@ function renderSignatureHash(hash) {
165
166
  .map((part) => (part >>> 0).toString(16).padStart(8, "0"))
166
167
  .join("");
167
168
  }
168
- function structuredHash(value, normalizeVolatile) {
169
+ const COMPACT_SIGNATURE_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
170
+ function renderCompactSignatureHash(hash) {
171
+ let remaining = (BigInt(hash.first >>> 0) << 96n) |
172
+ (BigInt(hash.second >>> 0) << 64n) |
173
+ (BigInt(hash.third >>> 0) << 32n) |
174
+ BigInt(hash.fourth >>> 0);
175
+ let output = "";
176
+ for (let index = 0; index < TOOL_FALLBACK_OUTPUT_SIGNATURE_BASE62_CHARS; index++) {
177
+ output = COMPACT_SIGNATURE_ALPHABET[Number(remaining % 62n)] + output;
178
+ remaining /= 62n;
179
+ }
180
+ return output;
181
+ }
182
+ function calculateStructuredHash(value, normalizeVolatile) {
169
183
  const hash = createSignatureHash();
170
184
  updateStructuredHash(hash, value, new Set(), 0, normalizeVolatile ? updateNormalizedHashString : updateExactHashString);
171
- return renderSignatureHash(hash);
185
+ return hash;
186
+ }
187
+ function structuredHash(value, normalizeVolatile) {
188
+ return renderSignatureHash(calculateStructuredHash(value, normalizeVolatile));
189
+ }
190
+ function structuredOutputSignature(output) {
191
+ return renderCompactSignatureHash(calculateStructuredHash(output, false));
172
192
  }
173
193
  function boundedJsonPreview(value, maxChars) {
174
194
  let output = "";
@@ -351,9 +371,6 @@ export function readVisibleToolFailureCode(result) {
351
371
  }
352
372
  return undefined;
353
373
  }
354
- export function isClosedOperationFailureCode(code) {
355
- return code === "operation_recovery_exhausted" || code === "recovery_exhausted";
356
- }
357
374
  /** Failures that only a new owner prompt can clear. Do not restore their circuit across user turns. */
358
375
  export function isPromptScopedFailureCode(code) {
359
376
  return code === "owner_authorization_required";
@@ -368,6 +385,10 @@ export function restoreToolFailureRecord(result, tool, args) {
368
385
  };
369
386
  }
370
387
  const identity = operationIdentity(tool, args);
388
+ // A completed operation that reported a negative status keeps its own raw output, so there is no
389
+ // harness record to read back. Recover its terminal status from that output rather than flattening
390
+ // every such result to a generic `tool_error`.
391
+ const visibleCode = readVisibleToolFailureCode(result);
371
392
  return {
372
393
  version: TOOL_FAILURE_MEMORY_VERSION,
373
394
  failureKey: identity.failureKey,
@@ -377,7 +398,7 @@ export function restoreToolFailureRecord(result, tool, args) {
377
398
  occurrence: 1,
378
399
  state: "failed",
379
400
  phase: "execution",
380
- failureCode: boundedFailureCode(readVisibleToolFailureCode(result) ?? "tool_error"),
401
+ failureCode: boundedFailureCode(visibleCode ?? classifyToolFailure(firstText(result))),
381
402
  correction: fallbackFailureGuidance("failed", false, "execution"),
382
403
  };
383
404
  }
@@ -407,19 +428,6 @@ export function forEachPairedToolResult(messages, visit) {
407
428
  }
408
429
  }
409
430
  }
410
- export function transcriptHasClosedToolOperation(messages) {
411
- const closedByExecutionKey = new Map();
412
- forEachPairedToolResult(messages, ({ executionKey, result }) => {
413
- if (!result.isError) {
414
- closedByExecutionKey.delete(executionKey);
415
- return;
416
- }
417
- if (isClosedOperationFailureCode(readVisibleToolFailureCode(result))) {
418
- closedByExecutionKey.set(executionKey, true);
419
- }
420
- });
421
- return closedByExecutionKey.size > 0;
422
- }
423
431
  function boundedFailureCode(value) {
424
432
  const normalized = value
425
433
  .trim()
@@ -619,6 +627,16 @@ export function assessToolFailure(message, state, errorClass) {
619
627
  function isRecord(value) {
620
628
  return typeof value === "object" && value !== null && !Array.isArray(value);
621
629
  }
630
+ function isOutputSignature(value) {
631
+ if (typeof value !== "string")
632
+ return false;
633
+ if (value.length === TOOL_FALLBACK_OUTPUT_SIGNATURE_BASE62_CHARS)
634
+ return /^[0-9A-Za-z]+$/.test(value);
635
+ if (value.length === TOOL_OUTPUT_SIGNATURE_BASE64URL_CHARS)
636
+ return /^[A-Za-z0-9_-]+$/.test(value);
637
+ return ((value.length === TOOL_SIGNATURE_HEX_CHARS || value.length === LEGACY_TOOL_OUTPUT_SIGNATURE_HEX_CHARS) &&
638
+ /^[0-9a-f]+$/.test(value));
639
+ }
622
640
  function readFailureRecord(details) {
623
641
  if (!isRecord(details) || !isRecord(details.piToolFailureMemory))
624
642
  return undefined;
@@ -635,6 +653,7 @@ function readFailureRecord(details) {
635
653
  return undefined;
636
654
  }
637
655
  const diagnostic = typeof candidate.diagnostic === "string" ? truncate(candidate.diagnostic, MAX_DIAGNOSTIC_CHARS) : undefined;
656
+ const outputSignature = isOutputSignature(candidate.outputSignature) ? candidate.outputSignature : undefined;
638
657
  const note = typeof candidate.note === "string" ? truncate(candidate.note, MAX_DIAGNOSTIC_CHARS) : undefined;
639
658
  const evidence = sanitizeToolFailureEvidence(candidate.evidence);
640
659
  const retainedCorrection = typeof candidate.correction === "string" ? truncate(candidate.correction, MAX_CORRECTION_CHARS) : undefined;
@@ -659,6 +678,7 @@ function readFailureRecord(details) {
659
678
  state: candidate.state,
660
679
  phase,
661
680
  failureCode: boundedFailureCode(candidate.failureCode),
681
+ outputSignature,
662
682
  diagnostic,
663
683
  note,
664
684
  evidence,
@@ -728,8 +748,18 @@ function fastTextSignature(text) {
728
748
  }
729
749
  function analyzeToolFailureContext(messages) {
730
750
  const callById = new Map();
751
+ /**
752
+ * A call the agent made is erased only in two cases: a superseded success, whose newer identical
753
+ * call is still present, and a discard-attempt directive, where the harness has taken ownership of
754
+ * the attempt and the original arguments must not come back — either because it holds the payload
755
+ * by reference (a retarget) or because replaying those bytes is itself the hazard (an encoding
756
+ * corruption). Never for an ordinary failure: being told to change an operation is unactionable
757
+ * once the operation itself is gone.
758
+ */
731
759
  const omittedCallIds = new Set();
732
- const orphanFailedResults = new Set();
760
+ const omittedResults = new Set();
761
+ /** Unbounded failure results to replace in place with their bounded record. */
762
+ const boundedReplacements = new Map();
733
763
  const active = new Map();
734
764
  const activeDirectives = new Map();
735
765
  let sequence = 0;
@@ -754,8 +784,18 @@ function analyzeToolFailureContext(messages) {
754
784
  const call = callById.get(message.toolCallId);
755
785
  callById.delete(message.toolCallId);
756
786
  const textPayload = firstText(message);
757
- const isFailure = message.isError === true || textPayload.startsWith("[harness] ");
758
- if (isFailure) {
787
+ // A completed operation reporting its own negative status is evidence, not a mistake: it never
788
+ // enters the ledger and its output stays exactly as the tool wrote it. It does resolve any
789
+ // earlier failure recorded for the same operation, though — a tool that could not run before
790
+ // has now run — so a transcript that predates this classification cannot keep an obsolete
791
+ // record active across the boundary.
792
+ if (message.errorKind === "operation_outcome") {
793
+ if (call)
794
+ active.delete(getToolFailureKey(call.name, call.arguments));
795
+ continue;
796
+ }
797
+ const isHarnessFailure = message.isError === true || textPayload.startsWith("[harness] ");
798
+ if (isHarnessFailure) {
759
799
  const toolName = call?.name ?? message.toolName;
760
800
  const kindCount = (kindMistakesMap.get(toolName) ?? 0) + 1;
761
801
  kindMistakesMap.set(toolName, kindCount);
@@ -763,10 +803,13 @@ function analyzeToolFailureContext(messages) {
763
803
  if (directive) {
764
804
  activeDirectives.delete(directive.failureCode);
765
805
  activeDirectives.set(directive.failureCode, directive);
806
+ // The harness has taken ownership of this attempt: the directive replaces it, and the
807
+ // original arguments must not reappear — a retarget keeps the payload by reference, and a
808
+ // corrupt payload must never be replayed at all. Either way the call comes out.
766
809
  if (call)
767
810
  omittedCallIds.add(call.id);
768
811
  else
769
- orphanFailedResults.add(message);
812
+ omittedResults.add(message);
770
813
  continue;
771
814
  }
772
815
  const retained = readFailureRecord(message.details);
@@ -805,6 +848,7 @@ function analyzeToolFailureContext(messages) {
805
848
  state,
806
849
  phase: retained?.phase ?? assessment?.phase ?? inferToolFailurePhase(state, "tool_error"),
807
850
  failureCode: retained?.failureCode ?? assessment?.failureCode ?? "tool_error",
851
+ outputSignature: retained ? retained.outputSignature : structuredOutputSignature(textPayload),
808
852
  diagnostic: retained?.diagnostic ?? assessment?.diagnostic,
809
853
  evidence: retained?.evidence,
810
854
  correction: retained?.correction ??
@@ -819,10 +863,12 @@ function analyzeToolFailureContext(messages) {
819
863
  break;
820
864
  active.delete(oldest);
821
865
  }
822
- if (call)
823
- omittedCallIds.add(call.id);
824
- else
825
- orphanFailedResults.add(message);
866
+ // A failure result written before this harness bounded its own output — a legacy transcript,
867
+ // or a host that set isError directly — can carry unbounded raw text. Bounding it in place
868
+ // is the same treatment createToolFailureResult gives a fresh failure, applied late; the
869
+ // call that produced it still stands.
870
+ if (!retained)
871
+ boundedReplacements.set(message, record);
826
872
  continue;
827
873
  }
828
874
  if (call) {
@@ -843,16 +889,26 @@ function analyzeToolFailureContext(messages) {
843
889
  }
844
890
  }
845
891
  const kindMistakesSummary = Object.fromEntries(kindMistakesMap);
846
- if (omittedCallIds.size === 0 && orphanFailedResults.size === 0) {
847
- return { messages, activeRecords: [], activeDirectives: [], kindMistakesSummary };
892
+ const activeRecords = [...active.values()]
893
+ .sort((left, right) => left.sequence - right.sequence)
894
+ .map(({ record }) => record);
895
+ if (omittedCallIds.size === 0 && omittedResults.size === 0 && boundedReplacements.size === 0) {
896
+ return { messages, activeRecords, activeDirectives: [...activeDirectives.values()], kindMistakesSummary };
848
897
  }
849
898
  const filteredMessages = [];
850
899
  for (let index = 0; index < messages.length; index++) {
851
900
  const message = messages[index];
852
901
  if (message.role === "toolResult") {
853
- if (omittedCallIds.has(message.toolCallId) || orphanFailedResults.has(message))
902
+ if (omittedCallIds.has(message.toolCallId) || omittedResults.has(message))
854
903
  continue;
855
- filteredMessages.push(message);
904
+ const bounded = boundedReplacements.get(message);
905
+ filteredMessages.push(bounded
906
+ ? {
907
+ ...message,
908
+ content: [{ type: "text", text: `[harness] ${formatRecordJson(bounded, false)}` }],
909
+ details: { piToolFailureMemory: bounded },
910
+ }
911
+ : message);
856
912
  continue;
857
913
  }
858
914
  if (message.role !== "assistant") {
@@ -884,9 +940,6 @@ function analyzeToolFailureContext(messages) {
884
940
  filteredMessages.push({ ...message, content: retainedContent });
885
941
  }
886
942
  }
887
- const activeRecords = [...active.values()]
888
- .sort((left, right) => left.sequence - right.sequence)
889
- .map(({ record }) => record);
890
943
  return {
891
944
  messages: filteredMessages,
892
945
  activeRecords,
@@ -897,7 +950,7 @@ function analyzeToolFailureContext(messages) {
897
950
  export function createToolFailureMemoryTracker(messages) {
898
951
  return new Map(analyzeToolFailureContext(messages).activeRecords.map((record) => [record.failureKey, record]));
899
952
  }
900
- export function rememberToolFailure(tracker, tool, args, state, failureCode, correction, diagnostic, phase = inferToolFailurePhase(state, failureCode), evidence) {
953
+ export function rememberToolFailure(tracker, tool, args, state, failureCode, correction, diagnostic, phase = inferToolFailurePhase(state, failureCode), evidence, outputIdentity) {
901
954
  let kindCount = 1;
902
955
  for (const previous of tracker.values()) {
903
956
  if (previous.tool === tool) {
@@ -925,6 +978,9 @@ export function rememberToolFailure(tracker, tool, args, state, failureCode, cor
925
978
  state,
926
979
  phase,
927
980
  failureCode: boundedFailureCode(failureCode),
981
+ outputSignature: isOutputSignature(outputIdentity?.outputSignature)
982
+ ? outputIdentity.outputSignature
983
+ : structuredOutputSignature(outputIdentity?.output ?? ""),
928
984
  diagnostic: diagnostic ? truncate(diagnostic, MAX_DIAGNOSTIC_CHARS) : undefined,
929
985
  evidence: sanitizeToolFailureEvidence(evidence),
930
986
  correction: truncate(correction, MAX_CORRECTION_CHARS),
@@ -944,6 +1000,29 @@ export function rememberToolFailure(tracker, tool, args, state, failureCode, cor
944
1000
  }
945
1001
  return record;
946
1002
  }
1003
+ /**
1004
+ * Describe a completed operation that reported a negative status, without recording it as a mistake.
1005
+ *
1006
+ * The tool did its job, so nothing enters failure memory, nothing rewrites the tool's output, and no
1007
+ * correction is owed. The record exists only so the repetition governor can name the operation if the
1008
+ * agent replays it while nothing has changed.
1009
+ */
1010
+ export function describeOperationOutcome(tool, args, failureCode, diagnostic) {
1011
+ const identity = operationIdentity(tool, args);
1012
+ return {
1013
+ version: TOOL_FAILURE_MEMORY_VERSION,
1014
+ failureKey: identity.failureKey,
1015
+ [TOOL_FAILURE_EXECUTION_KEY]: identity.executionKey,
1016
+ tool: identity.tool,
1017
+ operation: identity.operation,
1018
+ occurrence: 1,
1019
+ state: "failed",
1020
+ phase: "execution",
1021
+ failureCode: boundedFailureCode(failureCode),
1022
+ ...(diagnostic ? { diagnostic: truncate(diagnostic, MAX_DIAGNOSTIC_CHARS) } : {}),
1023
+ correction: BLOCKED_REPLAY_CORRECTION,
1024
+ };
1025
+ }
947
1026
  export function clearToolFailure(tracker, tool, args) {
948
1027
  const failureKey = getToolFailureKey(tool, args);
949
1028
  const record = tracker.get(failureKey);
@@ -1002,14 +1081,19 @@ export function createToolFailureResult(record, terminate) {
1002
1081
  }
1003
1082
  export function createRepeatedToolFailureResult(record) {
1004
1083
  const retainedRecord = retainBlockedToolFailure(record);
1005
- const replayNotice = truncateMiddle(`The unchanged operation was not executed. Unchanged replay blocked after ${record.failureCode}`, MAX_DIAGNOSTIC_CHARS);
1084
+ // The note states why this call did not run and what makes it runnable again; the retained
1085
+ // root-cause correction stays the next_action, because that is the actionable half. Evidence is
1086
+ // left out: nothing executed, so there is none — the prior run's evidence is still in the
1087
+ // transcript, and repeating it here would only pay for the same bytes twice.
1088
+ const replayNotice = truncateMiddle(`Not executed: unchanged. ${TOOL_FAILURE_READMISSION_RULE}`, MAX_DIAGNOSTIC_CHARS);
1006
1089
  const blockedResult = createToolFailureResult({
1007
1090
  ...retainedRecord,
1091
+ evidence: undefined,
1008
1092
  state: "rejected",
1009
1093
  failureCode: "repeated_failed_operation",
1010
1094
  ...(retainedRecord.diagnostic
1011
1095
  ? { note: replayNotice }
1012
- : { diagnostic: replayNotice, correction: BLOCKED_REPLAY_CAVEMAN_CORRECTION }),
1096
+ : { diagnostic: replayNotice, correction: BLOCKED_REPLAY_CORRECTION }),
1013
1097
  });
1014
1098
  return {
1015
1099
  ...blockedResult,
@@ -1019,36 +1103,6 @@ export function createRepeatedToolFailureResult(record) {
1019
1103
  details: { piToolFailureMemory: retainedRecord },
1020
1104
  };
1021
1105
  }
1022
- export function createToolFailureRecoveryExhaustedResult(record, note) {
1023
- const retainedRecord = retainBlockedToolFailure(record);
1024
- const exhaustedResult = createToolFailureResult({
1025
- ...retainedRecord,
1026
- state: "rejected",
1027
- failureCode: "recovery_exhausted",
1028
- note: truncateMiddle(note, MAX_DIAGNOSTIC_CHARS),
1029
- correction: "Stop retrying tools in this run. Report the unresolved failure and the user or environment action required to continue.",
1030
- }, true);
1031
- return {
1032
- ...exhaustedResult,
1033
- details: { piToolFailureMemory: retainedRecord },
1034
- };
1035
- }
1036
- export function createToolFailureOperationExhaustedResult(record, note) {
1037
- const retainedRecord = {
1038
- ...retainBlockedToolFailure(record),
1039
- correction: CLOSED_OPERATION_CAVEMAN_CORRECTION,
1040
- };
1041
- const exhaustedResult = createToolFailureResult({
1042
- ...retainedRecord,
1043
- state: "rejected",
1044
- failureCode: "operation_recovery_exhausted",
1045
- note: truncateMiddle(note, MAX_DIAGNOSTIC_CHARS),
1046
- }, false);
1047
- return {
1048
- ...exhaustedResult,
1049
- details: { piToolFailureMemory: retainedRecord },
1050
- };
1051
- }
1052
1106
  function retainBlockedToolFailure(record) {
1053
1107
  return {
1054
1108
  ...record,
@@ -1069,17 +1123,9 @@ export function sanitizeToolFailureContext(messages, systemPrompt) {
1069
1123
  const kindSummary = Object.entries(analysis.kindMistakesSummary)
1070
1124
  .map(([kind, count]) => `${kind}:${count}`)
1071
1125
  .join(", ");
1072
- let remainingEvidenceChars = MAX_ACTIVE_FAILURE_EVIDENCE_CHARS;
1073
- const evidenceByFailureKey = new Map();
1074
- for (let index = records.length - 1; index >= 0 && remainingEvidenceChars > 1; index--) {
1075
- const record = records[index];
1076
- if (!record.evidence)
1077
- continue;
1078
- const retained = truncate(record.evidence, remainingEvidenceChars);
1079
- evidenceByFailureKey.set(record.failureKey, retained);
1080
- remainingEvidenceChars -= retained.length;
1081
- }
1082
- const lines = records.map((record) => escapePromptData(formatRecordJson(record, true, evidenceByFailureKey.get(record.failureKey) ?? null)));
1126
+ // Evidence is not repeated here: the failed call and its bounded record both remain in the
1127
+ // transcript, so the ledger only has to name what is still unresolved and what to do about it.
1128
+ const lines = records.map((record) => escapePromptData(formatRecordJson(record, true, null)));
1083
1129
  for (const directive of analysis.activeDirectives) {
1084
1130
  lines.push(escapePromptData(JSON.stringify({
1085
1131
  ...mandatoryToolFailureRecoveryMetadata(),