agentic-json-repair 1.0.0 → 1.0.1

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/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # agentic-json-repair
2
+
3
+ [![npm version](https://badge.fury.io/js/agentic-json-repair.svg)](https://www.npmjs.com/package/agentic-json-repair)
4
+
5
+ Repair and validate AI-generated JSON with auto-generated retry prompts. Perfect for building reliable AI agents and LLM pipelines.
6
+
7
+ ## Features
8
+
9
+ - 🔧 **Auto-repair** malformed JSON (missing quotes, trailing commas, etc.)
10
+ - 📝 **Extract JSON** from markdown code blocks or mixed prose
11
+ - ✅ **Validate** against Zod schemas with full type inference
12
+ - 🔄 **Auto-generate retry prompts** when validation fails
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install agentic-json-repair zod
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```typescript
23
+ import { safeParseAI } from 'agentic-json-repair';
24
+ import { z } from 'zod';
25
+
26
+ // Define your expected schema
27
+ const UserSchema = z.object({
28
+ name: z.string(),
29
+ age: z.number(),
30
+ });
31
+
32
+ // Parse messy AI output
33
+ const aiOutput = `
34
+ Sure! Here is the user data:
35
+ \`\`\`json
36
+ {
37
+ name: "Alice",
38
+ age: 30,
39
+ }
40
+ \`\`\`
41
+ `;
42
+
43
+ const result = safeParseAI(aiOutput, UserSchema);
44
+
45
+ if (result.success) {
46
+ console.log(result.data); // { name: "Alice", age: 30 } - fully typed!
47
+ } else {
48
+ // Use retry prompt to ask the AI to fix the output
49
+ console.log(result.retryPrompt);
50
+ }
51
+ ```
52
+
53
+ ## API
54
+
55
+ ### `safeParseAI<T>(aiOutput: string, schema: ZodType<T>): AgenticParseResult<T>`
56
+
57
+ Attempts to extract, repair, and validate JSON from an AI's text output.
58
+
59
+ **Returns:**
60
+
61
+ ```typescript
62
+ // On success
63
+ { success: true; data: T }
64
+
65
+ // On failure
66
+ { success: false; error: string; retryPrompt: string }
67
+ ```
68
+
69
+ ## What it handles
70
+
71
+ | Problem | Example | Fixed |
72
+ |---------|---------|-------|
73
+ | Markdown code blocks | `` ```json {...} ``` `` | ✅ |
74
+ | Surrounding prose | "Here's the JSON: {...}" | ✅ |
75
+ | Unquoted keys | `{ name: "Alice" }` | ✅ |
76
+ | Trailing commas | `{ "a": 1, }` | ✅ |
77
+ | Schema mismatches | Wrong types, missing fields | ✅ (retry prompt) |
78
+
79
+ ## Agentic Loop Example
80
+
81
+ ```typescript
82
+ async function getStructuredData(prompt: string, schema: z.ZodType) {
83
+ let attempts = 0;
84
+ let currentPrompt = prompt;
85
+
86
+ while (attempts < 3) {
87
+ const aiOutput = await callLLM(currentPrompt);
88
+ const result = safeParseAI(aiOutput, schema);
89
+
90
+ if (result.success) {
91
+ return result.data;
92
+ }
93
+
94
+ // Use the auto-generated retry prompt
95
+ currentPrompt = result.retryPrompt;
96
+ attempts++;
97
+ }
98
+
99
+ throw new Error('Failed to get valid structured data');
100
+ }
101
+ ```
102
+
103
+ ## License
104
+
105
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-json-repair",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Repair and validate AI-generated JSON with auto-generated retry prompts.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -12,6 +12,10 @@
12
12
  "require": "./dist/index.js"
13
13
  }
14
14
  },
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
15
19
  "scripts": {
16
20
  "build": "tsup src/index.ts --format cjs,esm --dts --clean",
17
21
  "test": "vitest run",
@@ -1,3 +0,0 @@
1
- {
2
- "recommendations": ["henrikdev.ag-quota"]
3
- }
package/src/index.test.ts DELETED
@@ -1,35 +0,0 @@
1
- import { expect, test } from 'vitest';
2
- import { safeParseAI } from './index';
3
- import { z } from 'zod';
4
-
5
- test('fixes broken AI output', () => {
6
- const brokenAiOutput = `
7
- Sure! Here is the user:
8
- \`\`\`json
9
- {
10
- name: "Alice",
11
- age: 30,
12
- }
13
- \`\`\`
14
- `;
15
-
16
- const UserSchema = z.object({ name: z.string(), age: z.number() });
17
- const result = safeParseAI(brokenAiOutput, UserSchema);
18
-
19
- expect(result.success).toBe(true);
20
- if (result.success) {
21
- expect(result.data.name).toBe("Alice");
22
- }
23
- });
24
-
25
- test('generates retry prompt on wrong schema', () => {
26
- const wrongTypeOutput = `{"age": "thirty"}`; // string instead of number
27
- const Schema = z.object({ age: z.number() });
28
-
29
- const result = safeParseAI(wrongTypeOutput, Schema);
30
-
31
- expect(result.success).toBe(false);
32
- if (!result.success) {
33
- expect(result.retryPrompt).toContain("expected number, received string");
34
- }
35
- });
package/src/index.ts DELETED
@@ -1,128 +0,0 @@
1
- import { jsonrepair } from 'jsonrepair';
2
- import { z } from 'zod';
3
-
4
- export type AgenticParseResult<T> =
5
- | { success: true; data: T }
6
- | { success: false; error: string; retryPrompt: string };
7
-
8
- /**
9
- * Attempts to extract, repair, and validate JSON from an AI's text output.
10
- * * @param aiOutput The raw string from the LLM (e.g., "Here is the data: ```json ...")
11
- * @param schema The Zod schema to validate against
12
- */
13
- /**
14
- * Extracts JSON content from AI output that may contain markdown code blocks or prose.
15
- */
16
- function extractJsonContent(aiOutput: string): string {
17
- // First, try to extract from markdown code blocks
18
- const codeBlockMatch = aiOutput.match(/```(?:json)?\s*([\s\S]*?)```/);
19
- if (codeBlockMatch) {
20
- return codeBlockMatch[1].trim();
21
- }
22
-
23
- // Otherwise, try to find the first JSON object or array
24
- const firstBrace = aiOutput.indexOf('{');
25
- const firstBracket = aiOutput.indexOf('[');
26
-
27
- let startChar: '{' | '[';
28
- let endChar: '}' | ']';
29
- let startIndex: number;
30
-
31
- if (firstBrace === -1 && firstBracket === -1) {
32
- // No JSON structure found, return as-is for jsonrepair to handle
33
- return aiOutput.trim();
34
- } else if (firstBrace === -1) {
35
- startChar = '[';
36
- endChar = ']';
37
- startIndex = firstBracket;
38
- } else if (firstBracket === -1) {
39
- startChar = '{';
40
- endChar = '}';
41
- startIndex = firstBrace;
42
- } else {
43
- // Both found, use whichever comes first
44
- if (firstBrace < firstBracket) {
45
- startChar = '{';
46
- endChar = '}';
47
- startIndex = firstBrace;
48
- } else {
49
- startChar = '[';
50
- endChar = ']';
51
- startIndex = firstBracket;
52
- }
53
- }
54
-
55
- // Find the matching closing bracket/brace
56
- let depth = 0;
57
- let inString = false;
58
- let escapeNext = false;
59
-
60
- for (let i = startIndex; i < aiOutput.length; i++) {
61
- const char = aiOutput[i];
62
-
63
- if (escapeNext) {
64
- escapeNext = false;
65
- continue;
66
- }
67
-
68
- if (char === '\\' && inString) {
69
- escapeNext = true;
70
- continue;
71
- }
72
-
73
- if (char === '"') {
74
- inString = !inString;
75
- continue;
76
- }
77
-
78
- if (!inString) {
79
- if (char === startChar) {
80
- depth++;
81
- } else if (char === endChar) {
82
- depth--;
83
- if (depth === 0) {
84
- return aiOutput.slice(startIndex, i + 1);
85
- }
86
- }
87
- }
88
- }
89
-
90
- // If we couldn't find matching brackets, return from startIndex to end
91
- return aiOutput.slice(startIndex).trim();
92
- }
93
-
94
- export function safeParseAI<T>(aiOutput: string, schema: z.ZodType<T>): AgenticParseResult<T> {
95
- try {
96
- // 1. Extract JSON: Find the JSON content within the AI output
97
- const cleanOutput = extractJsonContent(aiOutput);
98
-
99
- // 2. Repair JSON: Fixes missing quotes, trailing commas, etc.
100
- const repairedJson = jsonrepair(cleanOutput);
101
-
102
- // 3. Parse JSON
103
- const parsedObject = JSON.parse(repairedJson);
104
-
105
- // 4. Validate Schema
106
- const validation = schema.safeParse(parsedObject);
107
-
108
- if (validation.success) {
109
- return { success: true, data: validation.data };
110
- } else {
111
- // 5. Generate a "Self-Correction" prompt for the AI
112
- const issues = validation.error.issues.map(i => `${i.path.join('.')}: ${i.message}`).join(', ');
113
- return {
114
- success: false,
115
- error: "Validation Failed",
116
- retryPrompt: `The JSON was parsed but failed validation. Fix these issues: [${issues}] and return ONLY the JSON.`
117
- };
118
- }
119
-
120
- } catch (error) {
121
- // 6. Handle Syntax Errors that jsonrepair couldn't fix
122
- return {
123
- success: false,
124
- error: "JSON Syntax Error",
125
- retryPrompt: `The output was not valid JSON. Error: ${(error as Error).message}. Return ONLY valid JSON.`
126
- };
127
- }
128
- }
package/tsconfig.json DELETED
@@ -1,14 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "esModuleInterop": true,
7
- "strict": true,
8
- "declaration": true,
9
- "outDir": "dist",
10
- "skipLibCheck": true
11
- },
12
- "include": ["src"],
13
- "exclude": ["node_modules", "dist"]
14
- }