structured-json-agent 1.0.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.
package/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # Structured JSON Agent
2
+
3
+ A typed and extensible TypeScript library for creating and running Iterative AI Agents that guarantee structured JSON output.
4
+
5
+ This library orchestrates a **Generator ↔ Reviewer** cycle to ensure that the output from Large Language Models (LLMs) strictly adheres to a defined JSON Schema.
6
+
7
+ ## Features
8
+
9
+ * **Guaranteed JSON Output**: Enforces strict adherence to JSON Schemas (Draft-07+).
10
+ * **Iterative Self-Correction**: Automatically detects validation errors and feeds them back to a "Reviewer" model to fix the output.
11
+ * **Type-Safe**: Built with TypeScript for full type inference and safety.
12
+ * **Model Agnostic**: Compatible with OpenAI by default, but extensible for other providers.
13
+ * **Production Ready**: Includes typed errors, extensive validation, and a clean API.
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install structured-json-agent
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ### 1. Import and Configure
24
+
25
+ ```typescript
26
+ import { StructuredAgent } from "structured-json-agent";
27
+
28
+ // Define your Schemas
29
+ const inputSchema = {
30
+ type: "object",
31
+ properties: {
32
+ topic: { type: "string" },
33
+ depth: { type: "string", enum: ["basic", "advanced"] }
34
+ },
35
+ required: ["topic", "depth"]
36
+ };
37
+
38
+ const outputSchema = {
39
+ type: "object",
40
+ properties: {
41
+ title: { type: "string" },
42
+ keyPoints: { type: "array", items: { type: "string" } },
43
+ summary: { type: "string" }
44
+ },
45
+ required: ["title", "keyPoints", "summary"]
46
+ };
47
+
48
+ // Initialize the Agent
49
+ const agent = new StructuredAgent({
50
+ openAiApiKey: process.env.OPENAI_API_KEY!,
51
+ generatorModel: "gpt-4-turbo",
52
+ reviewerModel: "gpt-3.5-turbo", // Can be a faster/cheaper model for simple fixes
53
+ inputSchema,
54
+ outputSchema,
55
+ systemPrompt: "You are an expert summarizer. Create a structured summary based on the topic.",
56
+ maxIterations: 3 // Optional: Max correction attempts (default: 5)
57
+ });
58
+ ```
59
+
60
+ ### 2. Run the Agent
61
+
62
+ ```typescript
63
+ async function main() {
64
+ try {
65
+ const result = await agent.run({
66
+ topic: "Clean Architecture",
67
+ depth: "advanced"
68
+ });
69
+
70
+ console.log("Result:", result);
71
+ // Output is guaranteed to match outputSchema
72
+ } catch (error) {
73
+ console.error("Agent failed:", error);
74
+ }
75
+ }
76
+
77
+ main();
78
+ ```
79
+
80
+ ## How It Works
81
+
82
+ 1. **Validation**: The input JSON is validated against the `inputSchema`.
83
+ 2. **Generation**: The `generatorModel` creates an initial response based on the system prompt and input.
84
+ 3. **Verification Loop**:
85
+ * The response is parsed and validated against `outputSchema`.
86
+ * **If Valid**: The result is returned immediately.
87
+ * **If Invalid**: The `reviewerModel` is invoked with the invalid JSON, the specific validation errors, and the expected schema. It attempts to fix the JSON.
88
+ 4. **Convergence**: This cycle repeats until a valid JSON is produced or `maxIterations` is reached.
89
+
90
+ ## API Reference
91
+
92
+ ### `StructuredAgent` Config
93
+
94
+ | Property | Type | Description |
95
+ |Col |Col |Col |
96
+ | `openAiApiKey` | `string` | Your OpenAI API Key. |
97
+ | `generatorModel` | `string` | Model ID for the initial generation (e.g., `gpt-4`). |
98
+ | `reviewerModel` | `string` | Model ID for the review/correction phase. |
99
+ | `inputSchema` | `object` | JSON Schema for validating the input. |
100
+ | `outputSchema` | `object` | JSON Schema for the expected output. |
101
+ | `systemPrompt` | `string` | Core instructions for the agent. |
102
+ | `maxIterations` | `number?` | Max retries for correction. Default: 5. |
103
+ | `modelConfig` | `ModelConfig?` | Optional parameters (temperature, etc.). |
104
+ | `llmService` | `ILLMService?` | Optional custom LLM service implementation. |
105
+
106
+ ### Error Handling
107
+
108
+ The library exports specific error classes for handling failures:
109
+
110
+ * `InvalidInputSchemaError`: Input schema is invalid.
111
+ * `InvalidOutputSchemaError`: Output schema is invalid.
112
+ * `SchemaValidationError`: Input data does not match the schema.
113
+ * `MaxIterationsExceededError`: The agent could not produce valid JSON within the limit.
114
+ * `LLMExecutionError`: Failure in communicating with the LLM provider.
115
+
116
+ ## Architecture
117
+
118
+ The project is structured by domain:
119
+
120
+ * `src/agent`: Core orchestration logic.
121
+ * `src/schemas`: Validation logic using AJV.
122
+ * `src/llm`: Interface and implementation for LLM providers.
123
+ * `src/errors`: Custom error definitions.
124
+ * `src/types`: Shared interfaces.
125
+
@@ -0,0 +1,15 @@
1
+ import { AgentConfig } from "../types/index.js";
2
+ export declare class StructuredAgent {
3
+ private schemaValidator;
4
+ private llmService;
5
+ private inputValidator;
6
+ private outputValidator;
7
+ private config;
8
+ constructor(config: AgentConfig);
9
+ run(inputJson: unknown): Promise<unknown>;
10
+ private generateInitialResponse;
11
+ private reviewResponse;
12
+ private validateOutput;
13
+ private parseJson;
14
+ private buildSystemPrompt;
15
+ }
@@ -0,0 +1,150 @@
1
+ import { SchemaValidator } from "../schemas/validator.js";
2
+ import { OpenAILLMService } from "../llm/index.js";
3
+ import { InvalidInputSchemaError, InvalidOutputSchemaError, SchemaValidationError, MaxIterationsExceededError, LLMExecutionError, } from "../errors/index.js";
4
+ export class StructuredAgent {
5
+ schemaValidator;
6
+ llmService;
7
+ inputValidator;
8
+ outputValidator;
9
+ config;
10
+ constructor(config) {
11
+ this.config = config;
12
+ this.schemaValidator = new SchemaValidator();
13
+ // Use provided LLM service or default to OpenAI
14
+ this.llmService = config.llmService || new OpenAILLMService(config.openAiApiKey);
15
+ try {
16
+ this.inputValidator = this.schemaValidator.compile(config.inputSchema);
17
+ }
18
+ catch (e) {
19
+ throw new InvalidInputSchemaError("Failed to compile input schema", e);
20
+ }
21
+ try {
22
+ this.outputValidator = this.schemaValidator.compile(config.outputSchema);
23
+ }
24
+ catch (e) {
25
+ throw new InvalidOutputSchemaError("Failed to compile output schema", e);
26
+ }
27
+ }
28
+ async run(inputJson) {
29
+ // 1. Validate Input
30
+ try {
31
+ this.schemaValidator.validate(this.inputValidator, inputJson);
32
+ }
33
+ catch (error) {
34
+ if (error instanceof SchemaValidationError) {
35
+ // Enhance error message if needed, but the original is good
36
+ throw error;
37
+ }
38
+ throw error;
39
+ }
40
+ const maxIterations = this.config.maxIterations ?? 5;
41
+ const history = [];
42
+ // 2. Initial Generation
43
+ let currentJson = await this.generateInitialResponse(inputJson);
44
+ history.push({ step: "generation", result: currentJson });
45
+ let validationResult = this.validateOutput(currentJson);
46
+ if (validationResult.valid) {
47
+ return currentJson;
48
+ }
49
+ // 3. Review Loop
50
+ for (let i = 0; i < maxIterations; i++) {
51
+ try {
52
+ currentJson = await this.reviewResponse(currentJson, validationResult.errors || [], inputJson // Context might be needed
53
+ );
54
+ history.push({ step: `review-${i + 1}`, result: currentJson });
55
+ validationResult = this.validateOutput(currentJson);
56
+ if (validationResult.valid) {
57
+ return currentJson;
58
+ }
59
+ }
60
+ catch (error) {
61
+ // If LLM fails or parsing fails during review, we record it and continue?
62
+ // Or throw? The requirement says "return exclusively a valid JSON".
63
+ // If we can't continue, we should probably throw or let the loop hit max iterations.
64
+ // For now, let's treat execution errors as fatal or part of the attempt?
65
+ // If it's a parsing error, it's a validation error.
66
+ // If it's an API error, it's an LLMExecutionError.
67
+ if (error instanceof LLMExecutionError) {
68
+ throw error;
69
+ }
70
+ // If JSON parse error in reviewResponse, it might be caught there.
71
+ }
72
+ }
73
+ throw new MaxIterationsExceededError(`Failed to generate valid JSON after ${maxIterations} review iterations`, history);
74
+ }
75
+ async generateInitialResponse(input) {
76
+ const messages = [
77
+ {
78
+ role: "system",
79
+ content: this.buildSystemPrompt(),
80
+ },
81
+ {
82
+ role: "user",
83
+ content: JSON.stringify(input),
84
+ },
85
+ ];
86
+ const responseText = await this.llmService.complete(messages, this.config.generatorModel, this.config.modelConfig);
87
+ return this.parseJson(responseText);
88
+ }
89
+ async reviewResponse(invalidJson, errors, originalInput) {
90
+ const messages = [
91
+ {
92
+ role: "system",
93
+ content: `You are a strict JSON reviewer.
94
+ Your task is to fix the provided JSON so it adheres to the Schema.
95
+ Output ONLY the corrected JSON.`,
96
+ },
97
+ {
98
+ role: "user",
99
+ content: `Original Input Context: ${JSON.stringify(originalInput)}
100
+
101
+ The following JSON is INVALID based on the output schema:
102
+ ${JSON.stringify(invalidJson)}
103
+
104
+ Validation Errors:
105
+ ${errors.join("\n")}
106
+
107
+ Expected Output Schema:
108
+ ${JSON.stringify(this.config.outputSchema)}
109
+
110
+ Please correct the JSON.`,
111
+ },
112
+ ];
113
+ const responseText = await this.llmService.complete(messages, this.config.reviewerModel, this.config.modelConfig);
114
+ return this.parseJson(responseText);
115
+ }
116
+ validateOutput(data) {
117
+ try {
118
+ this.schemaValidator.validate(this.outputValidator, data);
119
+ return { valid: true };
120
+ }
121
+ catch (error) {
122
+ if (error instanceof SchemaValidationError) {
123
+ const formattedErrors = this.schemaValidator.formatErrors(error.errors);
124
+ return { valid: false, errors: [formattedErrors] };
125
+ }
126
+ return { valid: false, errors: ["Unknown validation error"] };
127
+ }
128
+ }
129
+ parseJson(text) {
130
+ try {
131
+ return JSON.parse(text);
132
+ }
133
+ catch (e) {
134
+ // If parsing fails, we return the text (as string) or null?
135
+ // But the flow expects unknown (object).
136
+ // If we return the text, the schema validation will likely fail (unless schema allows string).
137
+ // This allows the reviewer to see the malformed JSON text.
138
+ return text;
139
+ }
140
+ }
141
+ buildSystemPrompt() {
142
+ return `${this.config.systemPrompt}
143
+
144
+ IMPORTANT: You must output strict JSON only.
145
+ The output must adhere to the following JSON Schema:
146
+ ${JSON.stringify(this.config.outputSchema)}
147
+ `;
148
+ }
149
+ }
150
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAA4B,MAAM,iBAAiB,CAAC;AAI7E,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,qBAAqB,EACrB,0BAA0B,EAC1B,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,OAAO,eAAe;IAClB,eAAe,CAAkB;IACjC,UAAU,CAAc;IACxB,cAAc,CAAmB;IACjC,eAAe,CAAmB;IAClC,MAAM,CAAc;IAE5B,YAAY,MAAmB;QAC7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;QAE7C,gDAAgD;QAChD,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,IAAI,gBAAgB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAEjF,IAAI,CAAC;YACH,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACzE,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,uBAAuB,CAAC,gCAAgC,EAAE,CAAC,CAAC,CAAC;QACzE,CAAC;QAED,IAAI,CAAC;YACH,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAC3E,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,wBAAwB,CAAC,iCAAiC,EAAE,CAAC,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,GAAG,CAAC,SAAkB;QACjC,oBAAoB;QACpB,IAAI,CAAC;YACH,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;QAChE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,qBAAqB,EAAE,CAAC;gBAC3C,4DAA4D;gBAC5D,MAAM,KAAK,CAAC;YACd,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,CAAC;QACrD,MAAM,OAAO,GAAc,EAAE,CAAC;QAE9B,wBAAwB;QACxB,IAAI,WAAW,GAAG,MAAM,IAAI,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC;QAChE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;QAE1D,IAAI,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;QACxD,IAAI,gBAAgB,CAAC,KAAK,EAAE,CAAC;YAC3B,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,iBAAiB;QACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,IAAI,CAAC;gBACH,WAAW,GAAG,MAAM,IAAI,CAAC,cAAc,CACrC,WAAW,EACX,gBAAgB,CAAC,MAAM,IAAI,EAAE,EAC7B,SAAS,CAAC,0BAA0B;iBACrC,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;gBAE/D,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;gBACpD,IAAI,gBAAgB,CAAC,KAAK,EAAE,CAAC;oBAC3B,OAAO,WAAW,CAAC;gBACrB,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,0EAA0E;gBAC1E,oEAAoE;gBACpE,qFAAqF;gBACrF,yEAAyE;gBACzE,oDAAoD;gBACpD,mDAAmD;gBACnD,IAAI,KAAK,YAAY,iBAAiB,EAAE,CAAC;oBACvC,MAAM,KAAK,CAAC;gBACd,CAAC;gBACD,mEAAmE;YACrE,CAAC;QACH,CAAC;QAED,MAAM,IAAI,0BAA0B,CAClC,uCAAuC,aAAa,oBAAoB,EACxE,OAAO,CACR,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,uBAAuB,CAAC,KAAc;QAClD,MAAM,QAAQ,GAAkB;YAC9B;gBACE,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,IAAI,CAAC,iBAAiB,EAAE;aAClC;YACD;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;aAC/B;SACF,CAAC;QAEF,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CACjD,QAAQ,EACR,IAAI,CAAC,MAAM,CAAC,cAAc,EAC1B,IAAI,CAAC,MAAM,CAAC,WAAW,CACxB,CAAC;QAEF,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IACtC,CAAC;IAEO,KAAK,CAAC,cAAc,CAC1B,WAAoB,EACpB,MAAgB,EAChB,aAAsB;QAEtB,MAAM,QAAQ,GAAkB;YAC9B;gBACE,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE;;gCAEe;aACzB;YACD;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,2BAA2B,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC;;;EAGvE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;;;EAG3B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAGjB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;;yBAEjB;aAClB;SACF,CAAC;QAEF,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CACjD,QAAQ,EACR,IAAI,CAAC,MAAM,CAAC,aAAa,EACzB,IAAI,CAAC,MAAM,CAAC,WAAW,CACxB,CAAC;QAEF,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IACtC,CAAC;IAEO,cAAc,CAAC,IAAa;QAClC,IAAI,CAAC;YACH,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;YAC1D,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACzB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,qBAAqB,EAAE,CAAC;gBAC3C,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,KAAK,CAAC,MAAe,CAAC,CAAC;gBACjF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;YACrD,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,0BAA0B,CAAC,EAAE,CAAC;QAChE,CAAC;IACH,CAAC;IAEO,SAAS,CAAC,IAAY;QAC5B,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,4DAA4D;YAC5D,yCAAyC;YACzC,+FAA+F;YAC/F,2DAA2D;YAC3D,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAEO,iBAAiB;QACvB,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY;;;;EAIpC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;CACzC,CAAC;IACA,CAAC;CACF"}
@@ -0,0 +1,23 @@
1
+ export declare class StructuredAgentError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ export declare class InvalidInputSchemaError extends StructuredAgentError {
5
+ context?: unknown | undefined;
6
+ constructor(message: string, context?: unknown | undefined);
7
+ }
8
+ export declare class InvalidOutputSchemaError extends StructuredAgentError {
9
+ context?: unknown | undefined;
10
+ constructor(message: string, context?: unknown | undefined);
11
+ }
12
+ export declare class SchemaValidationError extends StructuredAgentError {
13
+ errors: unknown[];
14
+ constructor(message: string, errors: unknown[]);
15
+ }
16
+ export declare class MaxIterationsExceededError extends StructuredAgentError {
17
+ attempts: unknown[];
18
+ constructor(message: string, attempts: unknown[]);
19
+ }
20
+ export declare class LLMExecutionError extends StructuredAgentError {
21
+ originalError?: unknown | undefined;
22
+ constructor(message: string, originalError?: unknown | undefined);
23
+ }
@@ -0,0 +1,43 @@
1
+ export class StructuredAgentError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = this.constructor.name;
5
+ Error.captureStackTrace(this, this.constructor);
6
+ }
7
+ }
8
+ export class InvalidInputSchemaError extends StructuredAgentError {
9
+ context;
10
+ constructor(message, context) {
11
+ super(message);
12
+ this.context = context;
13
+ }
14
+ }
15
+ export class InvalidOutputSchemaError extends StructuredAgentError {
16
+ context;
17
+ constructor(message, context) {
18
+ super(message);
19
+ this.context = context;
20
+ }
21
+ }
22
+ export class SchemaValidationError extends StructuredAgentError {
23
+ errors;
24
+ constructor(message, errors) {
25
+ super(message);
26
+ this.errors = errors;
27
+ }
28
+ }
29
+ export class MaxIterationsExceededError extends StructuredAgentError {
30
+ attempts;
31
+ constructor(message, attempts) {
32
+ super(message);
33
+ this.attempts = attempts;
34
+ }
35
+ }
36
+ export class LLMExecutionError extends StructuredAgentError {
37
+ originalError;
38
+ constructor(message, originalError) {
39
+ super(message);
40
+ this.originalError = originalError;
41
+ }
42
+ }
43
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAClC,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAClD,CAAC;CACF;AAED,MAAM,OAAO,uBAAwB,SAAQ,oBAAoB;IAC3B;IAApC,YAAY,OAAe,EAAS,OAAiB;QACnD,KAAK,CAAC,OAAO,CAAC,CAAC;QADmB,YAAO,GAAP,OAAO,CAAU;IAErD,CAAC;CACF;AAED,MAAM,OAAO,wBAAyB,SAAQ,oBAAoB;IAC5B;IAApC,YAAY,OAAe,EAAS,OAAiB;QACnD,KAAK,CAAC,OAAO,CAAC,CAAC;QADmB,YAAO,GAAP,OAAO,CAAU;IAErD,CAAC;CACF;AAED,MAAM,OAAO,qBAAsB,SAAQ,oBAAoB;IACzB;IAApC,YAAY,OAAe,EAAS,MAAiB;QACnD,KAAK,CAAC,OAAO,CAAC,CAAC;QADmB,WAAM,GAAN,MAAM,CAAW;IAErD,CAAC;CACF;AAED,MAAM,OAAO,0BAA2B,SAAQ,oBAAoB;IAC9B;IAApC,YAAY,OAAe,EAAS,QAAmB;QACrD,KAAK,CAAC,OAAO,CAAC,CAAC;QADmB,aAAQ,GAAR,QAAQ,CAAW;IAEvD,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,oBAAoB;IACrB;IAApC,YAAY,OAAe,EAAS,aAAuB;QACzD,KAAK,CAAC,OAAO,CAAC,CAAC;QADmB,kBAAa,GAAb,aAAa,CAAU;IAE3D,CAAC;CACF"}
@@ -0,0 +1,4 @@
1
+ export * from "./agent/index.js";
2
+ export * from "./errors/index.js";
3
+ export * from "./types/index.js";
4
+ export * from "./schemas/validator.js";
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from "./agent/index.js";
2
+ export * from "./errors/index.js";
3
+ export * from "./types/index.js";
4
+ // Export schemas validator if needed, but maybe not necessary for public API
5
+ export * from "./schemas/validator.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,6EAA6E;AAC7E,cAAc,wBAAwB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from "./types.js";
2
+ export * from "./openai.js";
@@ -0,0 +1,3 @@
1
+ export * from "./types.js";
2
+ export * from "./openai.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/llm/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { ILLMService, ChatMessage } from "./types.js";
2
+ import { ModelConfig } from "../types/index.js";
3
+ export declare class OpenAILLMService implements ILLMService {
4
+ private client;
5
+ constructor(apiKey: string);
6
+ complete(messages: ChatMessage[], model: string, config?: ModelConfig): Promise<string>;
7
+ }
@@ -0,0 +1,33 @@
1
+ import OpenAI from "openai";
2
+ import { LLMExecutionError } from "../errors/index.js";
3
+ export class OpenAILLMService {
4
+ client;
5
+ constructor(apiKey) {
6
+ this.client = new OpenAI({
7
+ apiKey: apiKey,
8
+ });
9
+ }
10
+ async complete(messages, model, config) {
11
+ try {
12
+ const response = await this.client.chat.completions.create({
13
+ messages: messages,
14
+ model: model,
15
+ response_format: { type: "json_object" }, // Force JSON mode
16
+ temperature: config?.temperature ?? 0.7,
17
+ top_p: config?.top_p,
18
+ max_tokens: config?.max_tokens,
19
+ presence_penalty: config?.presence_penalty,
20
+ frequency_penalty: config?.frequency_penalty,
21
+ });
22
+ const content = response.choices[0]?.message?.content;
23
+ if (!content) {
24
+ throw new LLMExecutionError("Received empty response from LLM");
25
+ }
26
+ return content;
27
+ }
28
+ catch (error) {
29
+ throw new LLMExecutionError("Failed to execute LLM request", error);
30
+ }
31
+ }
32
+ }
33
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/llm/openai.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,OAAO,gBAAgB;IACnB,MAAM,CAAS;IAEvB,YAAY,MAAc;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,CAAC;YACvB,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;IACL,CAAC;IAEM,KAAK,CAAC,QAAQ,CACnB,QAAuB,EACvB,KAAa,EACb,MAAoB;QAEpB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;gBACzD,QAAQ,EAAE,QAAQ;gBAClB,KAAK,EAAE,KAAK;gBACZ,eAAe,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,kBAAkB;gBAC5D,WAAW,EAAE,MAAM,EAAE,WAAW,IAAI,GAAG;gBACvC,KAAK,EAAE,MAAM,EAAE,KAAK;gBACpB,UAAU,EAAE,MAAM,EAAE,UAAU;gBAC9B,gBAAgB,EAAE,MAAM,EAAE,gBAAgB;gBAC1C,iBAAiB,EAAE,MAAM,EAAE,iBAAiB;aAC7C,CAAC,CAAC;YAEH,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC;YACtD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,IAAI,iBAAiB,CAAC,kCAAkC,CAAC,CAAC;YAClE,CAAC;YAED,OAAO,OAAO,CAAC;QACjB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,iBAAiB,CAAC,+BAA+B,EAAE,KAAK,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,8 @@
1
+ import { ModelConfig } from "../types/index.js";
2
+ export interface ChatMessage {
3
+ role: "system" | "user" | "assistant";
4
+ content: string;
5
+ }
6
+ export interface ILLMService {
7
+ complete(messages: ChatMessage[], model: string, config?: ModelConfig): Promise<string>;
8
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/llm/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,20 @@
1
+ import type { ValidateFunction } from "ajv";
2
+ export declare class SchemaValidator {
3
+ private ajv;
4
+ constructor();
5
+ /**
6
+ * Compiles a schema and returns a validation function.
7
+ * Throws InvalidInputSchemaError if the schema is invalid.
8
+ */
9
+ compile(schema: object): ValidateFunction;
10
+ /**
11
+ * Validates data against a compiled schema validator.
12
+ * Returns true if valid.
13
+ * Throws SchemaValidationError if invalid.
14
+ */
15
+ validate(validator: ValidateFunction, data: unknown): void;
16
+ /**
17
+ * Helper to format AJV errors into a readable string
18
+ */
19
+ formatErrors(errors: any[]): string;
20
+ }
@@ -0,0 +1,39 @@
1
+ import Ajv from "ajv";
2
+ import { SchemaValidationError, InvalidInputSchemaError } from "../errors/index.js";
3
+ export class SchemaValidator {
4
+ ajv;
5
+ constructor() {
6
+ // @ts-ignore: Ajv import structure compatibility
7
+ this.ajv = new Ajv({ allErrors: true, strict: false });
8
+ }
9
+ /**
10
+ * Compiles a schema and returns a validation function.
11
+ * Throws InvalidInputSchemaError if the schema is invalid.
12
+ */
13
+ compile(schema) {
14
+ try {
15
+ return this.ajv.compile(schema);
16
+ }
17
+ catch (error) {
18
+ throw new InvalidInputSchemaError("Invalid JSON Schema provided", error);
19
+ }
20
+ }
21
+ /**
22
+ * Validates data against a compiled schema validator.
23
+ * Returns true if valid.
24
+ * Throws SchemaValidationError if invalid.
25
+ */
26
+ validate(validator, data) {
27
+ const valid = validator(data);
28
+ if (!valid) {
29
+ throw new SchemaValidationError("Data validation failed", validator.errors || []);
30
+ }
31
+ }
32
+ /**
33
+ * Helper to format AJV errors into a readable string
34
+ */
35
+ formatErrors(errors) {
36
+ return this.ajv.errorsText(errors);
37
+ }
38
+ }
39
+ //# sourceMappingURL=validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/schemas/validator.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AAEtB,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAEpF,MAAM,OAAO,eAAe;IAClB,GAAG,CAAM;IAEjB;QACE,iDAAiD;QACjD,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACzD,CAAC;IAED;;;OAGG;IACI,OAAO,CAAC,MAAc;QAC3B,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,uBAAuB,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IAED;;;;OAIG;IACI,QAAQ,CAAC,SAA2B,EAAE,IAAa;QACxD,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,qBAAqB,CAC7B,wBAAwB,EACxB,SAAS,CAAC,MAAM,IAAI,EAAE,CACvB,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACI,YAAY,CAAC,MAAa;QAC/B,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;CACF"}
@@ -0,0 +1,26 @@
1
+ import { ILLMService } from "../llm/types.js";
2
+ export interface ModelConfig {
3
+ temperature?: number;
4
+ top_p?: number;
5
+ max_tokens?: number;
6
+ presence_penalty?: number;
7
+ frequency_penalty?: number;
8
+ }
9
+ export interface AgentConfig {
10
+ openAiApiKey: string;
11
+ generatorModel: string;
12
+ reviewerModel: string;
13
+ inputSchema: object;
14
+ outputSchema: object;
15
+ systemPrompt: string;
16
+ modelConfig?: ModelConfig;
17
+ maxIterations?: number;
18
+ llmService?: ILLMService;
19
+ }
20
+ export interface AgentRunOptions {
21
+ input: unknown;
22
+ }
23
+ export interface ValidationResult {
24
+ valid: boolean;
25
+ errors?: string[];
26
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "structured-json-agent",
3
+ "version": "1.0.0",
4
+ "description": "A typed and extensible library for creating and running Iterative AI Agents that generate structured JSON output.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "scripts": {
12
+ "build": "rm -rf dist && tsc",
13
+ "prepublishOnly": "npm run build",
14
+ "test": "NODE_OPTIONS='--experimental-vm-modules' jest"
15
+ },
16
+ "keywords": [
17
+ "ai",
18
+ "agent",
19
+ "json",
20
+ "schema",
21
+ "openai",
22
+ "structured-output",
23
+ "llm"
24
+ ],
25
+ "author": "",
26
+ "license": "ISC",
27
+ "devDependencies": {
28
+ "@types/jest": "^30.0.0",
29
+ "@types/node": "^20.0.0",
30
+ "jest": "^30.2.0",
31
+ "ts-jest": "^29.4.6",
32
+ "typescript": "^5.0.0"
33
+ },
34
+ "dependencies": {
35
+ "ajv": "^8.12.0",
36
+ "openai": "^4.0.0"
37
+ },
38
+ "engines": {
39
+ "node": ">=18.0.0"
40
+ }
41
+ }