@aigne/core 1.3.0 → 1.3.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/CHANGELOG.md CHANGED
@@ -22,6 +22,13 @@
22
22
  * rename @aigne/core-next to @aigne/core ([3a81009](https://github.com/AIGNE-io/aigne-framework/commit/3a8100962c81813217b687ae28e8de604419c622))
23
23
  * use text resource from MCP correctly ([8b9eba8](https://github.com/AIGNE-io/aigne-framework/commit/8b9eba83352ec096a2a5d4f410d4c4bde7420bce))
24
24
 
25
+ ## [1.3.1](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.3.0...core-v1.3.1) (2025-03-25)
26
+
27
+
28
+ ### Bug Fixes
29
+
30
+ * **core:** use system message as user message for claude model if needed ([#32](https://github.com/AIGNE-io/aigne-framework/issues/32)) ([316a6d5](https://github.com/AIGNE-io/aigne-framework/commit/316a6d51f885cceee4020c24695f6588f6b7425f))
31
+
25
32
  ## [1.2.0](https://github.com/AIGNE-io/aigne-framework/compare/core-next-v1.1.0...core-next-v1.2.0) (2025-03-18)
26
33
 
27
34
  - chore: release v1.2.0
@@ -5,6 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.ClaudeChatModel = void 0;
7
7
  const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
8
+ const lodash_es_1 = require("lodash-es");
9
+ const json_schema_js_1 = require("../utils/json-schema.js");
8
10
  const type_utils_js_1 = require("../utils/type-utils.js");
9
11
  const chat_model_js_1 = require("./chat-model.js");
10
12
  const CHAT_MODEL_CLAUDE_DEFAULT_MODEL = "claude-3-7-sonnet-latest";
@@ -75,7 +77,7 @@ class ClaudeChatModel extends chat_model_js_1.ChatModel {
75
77
  result.toolCalls = toolCalls
76
78
  .map(({ args, ...c }) => ({
77
79
  ...c,
78
- function: { ...c.function, arguments: JSON.parse(args) },
80
+ function: { ...c.function, arguments: (0, json_schema_js_1.parseJSON)(args) },
79
81
  }))
80
82
  .filter(type_utils_js_1.isNonNullable);
81
83
  }
@@ -132,7 +134,7 @@ function convertMessages({ messages, responseFormat }) {
132
134
  else if (msg.role === "user") {
133
135
  if (!msg.content)
134
136
  throw new Error("User message must have content");
135
- msgs.push({ role: "user", content: contentBlockParamFromContent(msg.content) });
137
+ msgs.push({ role: "user", content: convertContent(msg.content) });
136
138
  }
137
139
  else if (msg.role === "agent") {
138
140
  if (msg.toolCalls?.length) {
@@ -147,7 +149,7 @@ function convertMessages({ messages, responseFormat }) {
147
149
  });
148
150
  }
149
151
  else if (msg.content) {
150
- msgs.push({ role: "assistant", content: contentBlockParamFromContent(msg.content) });
152
+ msgs.push({ role: "assistant", content: convertContent(msg.content) });
151
153
  }
152
154
  else {
153
155
  throw new Error("Agent message must have content or toolCalls");
@@ -157,9 +159,16 @@ function convertMessages({ messages, responseFormat }) {
157
159
  if (responseFormat?.type === "json_schema") {
158
160
  systemMessages.push(`You should provide a json response with schema: ${JSON.stringify(responseFormat.jsonSchema.schema)}`);
159
161
  }
160
- return { messages: msgs, system: systemMessages.join("\n").trim() || undefined };
162
+ const system = systemMessages.join("\n").trim() || undefined;
163
+ // Claude requires at least one message, so we add a system message if there are no messages
164
+ if (msgs.length === 0) {
165
+ if (!system)
166
+ throw new Error("No messages provided");
167
+ return { messages: [{ role: "user", content: system }] };
168
+ }
169
+ return { messages: msgs, system };
161
170
  }
162
- function contentBlockParamFromContent(content) {
171
+ function convertContent(content) {
163
172
  if (typeof content === "string")
164
173
  return content;
165
174
  if (Array.isArray(content)) {
@@ -191,7 +200,9 @@ function convertTools({ tools, toolChoice, }) {
191
200
  ? tools.map((i) => ({
192
201
  name: i.function.name,
193
202
  description: i.function.description,
194
- input_schema: i.function.parameters,
203
+ input_schema: (0, lodash_es_1.isEmpty)(i.function.parameters)
204
+ ? { type: "object" }
205
+ : i.function.parameters,
195
206
  }))
196
207
  : undefined,
197
208
  tool_choice: choice,
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.OpenAIChatModel = void 0;
7
7
  const nanoid_1 = require("nanoid");
8
8
  const openai_1 = __importDefault(require("openai"));
9
+ const json_schema_js_1 = require("../utils/json-schema.js");
9
10
  const type_utils_js_1 = require("../utils/type-utils.js");
10
11
  const chat_model_js_1 = require("./chat-model.js");
11
12
  const CHAT_MODEL_OPENAI_DEFAULT_MODEL = "gpt-4o-mini";
@@ -69,7 +70,7 @@ class OpenAIChatModel extends chat_model_js_1.ChatModel {
69
70
  }
70
71
  const result = {};
71
72
  if (input.responseFormat?.type === "json_schema" && text) {
72
- result.json = JSON.parse(text);
73
+ result.json = (0, json_schema_js_1.parseJSON)(text);
73
74
  }
74
75
  else {
75
76
  result.text = text;
@@ -77,7 +78,7 @@ class OpenAIChatModel extends chat_model_js_1.ChatModel {
77
78
  if (toolCalls.length) {
78
79
  result.toolCalls = toolCalls.map(({ args, ...c }) => ({
79
80
  ...c,
80
- function: { ...c.function, arguments: JSON.parse(args) },
81
+ function: { ...c.function, arguments: (0, json_schema_js_1.parseJSON)(args) },
81
82
  }));
82
83
  }
83
84
  return result;
@@ -1,3 +1,4 @@
1
1
  import type { ZodType } from "zod";
2
2
  import type { Message } from "../agents/agent.js";
3
3
  export declare function outputSchemaToResponseFormatSchema(agentOutput: ZodType<Message>): Record<string, unknown>;
4
+ export declare function parseJSON(json: string): any;
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.outputSchemaToResponseFormatSchema = outputSchemaToResponseFormatSchema;
4
+ exports.parseJSON = parseJSON;
4
5
  const lodash_es_1 = require("lodash-es");
5
6
  const zod_to_json_schema_1 = require("zod-to-json-schema");
7
+ const logger_js_1 = require("./logger.js");
6
8
  function outputSchemaToResponseFormatSchema(agentOutput) {
7
9
  return setAdditionPropertiesDeep((0, zod_to_json_schema_1.zodToJsonSchema)(agentOutput), false);
8
10
  }
@@ -21,3 +23,12 @@ function setAdditionPropertiesDeep(schema, additionalProperties) {
21
23
  }
22
24
  return schema;
23
25
  }
26
+ function parseJSON(json) {
27
+ try {
28
+ return JSON.parse(json);
29
+ }
30
+ catch (error) {
31
+ logger_js_1.logger.debug("Failed to parse JSON", { json, error });
32
+ throw new Error(`Failed to parse JSON ${error.message}`);
33
+ }
34
+ }
@@ -1,3 +1,4 @@
1
1
  import type { ZodType } from "zod";
2
2
  import type { Message } from "../agents/agent.js";
3
3
  export declare function outputSchemaToResponseFormatSchema(agentOutput: ZodType<Message>): Record<string, unknown>;
4
+ export declare function parseJSON(json: string): any;
@@ -1,4 +1,6 @@
1
1
  import Anthropic from "@anthropic-ai/sdk";
2
+ import { isEmpty } from "lodash-es";
3
+ import { parseJSON } from "../utils/json-schema.js";
2
4
  import { isNonNullable } from "../utils/type-utils.js";
3
5
  import { ChatModel, } from "./chat-model.js";
4
6
  const CHAT_MODEL_CLAUDE_DEFAULT_MODEL = "claude-3-7-sonnet-latest";
@@ -69,7 +71,7 @@ export class ClaudeChatModel extends ChatModel {
69
71
  result.toolCalls = toolCalls
70
72
  .map(({ args, ...c }) => ({
71
73
  ...c,
72
- function: { ...c.function, arguments: JSON.parse(args) },
74
+ function: { ...c.function, arguments: parseJSON(args) },
73
75
  }))
74
76
  .filter(isNonNullable);
75
77
  }
@@ -125,7 +127,7 @@ function convertMessages({ messages, responseFormat }) {
125
127
  else if (msg.role === "user") {
126
128
  if (!msg.content)
127
129
  throw new Error("User message must have content");
128
- msgs.push({ role: "user", content: contentBlockParamFromContent(msg.content) });
130
+ msgs.push({ role: "user", content: convertContent(msg.content) });
129
131
  }
130
132
  else if (msg.role === "agent") {
131
133
  if (msg.toolCalls?.length) {
@@ -140,7 +142,7 @@ function convertMessages({ messages, responseFormat }) {
140
142
  });
141
143
  }
142
144
  else if (msg.content) {
143
- msgs.push({ role: "assistant", content: contentBlockParamFromContent(msg.content) });
145
+ msgs.push({ role: "assistant", content: convertContent(msg.content) });
144
146
  }
145
147
  else {
146
148
  throw new Error("Agent message must have content or toolCalls");
@@ -150,9 +152,16 @@ function convertMessages({ messages, responseFormat }) {
150
152
  if (responseFormat?.type === "json_schema") {
151
153
  systemMessages.push(`You should provide a json response with schema: ${JSON.stringify(responseFormat.jsonSchema.schema)}`);
152
154
  }
153
- return { messages: msgs, system: systemMessages.join("\n").trim() || undefined };
155
+ const system = systemMessages.join("\n").trim() || undefined;
156
+ // Claude requires at least one message, so we add a system message if there are no messages
157
+ if (msgs.length === 0) {
158
+ if (!system)
159
+ throw new Error("No messages provided");
160
+ return { messages: [{ role: "user", content: system }] };
161
+ }
162
+ return { messages: msgs, system };
154
163
  }
155
- function contentBlockParamFromContent(content) {
164
+ function convertContent(content) {
156
165
  if (typeof content === "string")
157
166
  return content;
158
167
  if (Array.isArray(content)) {
@@ -184,7 +193,9 @@ function convertTools({ tools, toolChoice, }) {
184
193
  ? tools.map((i) => ({
185
194
  name: i.function.name,
186
195
  description: i.function.description,
187
- input_schema: i.function.parameters,
196
+ input_schema: isEmpty(i.function.parameters)
197
+ ? { type: "object" }
198
+ : i.function.parameters,
188
199
  }))
189
200
  : undefined,
190
201
  tool_choice: choice,
@@ -1,5 +1,6 @@
1
1
  import { nanoid } from "nanoid";
2
2
  import OpenAI from "openai";
3
+ import { parseJSON } from "../utils/json-schema.js";
3
4
  import { isNonNullable } from "../utils/type-utils.js";
4
5
  import { ChatModel, } from "./chat-model.js";
5
6
  const CHAT_MODEL_OPENAI_DEFAULT_MODEL = "gpt-4o-mini";
@@ -63,7 +64,7 @@ export class OpenAIChatModel extends ChatModel {
63
64
  }
64
65
  const result = {};
65
66
  if (input.responseFormat?.type === "json_schema" && text) {
66
- result.json = JSON.parse(text);
67
+ result.json = parseJSON(text);
67
68
  }
68
69
  else {
69
70
  result.text = text;
@@ -71,7 +72,7 @@ export class OpenAIChatModel extends ChatModel {
71
72
  if (toolCalls.length) {
72
73
  result.toolCalls = toolCalls.map(({ args, ...c }) => ({
73
74
  ...c,
74
- function: { ...c.function, arguments: JSON.parse(args) },
75
+ function: { ...c.function, arguments: parseJSON(args) },
75
76
  }));
76
77
  }
77
78
  return result;
@@ -1,3 +1,4 @@
1
1
  import type { ZodType } from "zod";
2
2
  import type { Message } from "../agents/agent.js";
3
3
  export declare function outputSchemaToResponseFormatSchema(agentOutput: ZodType<Message>): Record<string, unknown>;
4
+ export declare function parseJSON(json: string): any;
@@ -1,5 +1,6 @@
1
1
  import { isObject } from "lodash-es";
2
2
  import { zodToJsonSchema } from "zod-to-json-schema";
3
+ import { logger } from "./logger.js";
3
4
  export function outputSchemaToResponseFormatSchema(agentOutput) {
4
5
  return setAdditionPropertiesDeep(zodToJsonSchema(agentOutput), false);
5
6
  }
@@ -18,3 +19,12 @@ function setAdditionPropertiesDeep(schema, additionalProperties) {
18
19
  }
19
20
  return schema;
20
21
  }
22
+ export function parseJSON(json) {
23
+ try {
24
+ return JSON.parse(json);
25
+ }
26
+ catch (error) {
27
+ logger.debug("Failed to parse JSON", { json, error });
28
+ throw new Error(`Failed to parse JSON ${error.message}`);
29
+ }
30
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/core",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "AIGNE core library for building AI-powered applications",
5
5
  "publishConfig": {
6
6
  "access": "public"