@r3b1s/pi-repair-layer 0.2.0 → 0.3.0

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.
Files changed (76) hide show
  1. package/README.md +159 -293
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/{index.ts → dist/index.js} +2 -1
  5. package/dist/index.js.map +1 -0
  6. package/dist/src/core.d.ts +8 -0
  7. package/dist/src/core.d.ts.map +1 -0
  8. package/dist/src/core.js +7 -0
  9. package/dist/src/core.js.map +1 -0
  10. package/dist/src/envelope.d.ts +21 -0
  11. package/dist/src/envelope.d.ts.map +1 -0
  12. package/dist/src/envelope.js +158 -0
  13. package/dist/src/envelope.js.map +1 -0
  14. package/dist/src/grammar-recovery.d.ts +105 -0
  15. package/dist/src/grammar-recovery.d.ts.map +1 -0
  16. package/dist/src/grammar-recovery.js +1052 -0
  17. package/dist/src/grammar-recovery.js.map +1 -0
  18. package/dist/src/grammar.d.ts +2 -0
  19. package/dist/src/grammar.d.ts.map +1 -0
  20. package/dist/src/grammar.js +2 -0
  21. package/dist/src/grammar.js.map +1 -0
  22. package/dist/src/index.d.ts +36 -0
  23. package/dist/src/index.d.ts.map +1 -0
  24. package/dist/src/index.js +558 -0
  25. package/dist/src/index.js.map +1 -0
  26. package/dist/src/lifecycle.d.ts +34 -0
  27. package/dist/src/lifecycle.d.ts.map +1 -0
  28. package/dist/src/lifecycle.js +133 -0
  29. package/dist/src/lifecycle.js.map +1 -0
  30. package/dist/src/pi.d.ts +19 -0
  31. package/dist/src/pi.d.ts.map +1 -0
  32. package/dist/src/pi.js +38 -0
  33. package/dist/src/pi.js.map +1 -0
  34. package/dist/src/pipeline.d.ts +10 -0
  35. package/dist/src/pipeline.d.ts.map +1 -0
  36. package/dist/src/pipeline.js +166 -0
  37. package/dist/src/pipeline.js.map +1 -0
  38. package/dist/src/policy.d.ts +16 -0
  39. package/dist/src/policy.d.ts.map +1 -0
  40. package/dist/src/policy.js +31 -0
  41. package/dist/src/policy.js.map +1 -0
  42. package/dist/src/preprocess.d.ts +37 -0
  43. package/dist/src/preprocess.d.ts.map +1 -0
  44. package/dist/src/preprocess.js +216 -0
  45. package/dist/src/preprocess.js.map +1 -0
  46. package/dist/src/repair-engine.d.ts +91 -0
  47. package/dist/src/repair-engine.d.ts.map +1 -0
  48. package/dist/src/repair-engine.js +457 -0
  49. package/dist/src/repair-engine.js.map +1 -0
  50. package/dist/src/settings.d.ts +38 -0
  51. package/dist/src/settings.d.ts.map +1 -0
  52. package/dist/src/settings.js +87 -0
  53. package/dist/src/settings.js.map +1 -0
  54. package/dist/src/tables.d.ts +16 -0
  55. package/dist/src/tables.d.ts.map +1 -0
  56. package/dist/src/tables.js +302 -0
  57. package/dist/src/tables.js.map +1 -0
  58. package/dist/src/types.d.ts +52 -0
  59. package/dist/src/types.d.ts.map +1 -0
  60. package/dist/src/types.js +2 -0
  61. package/dist/src/types.js.map +1 -0
  62. package/dist/src/value-strips.d.ts +52 -0
  63. package/dist/src/value-strips.d.ts.map +1 -0
  64. package/dist/src/value-strips.js +191 -0
  65. package/dist/src/value-strips.js.map +1 -0
  66. package/docs/how-it-works.md +227 -0
  67. package/docs/operations.md +141 -0
  68. package/docs/research.md +247 -0
  69. package/docs/tool-owner-integration.md +327 -0
  70. package/package.json +31 -6
  71. package/src/grammar-recovery.ts +0 -1269
  72. package/src/index.ts +0 -621
  73. package/src/repair-engine.ts +0 -498
  74. package/src/settings.ts +0 -95
  75. package/src/tables.ts +0 -184
  76. package/src/value-strips.ts +0 -218
@@ -0,0 +1,158 @@
1
+ export const DEFAULT_ENVELOPE_LIMITS = {
2
+ maxInputBytes: 256 * 1024,
3
+ maxNestingDepth: 64,
4
+ maxDecodeAttempts: 3,
5
+ maxCandidates: 4,
6
+ maxWorkMs: 25,
7
+ };
8
+ export function isPlainObject(value) {
9
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
10
+ return false;
11
+ }
12
+ const prototype = Object.getPrototypeOf(value);
13
+ return prototype === Object.prototype || prototype === null;
14
+ }
15
+ function inputBytes(value) {
16
+ if (typeof value === "string")
17
+ return Buffer.byteLength(value, "utf8");
18
+ try {
19
+ return Buffer.byteLength(JSON.stringify(value) ?? "", "utf8");
20
+ }
21
+ catch {
22
+ return Number.POSITIVE_INFINITY;
23
+ }
24
+ }
25
+ function nestingDepth(value, limit) {
26
+ const stack = [{ value, depth: 0 }];
27
+ let maximum = 0;
28
+ const seen = new Set();
29
+ while (stack.length > 0) {
30
+ const item = stack.pop();
31
+ if (!item)
32
+ break;
33
+ maximum = Math.max(maximum, item.depth);
34
+ if (maximum > limit)
35
+ return maximum;
36
+ if (item.value === null || typeof item.value !== "object")
37
+ continue;
38
+ if (seen.has(item.value))
39
+ return limit + 1;
40
+ seen.add(item.value);
41
+ const children = Array.isArray(item.value)
42
+ ? item.value
43
+ : Object.values(item.value);
44
+ for (const child of children) {
45
+ stack.push({ value: child, depth: item.depth + 1 });
46
+ }
47
+ }
48
+ return maximum;
49
+ }
50
+ /** Escape only literal JSON control characters that occur inside a string. */
51
+ export function escapeJsonStringControlCharacters(text) {
52
+ let output = "";
53
+ let inString = false;
54
+ let escaped = false;
55
+ let changed = false;
56
+ for (const character of text) {
57
+ if (!inString) {
58
+ output += character;
59
+ if (character === '"')
60
+ inString = true;
61
+ continue;
62
+ }
63
+ if (escaped) {
64
+ output += character;
65
+ escaped = false;
66
+ continue;
67
+ }
68
+ if (character === "\\") {
69
+ output += character;
70
+ escaped = true;
71
+ continue;
72
+ }
73
+ if (character === '"') {
74
+ output += character;
75
+ inString = false;
76
+ continue;
77
+ }
78
+ const code = character.codePointAt(0) ?? 0;
79
+ if (code < 0x20) {
80
+ output += `\\u${code.toString(16).padStart(4, "0")}`;
81
+ changed = true;
82
+ }
83
+ else {
84
+ output += character;
85
+ }
86
+ }
87
+ return changed ? output : text;
88
+ }
89
+ function parseJson(text) {
90
+ try {
91
+ return JSON.parse(text);
92
+ }
93
+ catch {
94
+ return undefined;
95
+ }
96
+ }
97
+ function change(ruleId, note) {
98
+ return { ruleId, stage: "envelope", note };
99
+ }
100
+ const TRUNCATED_SUFFIXES = ["}", '"}', "]}", '"}]}'];
101
+ export function recoverEnvelope(input, overrides = {}) {
102
+ const limits = { ...DEFAULT_ENVELOPE_LIMITS, ...overrides };
103
+ const unchanged = (limited = false) => ({
104
+ value: input,
105
+ changes: [],
106
+ candidates: [],
107
+ limited,
108
+ });
109
+ if (inputBytes(input) > limits.maxInputBytes ||
110
+ nestingDepth(input, limits.maxNestingDepth) > limits.maxNestingDepth) {
111
+ return unchanged(true);
112
+ }
113
+ const started = performance.now();
114
+ const changes = [];
115
+ let value = structuredClone(input);
116
+ let attempts = 0;
117
+ while (typeof value === "string" &&
118
+ attempts < limits.maxDecodeAttempts &&
119
+ performance.now() - started <= limits.maxWorkMs) {
120
+ attempts += 1;
121
+ const escaped = escapeJsonStringControlCharacters(value);
122
+ const parsed = parseJson(escaped);
123
+ if (parsed === undefined)
124
+ break;
125
+ value = parsed;
126
+ changes.push(change("envelope.decode-json", "Decoded a JSON-encoded tool-argument envelope. Send the argument object directly next time."));
127
+ if (escaped !== input && attempts === 1) {
128
+ changes.push(change("envelope.escape-control-character", "Escaped a raw control character inside the JSON argument envelope."));
129
+ }
130
+ }
131
+ if (Array.isArray(value) && value.length === 1 && isPlainObject(value[0])) {
132
+ value = value[0];
133
+ changes.push(change("envelope.unwrap-singleton-object-array", "Unwrapped a singleton object array used as the tool-argument envelope."));
134
+ }
135
+ if (isPlainObject(value)) {
136
+ if (nestingDepth(value, limits.maxNestingDepth) > limits.maxNestingDepth) {
137
+ return unchanged(true);
138
+ }
139
+ return { value, changes, candidates: [], limited: false };
140
+ }
141
+ const candidates = [];
142
+ if (typeof input === "string" && input.trimStart().startsWith("{")) {
143
+ for (const suffix of TRUNCATED_SUFFIXES) {
144
+ if (candidates.length >= limits.maxCandidates)
145
+ break;
146
+ if (performance.now() - started > limits.maxWorkMs)
147
+ break;
148
+ const parsed = parseJson(escapeJsonStringControlCharacters(`${input}${suffix}`));
149
+ if (isPlainObject(parsed))
150
+ candidates.push(parsed);
151
+ }
152
+ }
153
+ return { value: input, changes: [], candidates, limited: false };
154
+ }
155
+ export function truncatedEnvelopeChange() {
156
+ return change("envelope.complete-truncated-object", "Completed a truncated JSON object envelope after the completed candidate passed the tool schema.");
157
+ }
158
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/envelope.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Grammar-leak recovery — adapted in place from monotykamary/pi-tool-repair
3
+ * (MIT), `src/grammar-repair.ts`. The grammar-family parsers, candidate
4
+ * selection, code-fence awareness, and `removeRanges` are kept close to
5
+ * upstream; the driver (`recoverGrammarLeaks`) is rewritten to integrate this
6
+ * extension's settings, model gate, and telemetry, and to add a stopReason gate
7
+ * upstream lacks.
8
+ *
9
+ * What it does: some models print a tool call as literal text (10 grammar
10
+ * families — DSML, Qwen/GLM XML, Kimi/Mistral/Llama/MiniMax sentinels, etc.)
11
+ * instead of emitting a real tool call. On the `message_end` hook this detects
12
+ * those leaked blocks, strips them from the assistant text, and — in `recover`
13
+ * mode — promotes the parsed calls to real toolCalls that execute the same turn.
14
+ *
15
+ * The one deliberate improvement over upstream: promotion happens ONLY when the
16
+ * original message's `stopReason` is `"stop"` (see `recoverGrammarLeaks`).
17
+ * Upstream promotes regardless and overwrites `stopReason: "length"`, defeating
18
+ * pi's protection that fails all tool calls on truncated output
19
+ * (docs/research.md Claim 7). Stripping leaked text is permitted on any
20
+ * stopReason; only promotion is gated.
21
+ */
22
+ export declare const GRAMMAR_NAMES: readonly ["dsml", "invoke", "qwen", "kimi", "mistral", "llama", "glm", "granite", "minimax-text", "olmo"];
23
+ export type GrammarName = (typeof GRAMMAR_NAMES)[number];
24
+ export type GrammarRecoveryMode = "off" | "observe" | "strip" | "recover";
25
+ export interface RecoveredToolCall {
26
+ name: string;
27
+ arguments: Record<string, unknown>;
28
+ grammar: GrammarName;
29
+ }
30
+ interface MinimalTextContent {
31
+ type: "text";
32
+ text: string;
33
+ [key: string]: unknown;
34
+ }
35
+ interface MinimalThinkingContent {
36
+ type: "thinking";
37
+ thinking: string;
38
+ [key: string]: unknown;
39
+ }
40
+ interface MinimalToolCallContent {
41
+ type: "toolCall";
42
+ id: string;
43
+ name: string;
44
+ arguments: Record<string, unknown>;
45
+ [key: string]: unknown;
46
+ }
47
+ type MinimalAssistantContent = MinimalTextContent | MinimalThinkingContent | MinimalToolCallContent | Record<string, unknown>;
48
+ export interface MinimalAssistantMessage {
49
+ role: string;
50
+ content: MinimalAssistantContent[];
51
+ stopReason?: string;
52
+ [key: string]: unknown;
53
+ }
54
+ /**
55
+ * Open-model families known to print tool-call grammar as text. Grammar
56
+ * recovery runs only when the current model matches one of these — a heuristic
57
+ * gate that keeps the parsers off frontier models (Claude/GPT/Gemini) that emit
58
+ * native tool calls and may legitimately quote grammar in prose. The real
59
+ * safety is the known-tool / empty-args / stopReason gates; this list is the
60
+ * cheap first filter and can be loosened as telemetry warrants.
61
+ */
62
+ export declare const GRAMMAR_RECOVERY_MODELS: readonly RegExp[];
63
+ /** Whether grammar recovery's model gate matches the given model id. */
64
+ export declare function modelLeaksGrammar(modelId: string | undefined): boolean;
65
+ export interface GrammarRecoveryOptions {
66
+ mode: GrammarRecoveryMode;
67
+ /** Active/allowed tool names; a leaked call is only promoted if its name is here. */
68
+ knownTools: Set<string>;
69
+ /** Which grammar families to detect. Default: all. */
70
+ grammars?: readonly GrammarName[];
71
+ /** Require the recovered tool name to be in `knownTools`. Default: true. */
72
+ requireKnownTool?: boolean;
73
+ /** Unknown/disallowed calls are preserved unless explicitly set to strip. */
74
+ unknownToolText?: "preserve" | "strip";
75
+ }
76
+ export interface GrammarRecoveryResult {
77
+ /** Whether the message was modified (text stripped and/or calls promoted). */
78
+ changed: boolean;
79
+ /** Calls promoted to real toolCalls (empty unless a promotion happened). */
80
+ recoveredCalls: RecoveredToolCall[];
81
+ /** Distinct grammar families whose leaked text was stripped. */
82
+ strippedGrammars: GrammarName[];
83
+ /** Number of leaked ranges removed from text. */
84
+ strippedRanges: number;
85
+ /** True when calls were promoted and stopReason was set to "toolUse". */
86
+ promoted: boolean;
87
+ /** Recognized leak metadata, populated even when observe mode preserves text. */
88
+ observed: boolean;
89
+ detectedGrammars: GrammarName[];
90
+ detectedRanges: number;
91
+ /** IDs assigned to promoted calls, in recoveredCalls order. */
92
+ promotedCallIds: string[];
93
+ /** The replacement message (same object when unchanged). */
94
+ message: MinimalAssistantMessage;
95
+ }
96
+ /**
97
+ * Detect leaked tool-call grammar in an assistant message, strip it from the
98
+ * text, and (in `recover` mode, on a `stopReason: "stop"` message with no
99
+ * existing toolCalls) promote the parsed calls to real toolCalls.
100
+ */
101
+ export declare function recoverGrammarLeaks(message: MinimalAssistantMessage, options: GrammarRecoveryOptions): GrammarRecoveryResult;
102
+ /** Pure parse: leaked tool calls in text (no stripping, no gates). For tests. */
103
+ export declare function parseToolGrammarLeaks(text: string, grammars?: Iterable<GrammarName>): RecoveredToolCall[];
104
+ export {};
105
+ //# sourceMappingURL=grammar-recovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grammar-recovery.d.ts","sourceRoot":"","sources":["../../src/grammar-recovery.ts"],"names":[],"mappings":"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"}