@aigne/core 1.42.0 → 1.43.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
@@ -12,6 +12,25 @@
12
12
  * dependencies
13
13
  * @aigne/observability bumped to 0.1.0
14
14
 
15
+ ## [1.43.1](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.43.0...core-v1.43.1) (2025-08-05)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **core:** filter empty memory content ([#312](https://github.com/AIGNE-io/aigne-framework/issues/312)) ([39dd77a](https://github.com/AIGNE-io/aigne-framework/commit/39dd77a68154d51c7a132adccd9f21b8bc461be0))
21
+
22
+ ## [1.43.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.42.0...core-v1.43.0) (2025-08-04)
23
+
24
+
25
+ ### Features
26
+
27
+ * add includeAllStepsOutput option to control TeamAgent sequential streaming behavior ([#305](https://github.com/AIGNE-io/aigne-framework/issues/305)) ([0817475](https://github.com/AIGNE-io/aigne-framework/commit/08174751316b940a70463e71971a19a18b92667b))
28
+
29
+
30
+ ### Bug Fixes
31
+
32
+ * **core:** share skills/agents from context ([#309](https://github.com/AIGNE-io/aigne-framework/issues/309)) ([88dd849](https://github.com/AIGNE-io/aigne-framework/commit/88dd849954c6f3fb68df238be22be3371c734e6e))
33
+
15
34
  ## [1.42.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.41.0...core-v1.42.0) (2025-08-01)
16
35
 
17
36
 
package/README.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @aigne/core
2
2
 
3
+ <p align="center">
4
+ <picture>
5
+ <source srcset="https://raw.githubusercontent.com/AIGNE-io/aigne-framework/main/logo-dark.svg" media="(prefers-color-scheme: dark)">
6
+ <source srcset="https://raw.githubusercontent.com/AIGNE-io/aigne-framework/main/logo.svg" media="(prefers-color-scheme: light)">
7
+ <img src="https://raw.githubusercontent.com/AIGNE-io/aigne-framework/main/logo.svg" alt="AIGNE Logo" width="400" />
8
+ </picture>
9
+ </p>
10
+
3
11
  [![GitHub star chart](https://img.shields.io/github/stars/AIGNE-io/aigne-framework?style=flat-square)](https://star-history.com/#AIGNE-io/aigne-framework)
4
12
  [![Open Issues](https://img.shields.io/github/issues-raw/AIGNE-io/aigne-framework?style=flat-square)](https://github.com/AIGNE-io/aigne-framework/issues)
5
13
  [![codecov](https://codecov.io/gh/AIGNE-io/aigne-framework/graph/badge.svg?token=DO07834RQL)](https://codecov.io/gh/AIGNE-io/aigne-framework)
@@ -156,6 +156,13 @@ export interface TeamAgentOptions<I extends Message, O extends Message> extends
156
156
  * @default false
157
157
  */
158
158
  iterateWithPreviousOutput?: boolean;
159
+ /**
160
+ * Controls whether to include output from all intermediate steps in sequential processing.
161
+ *
162
+ * @see TeamAgent.includeAllStepsOutput for detailed documentation
163
+ * @default false
164
+ */
165
+ includeAllStepsOutput?: boolean;
159
166
  }
160
167
  /**
161
168
  * TeamAgent coordinates a group of agents working together to accomplish tasks.
@@ -230,6 +237,18 @@ export declare class TeamAgent<I extends Message, O extends Message> extends Age
230
237
  * @default false
231
238
  */
232
239
  iterateWithPreviousOutput?: boolean;
240
+ /**
241
+ * Controls whether to include output from all intermediate steps in sequential processing.
242
+ *
243
+ * When `true`, yields output chunks from every agent in the sequential chain.
244
+ * When `false`, only yields output from the final agent.
245
+ *
246
+ * Only affects sequential processing mode. Useful for debugging and monitoring
247
+ * multi-step agent workflows.
248
+ *
249
+ * @default false
250
+ */
251
+ includeAllStepsOutput?: boolean;
233
252
  /**
234
253
  * Process an input message by routing it through the team's agents.
235
254
  *
@@ -83,6 +83,7 @@ class TeamAgent extends agent_js_1.Agent {
83
83
  };
84
84
  this.iterateOn = options.iterateOn;
85
85
  this.iterateWithPreviousOutput = options.iterateWithPreviousOutput;
86
+ this.includeAllStepsOutput = options.includeAllStepsOutput;
86
87
  }
87
88
  /**
88
89
  * The processing mode that determines how agents in the team are executed.
@@ -117,6 +118,18 @@ class TeamAgent extends agent_js_1.Agent {
117
118
  * @default false
118
119
  */
119
120
  iterateWithPreviousOutput;
121
+ /**
122
+ * Controls whether to include output from all intermediate steps in sequential processing.
123
+ *
124
+ * When `true`, yields output chunks from every agent in the sequential chain.
125
+ * When `false`, only yields output from the final agent.
126
+ *
127
+ * Only affects sequential processing mode. Useful for debugging and monitoring
128
+ * multi-step agent workflows.
129
+ *
130
+ * @default false
131
+ */
132
+ includeAllStepsOutput;
120
133
  /**
121
134
  * Process an input message by routing it through the team's agents.
122
135
  *
@@ -212,8 +225,12 @@ class TeamAgent extends agent_js_1.Agent {
212
225
  const output = {};
213
226
  for (const agent of this.skills) {
214
227
  const o = await options.context.invoke(agent, { ...input, ...output }, { ...options, streaming: true });
228
+ const isLast = agent === this.skills[this.skills.length - 1];
215
229
  for await (const chunk of o) {
216
- yield chunk;
230
+ // Only yield the chunk if it is the last agent in the sequence
231
+ if (this.includeAllStepsOutput || isLast) {
232
+ yield chunk;
233
+ }
217
234
  (0, stream_utils_js_1.mergeAgentResponseChunk)(output, chunk);
218
235
  }
219
236
  }
@@ -73,6 +73,7 @@ export interface Context<U extends UserContext = UserContext> extends TypedEvent
73
73
  rootId: string;
74
74
  model?: ChatModel;
75
75
  skills?: Agent[];
76
+ agents: Agent[];
76
77
  observer?: AIGNEObserver;
77
78
  span?: Span;
78
79
  usage: ContextUsage;
@@ -153,6 +154,7 @@ export declare class AIGNEContext implements Context {
153
154
  get messageQueue(): MessageQueue;
154
155
  get model(): ChatModel | undefined;
155
156
  get skills(): Agent<any, any>[] | undefined;
157
+ get agents(): Agent<any, any>[];
156
158
  get observer(): AIGNEObserver | undefined;
157
159
  get limits(): ContextLimits | undefined;
158
160
  get status(): "normal" | "timeout";
@@ -180,7 +182,7 @@ export declare class AIGNEContext implements Context {
180
182
  declare class AIGNEContextShared {
181
183
  private readonly parent?;
182
184
  spans: Span[];
183
- constructor(parent?: (Pick<Context, "model" | "skills" | "limits" | "observer"> & {
185
+ constructor(parent?: (Pick<Context, "model" | "agents" | "skills" | "limits" | "observer"> & {
184
186
  messageQueue?: MessageQueue;
185
187
  events?: Emitter<any>;
186
188
  }) | undefined);
@@ -188,6 +190,7 @@ declare class AIGNEContextShared {
188
190
  readonly events: Emitter<any>;
189
191
  get model(): ChatModel | undefined;
190
192
  get skills(): Agent<any, any>[] | undefined;
193
+ get agents(): Agent<any, any>[];
191
194
  get observer(): AIGNEObserver | undefined;
192
195
  get limits(): ContextLimits | undefined;
193
196
  addSpan(span: Span): void;
@@ -64,6 +64,9 @@ class AIGNEContext {
64
64
  get skills() {
65
65
  return this.internal.skills;
66
66
  }
67
+ get agents() {
68
+ return this.internal.agents;
69
+ }
67
70
  get observer() {
68
71
  return this.internal.observer;
69
72
  }
@@ -300,6 +303,9 @@ class AIGNEContextShared {
300
303
  get skills() {
301
304
  return this.parent?.skills;
302
305
  }
306
+ get agents() {
307
+ return this.parent?.agents ?? [];
308
+ }
303
309
  get observer() {
304
310
  return this.parent?.observer;
305
311
  }
@@ -11,4 +11,6 @@ export * from "./aigne/index.js";
11
11
  export * from "./memory/index.js";
12
12
  export * from "./prompt/prompt-builder.js";
13
13
  export * from "./prompt/template.js";
14
+ export * from "./utils/json-utils.js";
15
+ export * from "./utils/role-utils.js";
14
16
  export * from "./utils/stream-utils.js";
package/lib/cjs/index.js CHANGED
@@ -27,4 +27,6 @@ __exportStar(require("./aigne/index.js"), exports);
27
27
  __exportStar(require("./memory/index.js"), exports);
28
28
  __exportStar(require("./prompt/prompt-builder.js"), exports);
29
29
  __exportStar(require("./prompt/template.js"), exports);
30
+ __exportStar(require("./utils/json-utils.js"), exports);
31
+ __exportStar(require("./utils/role-utils.js"), exports);
30
32
  __exportStar(require("./utils/stream-utils.js"), exports);
@@ -110,7 +110,12 @@ class PromptBuilder {
110
110
  const stringOrStringify = (value) => typeof value === "string" ? value : (0, yaml_1.stringify)(value);
111
111
  for (const { content } of memories) {
112
112
  if ((0, type_utils_js_1.isRecord)(content) && "input" in content && "output" in content) {
113
- messages.push({ role: "user", content: stringOrStringify(content.input) }, { role: "agent", content: stringOrStringify(content.output) });
113
+ if (!(0, type_utils_js_1.isNil)(content.input) && content.input !== "") {
114
+ messages.push({ role: "user", content: stringOrStringify(content.input) });
115
+ }
116
+ if (!(0, type_utils_js_1.isNil)(content.output) && content.output !== "") {
117
+ messages.push({ role: "agent", content: stringOrStringify(content.output) });
118
+ }
114
119
  }
115
120
  else {
116
121
  other.push(content);
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Safely parses JSON text using jaison library which handles malformed JSON better than JSON.parse
3
+ *
4
+ * @param text - The text to parse as JSON
5
+ * @returns Parsed JSON object or null if parsing fails
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const result = safeParseJSON('{"key": "value"}');
10
+ * console.log(result); // { key: "value" }
11
+ *
12
+ * const malformed = safeParseJSON('{"key": "value"'); // Missing closing brace
13
+ * console.log(malformed); // null
14
+ * ```
15
+ */
16
+ export declare function safeParseJSON(text: string): any;
17
+ /**
18
+ * Safely stringifies a value to JSON, handling errors gracefully
19
+ *
20
+ * @param value - The value to stringify
21
+ * @param space - Optional spacing for pretty printing
22
+ * @returns JSON string or null if stringification fails
23
+ */
24
+ export declare function safeStringifyJSON(value: any, space?: number): string | null;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.safeParseJSON = safeParseJSON;
7
+ exports.safeStringifyJSON = safeStringifyJSON;
8
+ const jaison_1 = __importDefault(require("jaison"));
9
+ /**
10
+ * Safely parses JSON text using jaison library which handles malformed JSON better than JSON.parse
11
+ *
12
+ * @param text - The text to parse as JSON
13
+ * @returns Parsed JSON object or null if parsing fails
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const result = safeParseJSON('{"key": "value"}');
18
+ * console.log(result); // { key: "value" }
19
+ *
20
+ * const malformed = safeParseJSON('{"key": "value"'); // Missing closing brace
21
+ * console.log(malformed); // null
22
+ * ```
23
+ */
24
+ function safeParseJSON(text) {
25
+ if (!text)
26
+ return null;
27
+ try {
28
+ return (0, jaison_1.default)(text);
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ }
34
+ /**
35
+ * Safely stringifies a value to JSON, handling errors gracefully
36
+ *
37
+ * @param value - The value to stringify
38
+ * @param space - Optional spacing for pretty printing
39
+ * @returns JSON string or null if stringification fails
40
+ */
41
+ function safeStringifyJSON(value, space) {
42
+ try {
43
+ return JSON.stringify(value, null, space);
44
+ }
45
+ catch {
46
+ return null;
47
+ }
48
+ }
@@ -0,0 +1,31 @@
1
+ import type { Role } from "../agents/chat-model.js";
2
+ /**
3
+ * Standard role mapping for most chat model providers
4
+ * Maps AIGNE framework roles to common provider role names
5
+ */
6
+ export declare const STANDARD_ROLE_MAP: {
7
+ [key in Role]: string;
8
+ };
9
+ /**
10
+ * Creates a role mapper function for a specific provider
11
+ *
12
+ * @param roleMap - Custom role mapping for the provider
13
+ * @returns Function that maps AIGNE roles to provider roles
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * // For standard providers (OpenAI, Anthropic, etc.)
18
+ * const mapRole = createRoleMapper(STANDARD_ROLE_MAP);
19
+ *
20
+ * // For providers with different role names
21
+ * const customMap = { ...STANDARD_ROLE_MAP, agent: "bot" };
22
+ * const customMapper = createRoleMapper(customMap);
23
+ * ```
24
+ */
25
+ export declare function createRoleMapper<T extends string>(roleMap: {
26
+ [key in Role]: T;
27
+ }): (role: Role) => T;
28
+ /**
29
+ * Standard role mapper using the default role mapping
30
+ */
31
+ export declare const mapStandardRole: (role: Role) => string;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mapStandardRole = exports.STANDARD_ROLE_MAP = void 0;
4
+ exports.createRoleMapper = createRoleMapper;
5
+ /**
6
+ * Standard role mapping for most chat model providers
7
+ * Maps AIGNE framework roles to common provider role names
8
+ */
9
+ exports.STANDARD_ROLE_MAP = {
10
+ system: "system",
11
+ user: "user",
12
+ agent: "assistant",
13
+ tool: "tool",
14
+ };
15
+ /**
16
+ * Creates a role mapper function for a specific provider
17
+ *
18
+ * @param roleMap - Custom role mapping for the provider
19
+ * @returns Function that maps AIGNE roles to provider roles
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * // For standard providers (OpenAI, Anthropic, etc.)
24
+ * const mapRole = createRoleMapper(STANDARD_ROLE_MAP);
25
+ *
26
+ * // For providers with different role names
27
+ * const customMap = { ...STANDARD_ROLE_MAP, agent: "bot" };
28
+ * const customMapper = createRoleMapper(customMap);
29
+ * ```
30
+ */
31
+ function createRoleMapper(roleMap) {
32
+ return (role) => roleMap[role];
33
+ }
34
+ /**
35
+ * Standard role mapper using the default role mapping
36
+ */
37
+ exports.mapStandardRole = createRoleMapper(exports.STANDARD_ROLE_MAP);
@@ -156,6 +156,13 @@ export interface TeamAgentOptions<I extends Message, O extends Message> extends
156
156
  * @default false
157
157
  */
158
158
  iterateWithPreviousOutput?: boolean;
159
+ /**
160
+ * Controls whether to include output from all intermediate steps in sequential processing.
161
+ *
162
+ * @see TeamAgent.includeAllStepsOutput for detailed documentation
163
+ * @default false
164
+ */
165
+ includeAllStepsOutput?: boolean;
159
166
  }
160
167
  /**
161
168
  * TeamAgent coordinates a group of agents working together to accomplish tasks.
@@ -230,6 +237,18 @@ export declare class TeamAgent<I extends Message, O extends Message> extends Age
230
237
  * @default false
231
238
  */
232
239
  iterateWithPreviousOutput?: boolean;
240
+ /**
241
+ * Controls whether to include output from all intermediate steps in sequential processing.
242
+ *
243
+ * When `true`, yields output chunks from every agent in the sequential chain.
244
+ * When `false`, only yields output from the final agent.
245
+ *
246
+ * Only affects sequential processing mode. Useful for debugging and monitoring
247
+ * multi-step agent workflows.
248
+ *
249
+ * @default false
250
+ */
251
+ includeAllStepsOutput?: boolean;
233
252
  /**
234
253
  * Process an input message by routing it through the team's agents.
235
254
  *
@@ -73,6 +73,7 @@ export interface Context<U extends UserContext = UserContext> extends TypedEvent
73
73
  rootId: string;
74
74
  model?: ChatModel;
75
75
  skills?: Agent[];
76
+ agents: Agent[];
76
77
  observer?: AIGNEObserver;
77
78
  span?: Span;
78
79
  usage: ContextUsage;
@@ -153,6 +154,7 @@ export declare class AIGNEContext implements Context {
153
154
  get messageQueue(): MessageQueue;
154
155
  get model(): ChatModel | undefined;
155
156
  get skills(): Agent<any, any>[] | undefined;
157
+ get agents(): Agent<any, any>[];
156
158
  get observer(): AIGNEObserver | undefined;
157
159
  get limits(): ContextLimits | undefined;
158
160
  get status(): "normal" | "timeout";
@@ -180,7 +182,7 @@ export declare class AIGNEContext implements Context {
180
182
  declare class AIGNEContextShared {
181
183
  private readonly parent?;
182
184
  spans: Span[];
183
- constructor(parent?: (Pick<Context, "model" | "skills" | "limits" | "observer"> & {
185
+ constructor(parent?: (Pick<Context, "model" | "agents" | "skills" | "limits" | "observer"> & {
184
186
  messageQueue?: MessageQueue;
185
187
  events?: Emitter<any>;
186
188
  }) | undefined);
@@ -188,6 +190,7 @@ declare class AIGNEContextShared {
188
190
  readonly events: Emitter<any>;
189
191
  get model(): ChatModel | undefined;
190
192
  get skills(): Agent<any, any>[] | undefined;
193
+ get agents(): Agent<any, any>[];
191
194
  get observer(): AIGNEObserver | undefined;
192
195
  get limits(): ContextLimits | undefined;
193
196
  addSpan(span: Span): void;
@@ -11,4 +11,6 @@ export * from "./aigne/index.js";
11
11
  export * from "./memory/index.js";
12
12
  export * from "./prompt/prompt-builder.js";
13
13
  export * from "./prompt/template.js";
14
+ export * from "./utils/json-utils.js";
15
+ export * from "./utils/role-utils.js";
14
16
  export * from "./utils/stream-utils.js";
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Safely parses JSON text using jaison library which handles malformed JSON better than JSON.parse
3
+ *
4
+ * @param text - The text to parse as JSON
5
+ * @returns Parsed JSON object or null if parsing fails
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const result = safeParseJSON('{"key": "value"}');
10
+ * console.log(result); // { key: "value" }
11
+ *
12
+ * const malformed = safeParseJSON('{"key": "value"'); // Missing closing brace
13
+ * console.log(malformed); // null
14
+ * ```
15
+ */
16
+ export declare function safeParseJSON(text: string): any;
17
+ /**
18
+ * Safely stringifies a value to JSON, handling errors gracefully
19
+ *
20
+ * @param value - The value to stringify
21
+ * @param space - Optional spacing for pretty printing
22
+ * @returns JSON string or null if stringification fails
23
+ */
24
+ export declare function safeStringifyJSON(value: any, space?: number): string | null;
@@ -0,0 +1,31 @@
1
+ import type { Role } from "../agents/chat-model.js";
2
+ /**
3
+ * Standard role mapping for most chat model providers
4
+ * Maps AIGNE framework roles to common provider role names
5
+ */
6
+ export declare const STANDARD_ROLE_MAP: {
7
+ [key in Role]: string;
8
+ };
9
+ /**
10
+ * Creates a role mapper function for a specific provider
11
+ *
12
+ * @param roleMap - Custom role mapping for the provider
13
+ * @returns Function that maps AIGNE roles to provider roles
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * // For standard providers (OpenAI, Anthropic, etc.)
18
+ * const mapRole = createRoleMapper(STANDARD_ROLE_MAP);
19
+ *
20
+ * // For providers with different role names
21
+ * const customMap = { ...STANDARD_ROLE_MAP, agent: "bot" };
22
+ * const customMapper = createRoleMapper(customMap);
23
+ * ```
24
+ */
25
+ export declare function createRoleMapper<T extends string>(roleMap: {
26
+ [key in Role]: T;
27
+ }): (role: Role) => T;
28
+ /**
29
+ * Standard role mapper using the default role mapping
30
+ */
31
+ export declare const mapStandardRole: (role: Role) => string;
@@ -156,6 +156,13 @@ export interface TeamAgentOptions<I extends Message, O extends Message> extends
156
156
  * @default false
157
157
  */
158
158
  iterateWithPreviousOutput?: boolean;
159
+ /**
160
+ * Controls whether to include output from all intermediate steps in sequential processing.
161
+ *
162
+ * @see TeamAgent.includeAllStepsOutput for detailed documentation
163
+ * @default false
164
+ */
165
+ includeAllStepsOutput?: boolean;
159
166
  }
160
167
  /**
161
168
  * TeamAgent coordinates a group of agents working together to accomplish tasks.
@@ -230,6 +237,18 @@ export declare class TeamAgent<I extends Message, O extends Message> extends Age
230
237
  * @default false
231
238
  */
232
239
  iterateWithPreviousOutput?: boolean;
240
+ /**
241
+ * Controls whether to include output from all intermediate steps in sequential processing.
242
+ *
243
+ * When `true`, yields output chunks from every agent in the sequential chain.
244
+ * When `false`, only yields output from the final agent.
245
+ *
246
+ * Only affects sequential processing mode. Useful for debugging and monitoring
247
+ * multi-step agent workflows.
248
+ *
249
+ * @default false
250
+ */
251
+ includeAllStepsOutput?: boolean;
233
252
  /**
234
253
  * Process an input message by routing it through the team's agents.
235
254
  *
@@ -77,6 +77,7 @@ export class TeamAgent extends Agent {
77
77
  };
78
78
  this.iterateOn = options.iterateOn;
79
79
  this.iterateWithPreviousOutput = options.iterateWithPreviousOutput;
80
+ this.includeAllStepsOutput = options.includeAllStepsOutput;
80
81
  }
81
82
  /**
82
83
  * The processing mode that determines how agents in the team are executed.
@@ -111,6 +112,18 @@ export class TeamAgent extends Agent {
111
112
  * @default false
112
113
  */
113
114
  iterateWithPreviousOutput;
115
+ /**
116
+ * Controls whether to include output from all intermediate steps in sequential processing.
117
+ *
118
+ * When `true`, yields output chunks from every agent in the sequential chain.
119
+ * When `false`, only yields output from the final agent.
120
+ *
121
+ * Only affects sequential processing mode. Useful for debugging and monitoring
122
+ * multi-step agent workflows.
123
+ *
124
+ * @default false
125
+ */
126
+ includeAllStepsOutput;
114
127
  /**
115
128
  * Process an input message by routing it through the team's agents.
116
129
  *
@@ -206,8 +219,12 @@ export class TeamAgent extends Agent {
206
219
  const output = {};
207
220
  for (const agent of this.skills) {
208
221
  const o = await options.context.invoke(agent, { ...input, ...output }, { ...options, streaming: true });
222
+ const isLast = agent === this.skills[this.skills.length - 1];
209
223
  for await (const chunk of o) {
210
- yield chunk;
224
+ // Only yield the chunk if it is the last agent in the sequence
225
+ if (this.includeAllStepsOutput || isLast) {
226
+ yield chunk;
227
+ }
211
228
  mergeAgentResponseChunk(output, chunk);
212
229
  }
213
230
  }
@@ -73,6 +73,7 @@ export interface Context<U extends UserContext = UserContext> extends TypedEvent
73
73
  rootId: string;
74
74
  model?: ChatModel;
75
75
  skills?: Agent[];
76
+ agents: Agent[];
76
77
  observer?: AIGNEObserver;
77
78
  span?: Span;
78
79
  usage: ContextUsage;
@@ -153,6 +154,7 @@ export declare class AIGNEContext implements Context {
153
154
  get messageQueue(): MessageQueue;
154
155
  get model(): ChatModel | undefined;
155
156
  get skills(): Agent<any, any>[] | undefined;
157
+ get agents(): Agent<any, any>[];
156
158
  get observer(): AIGNEObserver | undefined;
157
159
  get limits(): ContextLimits | undefined;
158
160
  get status(): "normal" | "timeout";
@@ -180,7 +182,7 @@ export declare class AIGNEContext implements Context {
180
182
  declare class AIGNEContextShared {
181
183
  private readonly parent?;
182
184
  spans: Span[];
183
- constructor(parent?: (Pick<Context, "model" | "skills" | "limits" | "observer"> & {
185
+ constructor(parent?: (Pick<Context, "model" | "agents" | "skills" | "limits" | "observer"> & {
184
186
  messageQueue?: MessageQueue;
185
187
  events?: Emitter<any>;
186
188
  }) | undefined);
@@ -188,6 +190,7 @@ declare class AIGNEContextShared {
188
190
  readonly events: Emitter<any>;
189
191
  get model(): ChatModel | undefined;
190
192
  get skills(): Agent<any, any>[] | undefined;
193
+ get agents(): Agent<any, any>[];
191
194
  get observer(): AIGNEObserver | undefined;
192
195
  get limits(): ContextLimits | undefined;
193
196
  addSpan(span: Span): void;
@@ -58,6 +58,9 @@ export class AIGNEContext {
58
58
  get skills() {
59
59
  return this.internal.skills;
60
60
  }
61
+ get agents() {
62
+ return this.internal.agents;
63
+ }
61
64
  get observer() {
62
65
  return this.internal.observer;
63
66
  }
@@ -293,6 +296,9 @@ class AIGNEContextShared {
293
296
  get skills() {
294
297
  return this.parent?.skills;
295
298
  }
299
+ get agents() {
300
+ return this.parent?.agents ?? [];
301
+ }
296
302
  get observer() {
297
303
  return this.parent?.observer;
298
304
  }
@@ -11,4 +11,6 @@ export * from "./aigne/index.js";
11
11
  export * from "./memory/index.js";
12
12
  export * from "./prompt/prompt-builder.js";
13
13
  export * from "./prompt/template.js";
14
+ export * from "./utils/json-utils.js";
15
+ export * from "./utils/role-utils.js";
14
16
  export * from "./utils/stream-utils.js";
package/lib/esm/index.js CHANGED
@@ -11,4 +11,6 @@ export * from "./aigne/index.js";
11
11
  export * from "./memory/index.js";
12
12
  export * from "./prompt/prompt-builder.js";
13
13
  export * from "./prompt/template.js";
14
+ export * from "./utils/json-utils.js";
15
+ export * from "./utils/role-utils.js";
14
16
  export * from "./utils/stream-utils.js";
@@ -4,7 +4,7 @@ import { ZodObject } from "zod";
4
4
  import { zodToJsonSchema } from "zod-to-json-schema";
5
5
  import { Agent } from "../agents/agent.js";
6
6
  import { outputSchemaToResponseFormatSchema } from "../utils/json-schema.js";
7
- import { isRecord, unique } from "../utils/type-utils.js";
7
+ import { isNil, isRecord, unique } from "../utils/type-utils.js";
8
8
  import { MEMORY_MESSAGE_TEMPLATE } from "./prompts/memory-message-template.js";
9
9
  import { STRUCTURED_STREAM_INSTRUCTIONS } from "./prompts/structured-stream-instructions.js";
10
10
  import { AgentMessageTemplate, ChatMessagesTemplate, PromptTemplate, SystemMessageTemplate, UserMessageTemplate, } from "./template.js";
@@ -107,7 +107,12 @@ export class PromptBuilder {
107
107
  const stringOrStringify = (value) => typeof value === "string" ? value : stringify(value);
108
108
  for (const { content } of memories) {
109
109
  if (isRecord(content) && "input" in content && "output" in content) {
110
- messages.push({ role: "user", content: stringOrStringify(content.input) }, { role: "agent", content: stringOrStringify(content.output) });
110
+ if (!isNil(content.input) && content.input !== "") {
111
+ messages.push({ role: "user", content: stringOrStringify(content.input) });
112
+ }
113
+ if (!isNil(content.output) && content.output !== "") {
114
+ messages.push({ role: "agent", content: stringOrStringify(content.output) });
115
+ }
111
116
  }
112
117
  else {
113
118
  other.push(content);
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Safely parses JSON text using jaison library which handles malformed JSON better than JSON.parse
3
+ *
4
+ * @param text - The text to parse as JSON
5
+ * @returns Parsed JSON object or null if parsing fails
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const result = safeParseJSON('{"key": "value"}');
10
+ * console.log(result); // { key: "value" }
11
+ *
12
+ * const malformed = safeParseJSON('{"key": "value"'); // Missing closing brace
13
+ * console.log(malformed); // null
14
+ * ```
15
+ */
16
+ export declare function safeParseJSON(text: string): any;
17
+ /**
18
+ * Safely stringifies a value to JSON, handling errors gracefully
19
+ *
20
+ * @param value - The value to stringify
21
+ * @param space - Optional spacing for pretty printing
22
+ * @returns JSON string or null if stringification fails
23
+ */
24
+ export declare function safeStringifyJSON(value: any, space?: number): string | null;
@@ -0,0 +1,41 @@
1
+ import jaison from "jaison";
2
+ /**
3
+ * Safely parses JSON text using jaison library which handles malformed JSON better than JSON.parse
4
+ *
5
+ * @param text - The text to parse as JSON
6
+ * @returns Parsed JSON object or null if parsing fails
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const result = safeParseJSON('{"key": "value"}');
11
+ * console.log(result); // { key: "value" }
12
+ *
13
+ * const malformed = safeParseJSON('{"key": "value"'); // Missing closing brace
14
+ * console.log(malformed); // null
15
+ * ```
16
+ */
17
+ export function safeParseJSON(text) {
18
+ if (!text)
19
+ return null;
20
+ try {
21
+ return jaison(text);
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ }
27
+ /**
28
+ * Safely stringifies a value to JSON, handling errors gracefully
29
+ *
30
+ * @param value - The value to stringify
31
+ * @param space - Optional spacing for pretty printing
32
+ * @returns JSON string or null if stringification fails
33
+ */
34
+ export function safeStringifyJSON(value, space) {
35
+ try {
36
+ return JSON.stringify(value, null, space);
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
@@ -0,0 +1,31 @@
1
+ import type { Role } from "../agents/chat-model.js";
2
+ /**
3
+ * Standard role mapping for most chat model providers
4
+ * Maps AIGNE framework roles to common provider role names
5
+ */
6
+ export declare const STANDARD_ROLE_MAP: {
7
+ [key in Role]: string;
8
+ };
9
+ /**
10
+ * Creates a role mapper function for a specific provider
11
+ *
12
+ * @param roleMap - Custom role mapping for the provider
13
+ * @returns Function that maps AIGNE roles to provider roles
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * // For standard providers (OpenAI, Anthropic, etc.)
18
+ * const mapRole = createRoleMapper(STANDARD_ROLE_MAP);
19
+ *
20
+ * // For providers with different role names
21
+ * const customMap = { ...STANDARD_ROLE_MAP, agent: "bot" };
22
+ * const customMapper = createRoleMapper(customMap);
23
+ * ```
24
+ */
25
+ export declare function createRoleMapper<T extends string>(roleMap: {
26
+ [key in Role]: T;
27
+ }): (role: Role) => T;
28
+ /**
29
+ * Standard role mapper using the default role mapping
30
+ */
31
+ export declare const mapStandardRole: (role: Role) => string;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Standard role mapping for most chat model providers
3
+ * Maps AIGNE framework roles to common provider role names
4
+ */
5
+ export const STANDARD_ROLE_MAP = {
6
+ system: "system",
7
+ user: "user",
8
+ agent: "assistant",
9
+ tool: "tool",
10
+ };
11
+ /**
12
+ * Creates a role mapper function for a specific provider
13
+ *
14
+ * @param roleMap - Custom role mapping for the provider
15
+ * @returns Function that maps AIGNE roles to provider roles
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * // For standard providers (OpenAI, Anthropic, etc.)
20
+ * const mapRole = createRoleMapper(STANDARD_ROLE_MAP);
21
+ *
22
+ * // For providers with different role names
23
+ * const customMap = { ...STANDARD_ROLE_MAP, agent: "bot" };
24
+ * const customMapper = createRoleMapper(customMap);
25
+ * ```
26
+ */
27
+ export function createRoleMapper(roleMap) {
28
+ return (role) => roleMap[role];
29
+ }
30
+ /**
31
+ * Standard role mapper using the default role mapping
32
+ */
33
+ export const mapStandardRole = createRoleMapper(STANDARD_ROLE_MAP);
package/package.json CHANGED
@@ -1,17 +1,20 @@
1
1
  {
2
2
  "name": "@aigne/core",
3
- "version": "1.42.0",
3
+ "version": "1.43.1",
4
4
  "description": "AIGNE core library for building AI-powered applications",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
8
  "author": "Arcblock <blocklet@arcblock.io> https://github.com/blocklet",
9
- "homepage": "https://github.com/AIGNE-io/aigne-framework",
9
+ "homepage": "https://www.aigne.io/framework",
10
10
  "license": "Elastic-2.0",
11
11
  "repository": {
12
12
  "type": "git",
13
13
  "url": "git+https://github.com/AIGNE-io/aigne-framework"
14
14
  },
15
+ "bugs": {
16
+ "url": "https://github.com/AIGNE-io/aigne-framework/issues"
17
+ },
15
18
  "files": [
16
19
  "lib/cjs",
17
20
  "lib/dts",
@@ -74,6 +77,7 @@
74
77
  "eventsource-parser": "^3.0.3",
75
78
  "fast-deep-equal": "^3.1.3",
76
79
  "immer": "^10.1.1",
80
+ "jaison": "^2.0.2",
77
81
  "jsonata": "^2.0.6",
78
82
  "mustache": "^4.2.0",
79
83
  "nanoid": "^5.1.5",