@aigne/core 1.61.0-beta.3 → 1.61.0-beta.5
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/CHANGELOG.md +23 -0
- package/lib/cjs/agents/chat-model.d.ts +9 -0
- package/lib/cjs/agents/chat-model.js +28 -18
- package/lib/cjs/utils/json-schema.d.ts +2 -1
- package/lib/cjs/utils/json-schema.js +25 -0
- package/lib/dts/agents/chat-model.d.ts +9 -0
- package/lib/dts/utils/json-schema.d.ts +2 -1
- package/lib/esm/agents/chat-model.d.ts +9 -0
- package/lib/esm/agents/chat-model.js +28 -18
- package/lib/esm/utils/json-schema.d.ts +2 -1
- package/lib/esm/utils/json-schema.js +23 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.61.0-beta.5](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.61.0-beta.4...core-v1.61.0-beta.5) (2025-09-25)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **core:** add automatic JSON parsing and validation for structured outputs ([#548](https://github.com/AIGNE-io/aigne-framework/issues/548)) ([9077f93](https://github.com/AIGNE-io/aigne-framework/commit/9077f93856865915aaf5e8caa5638ef0b7f05b1e))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @aigne/observability-api bumped to 0.11.0-beta
|
|
16
|
+
|
|
17
|
+
## [1.61.0-beta.4](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.61.0-beta.3...core-v1.61.0-beta.4) (2025-09-25)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Dependencies
|
|
21
|
+
|
|
22
|
+
* The following workspace dependencies were updated
|
|
23
|
+
* dependencies
|
|
24
|
+
* @aigne/observability-api bumped to 0.10.5-beta
|
|
25
|
+
|
|
3
26
|
## [1.61.0-beta.3](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.61.0-beta.2...core-v1.61.0-beta.3) (2025-09-24)
|
|
4
27
|
|
|
5
28
|
|
|
@@ -111,6 +111,15 @@ export declare abstract class ChatModel extends Model<ChatModelInput, ChatModelO
|
|
|
111
111
|
*/
|
|
112
112
|
abstract process(input: ChatModelInput, options: AgentInvokeOptions): PromiseOrValue<AgentProcessResult<ChatModelOutput>>;
|
|
113
113
|
protected processAgentOutput(input: ChatModelInput, output: Exclude<AgentResponse<ChatModelOutput>, AgentResponseStream<ChatModelOutput>>, options: AgentInvokeOptions): Promise<ChatModelOutput>;
|
|
114
|
+
protected validateJsonSchema<T>(schema: object, data: T, options?: {
|
|
115
|
+
safe?: false;
|
|
116
|
+
}): T;
|
|
117
|
+
protected validateJsonSchema<T>(schema: object, data: T, options: {
|
|
118
|
+
safe: true;
|
|
119
|
+
}): z.SafeParseReturnType<T, T>;
|
|
120
|
+
protected validateJsonSchema<T>(schema: object, data: T, options?: {
|
|
121
|
+
safe?: boolean;
|
|
122
|
+
}): T | z.SafeParseReturnType<T, T>;
|
|
114
123
|
}
|
|
115
124
|
/**
|
|
116
125
|
* Input message format for ChatModel
|
|
@@ -35,8 +35,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.chatModelOutputUsageSchema = exports.unionContentSchema = exports.textContentSchema = exports.roleSchema = exports.ChatModel = exports.StructuredOutputError = void 0;
|
|
37
37
|
const index_js_1 = require("@aigne/platform-helpers/nodejs/index.js");
|
|
38
|
-
const ajv_1 = require("ajv");
|
|
39
38
|
const zod_1 = require("zod");
|
|
39
|
+
const zod_from_json_schema_1 = require("zod-from-json-schema");
|
|
40
|
+
const json_schema_js_1 = require("../utils/json-schema.js");
|
|
40
41
|
const type_utils_js_1 = require("../utils/type-utils.js");
|
|
41
42
|
const agent_js_1 = require("./agent.js");
|
|
42
43
|
const model_js_1 = require("./model.js");
|
|
@@ -213,19 +214,6 @@ class ChatModel extends model_js_1.Model {
|
|
|
213
214
|
* @param options Options for invoking the agent
|
|
214
215
|
*/
|
|
215
216
|
async postprocess(input, output, options) {
|
|
216
|
-
// Restore original tool names in the output
|
|
217
|
-
if (output.toolCalls?.length) {
|
|
218
|
-
const toolsMap = input._toolsMap;
|
|
219
|
-
if (toolsMap) {
|
|
220
|
-
for (const toolCall of output.toolCalls) {
|
|
221
|
-
const originalTool = toolsMap[toolCall.function.name];
|
|
222
|
-
if (!originalTool) {
|
|
223
|
-
throw new Error(`Tool "${toolCall.function.name}" not found in tools map`);
|
|
224
|
-
}
|
|
225
|
-
toolCall.function.name = originalTool.function.name;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
217
|
super.postprocess(input, output, options);
|
|
230
218
|
const { usage } = output;
|
|
231
219
|
if (usage) {
|
|
@@ -245,16 +233,38 @@ class ChatModel extends model_js_1.Model {
|
|
|
245
233
|
}
|
|
246
234
|
// Remove fields with `null` value for validation
|
|
247
235
|
output = (0, type_utils_js_1.omitByDeep)(output, (value) => (0, type_utils_js_1.isNil)(value));
|
|
236
|
+
const toolCalls = output.toolCalls;
|
|
248
237
|
if (input.responseFormat?.type === "json_schema" &&
|
|
249
238
|
// NOTE: Should not validate if there are tool calls
|
|
250
|
-
!
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
239
|
+
!toolCalls?.length) {
|
|
240
|
+
output.json = this.validateJsonSchema(input.responseFormat.jsonSchema.schema, output.json);
|
|
241
|
+
}
|
|
242
|
+
// Restore original tool names in the output
|
|
243
|
+
if (toolCalls?.length) {
|
|
244
|
+
const toolsMap = input._toolsMap;
|
|
245
|
+
if (toolsMap) {
|
|
246
|
+
for (const toolCall of toolCalls) {
|
|
247
|
+
const originalTool = toolsMap[toolCall.function.name];
|
|
248
|
+
if (!originalTool) {
|
|
249
|
+
throw new Error(`Tool "${toolCall.function.name}" not found in tools map`);
|
|
250
|
+
}
|
|
251
|
+
toolCall.function.name = originalTool.function.name;
|
|
252
|
+
toolCall.function.arguments = this.validateJsonSchema(originalTool.function.parameters, toolCall.function.arguments);
|
|
253
|
+
}
|
|
254
254
|
}
|
|
255
255
|
}
|
|
256
256
|
return super.processAgentOutput(input, output, options);
|
|
257
257
|
}
|
|
258
|
+
validateJsonSchema(schema, data, options) {
|
|
259
|
+
const s = (0, json_schema_js_1.wrapAutoParseJsonSchema)((0, zod_from_json_schema_1.convertJsonSchemaToZod)(schema));
|
|
260
|
+
const r = s.safeParse(data);
|
|
261
|
+
if (options?.safe)
|
|
262
|
+
return r;
|
|
263
|
+
if (r.error) {
|
|
264
|
+
throw new StructuredOutputError(`Output JSON does not conform to the provided JSON schema: ${r.error.errors.map((i) => `${i.path}: ${i.message}`).join(", ")}`);
|
|
265
|
+
}
|
|
266
|
+
return r.data;
|
|
267
|
+
}
|
|
258
268
|
}
|
|
259
269
|
exports.ChatModel = ChatModel;
|
|
260
270
|
exports.roleSchema = zod_1.z.union([
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ZodType, z } from "zod";
|
|
2
2
|
import type { Message } from "../agents/agent.js";
|
|
3
3
|
export declare function outputSchemaToResponseFormatSchema(agentOutput: ZodType<Message>): Record<string, unknown>;
|
|
4
4
|
export declare function parseJSON(json: string): any;
|
|
@@ -11,3 +11,4 @@ export declare function parseJSON(json: string): any;
|
|
|
11
11
|
*/
|
|
12
12
|
export declare function ensureZodUnionArray<T extends z.ZodType>(union: T[]): [T, T, ...T[]];
|
|
13
13
|
export declare function isZodSchema(schema: ZodType): schema is ZodType;
|
|
14
|
+
export declare const wrapAutoParseJsonSchema: <T extends ZodType>(schema: T) => T;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wrapAutoParseJsonSchema = void 0;
|
|
3
4
|
exports.outputSchemaToResponseFormatSchema = outputSchemaToResponseFormatSchema;
|
|
4
5
|
exports.parseJSON = parseJSON;
|
|
5
6
|
exports.ensureZodUnionArray = ensureZodUnionArray;
|
|
6
7
|
exports.isZodSchema = isZodSchema;
|
|
8
|
+
const zod_1 = require("zod");
|
|
7
9
|
const zod_to_json_schema_1 = require("zod-to-json-schema");
|
|
10
|
+
const json_utils_js_1 = require("./json-utils.js");
|
|
8
11
|
const logger_js_1 = require("./logger.js");
|
|
9
12
|
const type_utils_js_1 = require("./type-utils.js");
|
|
10
13
|
function outputSchemaToResponseFormatSchema(agentOutput) {
|
|
@@ -90,3 +93,25 @@ function convertNullableToOptional(schema) {
|
|
|
90
93
|
}
|
|
91
94
|
return [schema, false];
|
|
92
95
|
}
|
|
96
|
+
const wrapJsonParse = (schema) => {
|
|
97
|
+
return zod_1.z.preprocess((val) => (typeof val === "string" ? (0, json_utils_js_1.safeParseJSON)(val) : val), schema);
|
|
98
|
+
};
|
|
99
|
+
const wrapAutoParseJsonSchema = (schema) => {
|
|
100
|
+
if (schema instanceof zod_1.z.ZodNullable)
|
|
101
|
+
return zod_1.z.nullable((0, exports.wrapAutoParseJsonSchema)(schema._def.innerType));
|
|
102
|
+
if (schema instanceof zod_1.z.ZodOptional)
|
|
103
|
+
return zod_1.z.optional((0, exports.wrapAutoParseJsonSchema)(schema._def.innerType));
|
|
104
|
+
if (schema instanceof zod_1.z.ZodObject) {
|
|
105
|
+
const newSchema = schema.extend(Object.fromEntries(Object.entries(schema.shape).map(([key, value]) => [
|
|
106
|
+
key,
|
|
107
|
+
(0, exports.wrapAutoParseJsonSchema)(value),
|
|
108
|
+
])));
|
|
109
|
+
return wrapJsonParse(newSchema);
|
|
110
|
+
}
|
|
111
|
+
if (schema instanceof zod_1.z.ZodArray) {
|
|
112
|
+
schema._def.type = (0, exports.wrapAutoParseJsonSchema)(schema._def.type);
|
|
113
|
+
return wrapJsonParse(schema);
|
|
114
|
+
}
|
|
115
|
+
return schema;
|
|
116
|
+
};
|
|
117
|
+
exports.wrapAutoParseJsonSchema = wrapAutoParseJsonSchema;
|
|
@@ -111,6 +111,15 @@ export declare abstract class ChatModel extends Model<ChatModelInput, ChatModelO
|
|
|
111
111
|
*/
|
|
112
112
|
abstract process(input: ChatModelInput, options: AgentInvokeOptions): PromiseOrValue<AgentProcessResult<ChatModelOutput>>;
|
|
113
113
|
protected processAgentOutput(input: ChatModelInput, output: Exclude<AgentResponse<ChatModelOutput>, AgentResponseStream<ChatModelOutput>>, options: AgentInvokeOptions): Promise<ChatModelOutput>;
|
|
114
|
+
protected validateJsonSchema<T>(schema: object, data: T, options?: {
|
|
115
|
+
safe?: false;
|
|
116
|
+
}): T;
|
|
117
|
+
protected validateJsonSchema<T>(schema: object, data: T, options: {
|
|
118
|
+
safe: true;
|
|
119
|
+
}): z.SafeParseReturnType<T, T>;
|
|
120
|
+
protected validateJsonSchema<T>(schema: object, data: T, options?: {
|
|
121
|
+
safe?: boolean;
|
|
122
|
+
}): T | z.SafeParseReturnType<T, T>;
|
|
114
123
|
}
|
|
115
124
|
/**
|
|
116
125
|
* Input message format for ChatModel
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ZodType, z } from "zod";
|
|
2
2
|
import type { Message } from "../agents/agent.js";
|
|
3
3
|
export declare function outputSchemaToResponseFormatSchema(agentOutput: ZodType<Message>): Record<string, unknown>;
|
|
4
4
|
export declare function parseJSON(json: string): any;
|
|
@@ -11,3 +11,4 @@ export declare function parseJSON(json: string): any;
|
|
|
11
11
|
*/
|
|
12
12
|
export declare function ensureZodUnionArray<T extends z.ZodType>(union: T[]): [T, T, ...T[]];
|
|
13
13
|
export declare function isZodSchema(schema: ZodType): schema is ZodType;
|
|
14
|
+
export declare const wrapAutoParseJsonSchema: <T extends ZodType>(schema: T) => T;
|
|
@@ -111,6 +111,15 @@ export declare abstract class ChatModel extends Model<ChatModelInput, ChatModelO
|
|
|
111
111
|
*/
|
|
112
112
|
abstract process(input: ChatModelInput, options: AgentInvokeOptions): PromiseOrValue<AgentProcessResult<ChatModelOutput>>;
|
|
113
113
|
protected processAgentOutput(input: ChatModelInput, output: Exclude<AgentResponse<ChatModelOutput>, AgentResponseStream<ChatModelOutput>>, options: AgentInvokeOptions): Promise<ChatModelOutput>;
|
|
114
|
+
protected validateJsonSchema<T>(schema: object, data: T, options?: {
|
|
115
|
+
safe?: false;
|
|
116
|
+
}): T;
|
|
117
|
+
protected validateJsonSchema<T>(schema: object, data: T, options: {
|
|
118
|
+
safe: true;
|
|
119
|
+
}): z.SafeParseReturnType<T, T>;
|
|
120
|
+
protected validateJsonSchema<T>(schema: object, data: T, options?: {
|
|
121
|
+
safe?: boolean;
|
|
122
|
+
}): T | z.SafeParseReturnType<T, T>;
|
|
114
123
|
}
|
|
115
124
|
/**
|
|
116
125
|
* Input message format for ChatModel
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
|
|
2
|
-
import { Ajv } from "ajv";
|
|
3
2
|
import { z } from "zod";
|
|
3
|
+
import { convertJsonSchemaToZod } from "zod-from-json-schema";
|
|
4
|
+
import { wrapAutoParseJsonSchema } from "../utils/json-schema.js";
|
|
4
5
|
import { checkArguments, isNil, omitByDeep } from "../utils/type-utils.js";
|
|
5
6
|
import { agentOptionsSchema, } from "./agent.js";
|
|
6
7
|
import { fileContentSchema, fileUnionContentSchema, localContentSchema, Model, urlContentSchema, } from "./model.js";
|
|
@@ -176,19 +177,6 @@ export class ChatModel extends Model {
|
|
|
176
177
|
* @param options Options for invoking the agent
|
|
177
178
|
*/
|
|
178
179
|
async postprocess(input, output, options) {
|
|
179
|
-
// Restore original tool names in the output
|
|
180
|
-
if (output.toolCalls?.length) {
|
|
181
|
-
const toolsMap = input._toolsMap;
|
|
182
|
-
if (toolsMap) {
|
|
183
|
-
for (const toolCall of output.toolCalls) {
|
|
184
|
-
const originalTool = toolsMap[toolCall.function.name];
|
|
185
|
-
if (!originalTool) {
|
|
186
|
-
throw new Error(`Tool "${toolCall.function.name}" not found in tools map`);
|
|
187
|
-
}
|
|
188
|
-
toolCall.function.name = originalTool.function.name;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
180
|
super.postprocess(input, output, options);
|
|
193
181
|
const { usage } = output;
|
|
194
182
|
if (usage) {
|
|
@@ -208,16 +196,38 @@ export class ChatModel extends Model {
|
|
|
208
196
|
}
|
|
209
197
|
// Remove fields with `null` value for validation
|
|
210
198
|
output = omitByDeep(output, (value) => isNil(value));
|
|
199
|
+
const toolCalls = output.toolCalls;
|
|
211
200
|
if (input.responseFormat?.type === "json_schema" &&
|
|
212
201
|
// NOTE: Should not validate if there are tool calls
|
|
213
|
-
!
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
202
|
+
!toolCalls?.length) {
|
|
203
|
+
output.json = this.validateJsonSchema(input.responseFormat.jsonSchema.schema, output.json);
|
|
204
|
+
}
|
|
205
|
+
// Restore original tool names in the output
|
|
206
|
+
if (toolCalls?.length) {
|
|
207
|
+
const toolsMap = input._toolsMap;
|
|
208
|
+
if (toolsMap) {
|
|
209
|
+
for (const toolCall of toolCalls) {
|
|
210
|
+
const originalTool = toolsMap[toolCall.function.name];
|
|
211
|
+
if (!originalTool) {
|
|
212
|
+
throw new Error(`Tool "${toolCall.function.name}" not found in tools map`);
|
|
213
|
+
}
|
|
214
|
+
toolCall.function.name = originalTool.function.name;
|
|
215
|
+
toolCall.function.arguments = this.validateJsonSchema(originalTool.function.parameters, toolCall.function.arguments);
|
|
216
|
+
}
|
|
217
217
|
}
|
|
218
218
|
}
|
|
219
219
|
return super.processAgentOutput(input, output, options);
|
|
220
220
|
}
|
|
221
|
+
validateJsonSchema(schema, data, options) {
|
|
222
|
+
const s = wrapAutoParseJsonSchema(convertJsonSchemaToZod(schema));
|
|
223
|
+
const r = s.safeParse(data);
|
|
224
|
+
if (options?.safe)
|
|
225
|
+
return r;
|
|
226
|
+
if (r.error) {
|
|
227
|
+
throw new StructuredOutputError(`Output JSON does not conform to the provided JSON schema: ${r.error.errors.map((i) => `${i.path}: ${i.message}`).join(", ")}`);
|
|
228
|
+
}
|
|
229
|
+
return r.data;
|
|
230
|
+
}
|
|
221
231
|
}
|
|
222
232
|
export const roleSchema = z.union([
|
|
223
233
|
z.literal("system"),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ZodType, z } from "zod";
|
|
2
2
|
import type { Message } from "../agents/agent.js";
|
|
3
3
|
export declare function outputSchemaToResponseFormatSchema(agentOutput: ZodType<Message>): Record<string, unknown>;
|
|
4
4
|
export declare function parseJSON(json: string): any;
|
|
@@ -11,3 +11,4 @@ export declare function parseJSON(json: string): any;
|
|
|
11
11
|
*/
|
|
12
12
|
export declare function ensureZodUnionArray<T extends z.ZodType>(union: T[]): [T, T, ...T[]];
|
|
13
13
|
export declare function isZodSchema(schema: ZodType): schema is ZodType;
|
|
14
|
+
export declare const wrapAutoParseJsonSchema: <T extends ZodType>(schema: T) => T;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
1
2
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
3
|
+
import { safeParseJSON } from "./json-utils.js";
|
|
2
4
|
import { logger } from "./logger.js";
|
|
3
5
|
import { isEmpty, isRecord } from "./type-utils.js";
|
|
4
6
|
export function outputSchemaToResponseFormatSchema(agentOutput) {
|
|
@@ -84,3 +86,24 @@ function convertNullableToOptional(schema) {
|
|
|
84
86
|
}
|
|
85
87
|
return [schema, false];
|
|
86
88
|
}
|
|
89
|
+
const wrapJsonParse = (schema) => {
|
|
90
|
+
return z.preprocess((val) => (typeof val === "string" ? safeParseJSON(val) : val), schema);
|
|
91
|
+
};
|
|
92
|
+
export const wrapAutoParseJsonSchema = (schema) => {
|
|
93
|
+
if (schema instanceof z.ZodNullable)
|
|
94
|
+
return z.nullable(wrapAutoParseJsonSchema(schema._def.innerType));
|
|
95
|
+
if (schema instanceof z.ZodOptional)
|
|
96
|
+
return z.optional(wrapAutoParseJsonSchema(schema._def.innerType));
|
|
97
|
+
if (schema instanceof z.ZodObject) {
|
|
98
|
+
const newSchema = schema.extend(Object.fromEntries(Object.entries(schema.shape).map(([key, value]) => [
|
|
99
|
+
key,
|
|
100
|
+
wrapAutoParseJsonSchema(value),
|
|
101
|
+
])));
|
|
102
|
+
return wrapJsonParse(newSchema);
|
|
103
|
+
}
|
|
104
|
+
if (schema instanceof z.ZodArray) {
|
|
105
|
+
schema._def.type = wrapAutoParseJsonSchema(schema._def.type);
|
|
106
|
+
return wrapJsonParse(schema);
|
|
107
|
+
}
|
|
108
|
+
return schema;
|
|
109
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/core",
|
|
3
|
-
"version": "1.61.0-beta.
|
|
3
|
+
"version": "1.61.0-beta.5",
|
|
4
4
|
"description": "The functional core of agentic AI",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -71,7 +71,6 @@
|
|
|
71
71
|
"@opentelemetry/api": "^1.9.0",
|
|
72
72
|
"@opentelemetry/sdk-trace-base": "^2.1.0",
|
|
73
73
|
"@types/debug": "^4.1.12",
|
|
74
|
-
"ajv": "^8.17.1",
|
|
75
74
|
"camelize-ts": "^3.0.0",
|
|
76
75
|
"content-type": "^1.0.5",
|
|
77
76
|
"debug": "^4.4.3",
|
|
@@ -91,8 +90,9 @@
|
|
|
91
90
|
"uuid": "^13.0.0",
|
|
92
91
|
"yaml": "^2.8.1",
|
|
93
92
|
"zod": "^3.25.67",
|
|
93
|
+
"zod-from-json-schema": "^0.0.5",
|
|
94
94
|
"zod-to-json-schema": "^3.24.6",
|
|
95
|
-
"@aigne/observability-api": "^0.
|
|
95
|
+
"@aigne/observability-api": "^0.11.0-beta",
|
|
96
96
|
"@aigne/platform-helpers": "^0.6.3-beta"
|
|
97
97
|
},
|
|
98
98
|
"devDependencies": {
|