@aigne/core 1.45.0 → 1.46.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,33 @@
12
12
  * dependencies
13
13
  * @aigne/observability bumped to 0.1.0
14
14
 
15
+ ## [1.46.1](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.46.0...core-v1.46.1) (2025-08-08)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **core:** auto trim trailing whitespace for AIAgent with structuredStreamMode enabled ([#334](https://github.com/AIGNE-io/aigne-framework/issues/334)) ([342eb49](https://github.com/AIGNE-io/aigne-framework/commit/342eb493995809f01da02fca6975ea6e52ecbd3a))
21
+ * **core:** hide internal prop toolsMap from trace logs ([#335](https://github.com/AIGNE-io/aigne-framework/issues/335)) ([bcec317](https://github.com/AIGNE-io/aigne-framework/commit/bcec317bf436988e5f43af05f649196bdbd6ac55))
22
+
23
+ ## [1.46.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.45.0...core-v1.46.0) (2025-08-06)
24
+
25
+
26
+ ### Features
27
+
28
+ * **cli:** support custom task title of agent in cli ([#328](https://github.com/AIGNE-io/aigne-framework/issues/328)) ([128d75f](https://github.com/AIGNE-io/aigne-framework/commit/128d75fb42ca470b47a2793d79c92d7bb64cfedb))
29
+
30
+
31
+ ### Bug Fixes
32
+
33
+ * **core:** improve hook handling in agent and context ([#325](https://github.com/AIGNE-io/aigne-framework/issues/325)) ([c858fec](https://github.com/AIGNE-io/aigne-framework/commit/c858fecb08453c2daca9708f4b8a9c135fac40b0))
34
+
35
+
36
+ ### Dependencies
37
+
38
+ * The following workspace dependencies were updated
39
+ * dependencies
40
+ * @aigne/platform-helpers bumped to 0.6.0
41
+
15
42
  ## [1.45.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.44.0...core-v1.45.0) (2025-08-06)
16
43
 
17
44
 
package/README.md CHANGED
@@ -6,6 +6,8 @@
6
6
  <source srcset="https://raw.githubusercontent.com/AIGNE-io/aigne-framework/main/logo.svg" media="(prefers-color-scheme: light)">
7
7
  <img src="https://raw.githubusercontent.com/AIGNE-io/aigne-framework/main/logo.svg" alt="AIGNE Logo" width="400" />
8
8
  </picture>
9
+
10
+ <center>The functional core of agentic AI</center>
9
11
  </p>
10
12
 
11
13
  [![GitHub star chart](https://img.shields.io/github/stars/AIGNE-io/aigne-framework?style=flat-square)](https://star-history.com/#AIGNE-io/aigne-framework)
@@ -14,12 +16,16 @@
14
16
  [![NPM Version](https://img.shields.io/npm/v/@aigne/core)](https://www.npmjs.com/package/@aigne/core)
15
17
  [![Elastic-2.0 licensed](https://img.shields.io/npm/l/@aigne/core)](https://github.com/AIGNE-io/aigne-framework/blob/main/LICENSE)
16
18
 
17
- Core library of [AIGNE Framework](https://github.com/AIGNE-io/aigne-framework) for building AI-powered applications.
18
-
19
19
  ## Introduction
20
20
 
21
21
  `@aigne/core` is the foundation component of [AIGNE Framework](https://github.com/AIGNE-io/aigne-framework), providing the essential modules and tools needed to build AI-driven applications. This package implements the core functionalities of the framework, including agent systems, aigne environment, model integrations, and workflow pattern support.
22
22
 
23
+ <picture>
24
+ <source srcset="https://raw.githubusercontent.com/AIGNE-io/aigne-framework/main/assets/aigne-framework-dark.png" media="(prefers-color-scheme: dark)">
25
+ <source srcset="https://raw.githubusercontent.com/AIGNE-io/aigne-framework/main/assets/aigne-framework.png" media="(prefers-color-scheme: light)">
26
+ <img src="https://raw.githubusercontent.com/AIGNE-io/aigne-framework/main/aigne-framework.png" alt="AIGNE Arch" />
27
+ </picture>
28
+
23
29
  ## Features
24
30
 
25
31
  * **Multiple AI Model Support**: Built-in support for OpenAI, Gemini, Claude, Nova, and other mainstream AI models, easily extensible to support additional models
@@ -72,6 +72,7 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
72
72
  * for documentation and debugging
73
73
  */
74
74
  description?: string;
75
+ taskTitle?: string;
75
76
  /**
76
77
  * Zod schema defining the input message structure
77
78
  *
@@ -256,6 +257,7 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
256
257
  * each other's roles in a multi-agent system
257
258
  */
258
259
  readonly description?: string;
260
+ taskTitle?: string;
259
261
  private readonly _inputSchema?;
260
262
  defaultInput?: Partial<{
261
263
  [key in keyof I]: {
@@ -104,6 +104,7 @@ class Agent {
104
104
  this.name = options.name || this.constructor.name;
105
105
  this.alias = options.alias;
106
106
  this.description = options.description;
107
+ this.taskTitle = options.taskTitle;
107
108
  if (inputSchema)
108
109
  checkAgentInputOutputSchema(inputSchema);
109
110
  if (outputSchema)
@@ -193,6 +194,7 @@ class Agent {
193
194
  * each other's roles in a multi-agent system
194
195
  */
195
196
  description;
197
+ taskTitle;
196
198
  _inputSchema;
197
199
  defaultInput;
198
200
  _outputSchema;
@@ -388,7 +390,7 @@ class Agent {
388
390
  async callHooks(hook, input, options) {
389
391
  const { context } = options;
390
392
  const result = {};
391
- for (const hooks of (0, type_utils_js_1.flat)(options.hooks, this.hooks)) {
393
+ for (const hooks of (0, type_utils_js_1.flat)(options.hooks, options.context.hooks, this.hooks)) {
392
394
  const h = hooks[hook];
393
395
  if (!h)
394
396
  continue;
@@ -103,7 +103,11 @@ class ChatModel extends agent_js_1.Agent {
103
103
  toolsMap[name] = originalTool;
104
104
  }
105
105
  this.validateToolNames(tools);
106
- Object.assign(input, { _toolsMap: toolsMap, tools });
106
+ Object.assign(input, { tools });
107
+ Object.defineProperty(input, "_toolsMap", {
108
+ value: toolsMap,
109
+ enumerable: false,
110
+ });
107
111
  }
108
112
  }
109
113
  /**
@@ -1,7 +1,7 @@
1
1
  import type { AIGNEObserver } from "@aigne/observability-api";
2
2
  import type { Span } from "@opentelemetry/api";
3
3
  import { Emitter } from "strict-event-emitter";
4
- import { type Agent, type AgentInvokeOptions, type AgentProcessAsyncGenerator, type AgentResponse, type AgentResponseStream, type Message } from "../agents/agent.js";
4
+ import { type Agent, type AgentHooks, type AgentInvokeOptions, type AgentProcessAsyncGenerator, type AgentResponse, type AgentResponseStream, type Message } from "../agents/agent.js";
5
5
  import type { ChatModel } from "../agents/chat-model.js";
6
6
  import { UserAgent } from "../agents/user-agent.js";
7
7
  import type { Memory } from "../memory/memory.js";
@@ -80,6 +80,7 @@ export interface Context<U extends UserContext = UserContext> extends TypedEvent
80
80
  limits?: ContextLimits;
81
81
  status?: "normal" | "timeout";
82
82
  userContext: U;
83
+ hooks?: AgentHooks[];
83
84
  memories: Pick<Memory, "content">[];
84
85
  /**
85
86
  * Create a user agent to consistently invoke an agent
@@ -164,11 +165,14 @@ export declare class AIGNEContext implements Context {
164
165
  set userContext(userContext: Context["userContext"]);
165
166
  get memories(): Context["memories"];
166
167
  set memories(memories: Context["memories"]);
168
+ get hooks(): AgentHooks[];
169
+ set hooks(hooks: AgentHooks[]);
167
170
  newContext({ reset }?: {
168
171
  reset?: boolean;
169
172
  }): AIGNEContext;
170
173
  invoke: Context["invoke"];
171
174
  private onInvocationResult;
175
+ private processOptions;
172
176
  publish: Context["publish"];
173
177
  subscribe: Context["subscribe"];
174
178
  unsubscribe: Context["unsubscribe"];
@@ -197,6 +201,7 @@ declare class AIGNEContextShared {
197
201
  usage: ContextUsage;
198
202
  userContext: Context["userContext"];
199
203
  memories: Context["memories"];
204
+ hooks: AgentHooks[];
200
205
  private abortController;
201
206
  private timer?;
202
207
  private initTimeout;
@@ -94,6 +94,12 @@ class AIGNEContext {
94
94
  set memories(memories) {
95
95
  this.internal.memories = memories;
96
96
  }
97
+ get hooks() {
98
+ return this.internal.hooks;
99
+ }
100
+ set hooks(hooks) {
101
+ this.internal.hooks = hooks;
102
+ }
97
103
  newContext({ reset } = {}) {
98
104
  return new AIGNEContext(this, { reset });
99
105
  }
@@ -103,14 +109,7 @@ class AIGNEContext {
103
109
  message,
104
110
  options,
105
111
  });
106
- if (options?.userContext) {
107
- Object.assign(this.userContext, options.userContext);
108
- options.userContext = undefined;
109
- }
110
- if (options?.memories?.length) {
111
- this.memories.push(...options.memories);
112
- options.memories = undefined;
113
- }
112
+ this.processOptions(options);
114
113
  if ((0, type_utils_js_1.isNil)(message)) {
115
114
  return user_agent_js_1.UserAgent.from({
116
115
  context: this,
@@ -176,7 +175,7 @@ class AIGNEContext {
176
175
  },
177
176
  };
178
177
  }
179
- publish = ((topic, payload, options) => {
178
+ processOptions(options) {
180
179
  if (options?.userContext) {
181
180
  Object.assign(this.userContext, options.userContext);
182
181
  options.userContext = undefined;
@@ -185,6 +184,13 @@ class AIGNEContext {
185
184
  this.memories.push(...options.memories);
186
185
  options.memories = undefined;
187
186
  }
187
+ if (options?.hooks) {
188
+ this.hooks.push(...(0, type_utils_js_1.flat)(options.hooks));
189
+ options.hooks = undefined;
190
+ }
191
+ }
192
+ publish = ((topic, payload, options) => {
193
+ this.processOptions(options);
188
194
  const newContext = options?.newContext === false ? this : this.newContext();
189
195
  return this.internal.messageQueue.publish(topic, {
190
196
  ...(0, message_queue_js_1.toMessagePayload)(payload),
@@ -318,6 +324,7 @@ class AIGNEContextShared {
318
324
  usage = (0, usage_js_1.newEmptyContextUsage)();
319
325
  userContext = {};
320
326
  memories = [];
327
+ hooks = [];
321
328
  abortController = new AbortController();
322
329
  timer;
323
330
  initTimeout() {
@@ -19,6 +19,7 @@ export type NestAgentSchema = string | {
19
19
  export interface BaseAgentSchema {
20
20
  name?: string;
21
21
  description?: string;
22
+ taskTitle?: string;
22
23
  inputSchema?: ZodType<Record<string, any>>;
23
24
  defaultInput?: Record<string, any>;
24
25
  outputSchema?: ZodType<Record<string, any>>;
@@ -34,6 +34,7 @@ async function parseAgentFile(path, data) {
34
34
  name: (0, schema_js_1.optionalize)(zod_1.z.string()),
35
35
  alias: (0, schema_js_1.optionalize)(zod_1.z.array(zod_1.z.string())),
36
36
  description: (0, schema_js_1.optionalize)(zod_1.z.string()),
37
+ taskTitle: (0, schema_js_1.optionalize)(zod_1.z.string()),
37
38
  inputSchema: (0, schema_js_1.optionalize)((0, schema_js_1.inputOutputSchema)({ path })).transform((v) => v ? (0, json_schema_to_zod_1.jsonSchemaToZod)(v) : undefined),
38
39
  defaultInput: (0, schema_js_1.optionalize)(schema_js_1.defaultInputSchema),
39
40
  outputSchema: (0, schema_js_1.optionalize)((0, schema_js_1.inputOutputSchema)({ path })).transform((v) => v ? (0, json_schema_to_zod_1.jsonSchemaToZod)(v) : undefined),
@@ -16,9 +16,17 @@ class ExtractMetadataTransform extends TransformStream {
16
16
  if (this.state === "none") {
17
17
  const found = findMatchIndex(this.buffer, this.cursor, start);
18
18
  if (found.start > this.cursor) {
19
- const text = this.buffer.slice(this.cursor, found.start);
19
+ let text = this.buffer.slice(this.cursor, found.start);
20
20
  this.cursor = found.start;
21
- controller.enqueue({ delta: { text: { text } } });
21
+ // Trim trailing whitespace from the text
22
+ const whitespace = text.match(/(?<whitespace>\s+)$/)?.groups?.whitespace;
23
+ if (whitespace) {
24
+ text = text.slice(0, -whitespace.length);
25
+ this.cursor -= whitespace.length;
26
+ }
27
+ if (text) {
28
+ controller.enqueue({ delta: { text: { text } } });
29
+ }
22
30
  }
23
31
  if (found.end) {
24
32
  this.state = "start";
@@ -72,6 +72,7 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
72
72
  * for documentation and debugging
73
73
  */
74
74
  description?: string;
75
+ taskTitle?: string;
75
76
  /**
76
77
  * Zod schema defining the input message structure
77
78
  *
@@ -256,6 +257,7 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
256
257
  * each other's roles in a multi-agent system
257
258
  */
258
259
  readonly description?: string;
260
+ taskTitle?: string;
259
261
  private readonly _inputSchema?;
260
262
  defaultInput?: Partial<{
261
263
  [key in keyof I]: {
@@ -1,7 +1,7 @@
1
1
  import type { AIGNEObserver } from "@aigne/observability-api";
2
2
  import type { Span } from "@opentelemetry/api";
3
3
  import { Emitter } from "strict-event-emitter";
4
- import { type Agent, type AgentInvokeOptions, type AgentProcessAsyncGenerator, type AgentResponse, type AgentResponseStream, type Message } from "../agents/agent.js";
4
+ import { type Agent, type AgentHooks, type AgentInvokeOptions, type AgentProcessAsyncGenerator, type AgentResponse, type AgentResponseStream, type Message } from "../agents/agent.js";
5
5
  import type { ChatModel } from "../agents/chat-model.js";
6
6
  import { UserAgent } from "../agents/user-agent.js";
7
7
  import type { Memory } from "../memory/memory.js";
@@ -80,6 +80,7 @@ export interface Context<U extends UserContext = UserContext> extends TypedEvent
80
80
  limits?: ContextLimits;
81
81
  status?: "normal" | "timeout";
82
82
  userContext: U;
83
+ hooks?: AgentHooks[];
83
84
  memories: Pick<Memory, "content">[];
84
85
  /**
85
86
  * Create a user agent to consistently invoke an agent
@@ -164,11 +165,14 @@ export declare class AIGNEContext implements Context {
164
165
  set userContext(userContext: Context["userContext"]);
165
166
  get memories(): Context["memories"];
166
167
  set memories(memories: Context["memories"]);
168
+ get hooks(): AgentHooks[];
169
+ set hooks(hooks: AgentHooks[]);
167
170
  newContext({ reset }?: {
168
171
  reset?: boolean;
169
172
  }): AIGNEContext;
170
173
  invoke: Context["invoke"];
171
174
  private onInvocationResult;
175
+ private processOptions;
172
176
  publish: Context["publish"];
173
177
  subscribe: Context["subscribe"];
174
178
  unsubscribe: Context["unsubscribe"];
@@ -197,6 +201,7 @@ declare class AIGNEContextShared {
197
201
  usage: ContextUsage;
198
202
  userContext: Context["userContext"];
199
203
  memories: Context["memories"];
204
+ hooks: AgentHooks[];
200
205
  private abortController;
201
206
  private timer?;
202
207
  private initTimeout;
@@ -19,6 +19,7 @@ export type NestAgentSchema = string | {
19
19
  export interface BaseAgentSchema {
20
20
  name?: string;
21
21
  description?: string;
22
+ taskTitle?: string;
22
23
  inputSchema?: ZodType<Record<string, any>>;
23
24
  defaultInput?: Record<string, any>;
24
25
  outputSchema?: ZodType<Record<string, any>>;
@@ -72,6 +72,7 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
72
72
  * for documentation and debugging
73
73
  */
74
74
  description?: string;
75
+ taskTitle?: string;
75
76
  /**
76
77
  * Zod schema defining the input message structure
77
78
  *
@@ -256,6 +257,7 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
256
257
  * each other's roles in a multi-agent system
257
258
  */
258
259
  readonly description?: string;
260
+ taskTitle?: string;
259
261
  private readonly _inputSchema?;
260
262
  defaultInput?: Partial<{
261
263
  [key in keyof I]: {
@@ -59,6 +59,7 @@ export class Agent {
59
59
  this.name = options.name || this.constructor.name;
60
60
  this.alias = options.alias;
61
61
  this.description = options.description;
62
+ this.taskTitle = options.taskTitle;
62
63
  if (inputSchema)
63
64
  checkAgentInputOutputSchema(inputSchema);
64
65
  if (outputSchema)
@@ -148,6 +149,7 @@ export class Agent {
148
149
  * each other's roles in a multi-agent system
149
150
  */
150
151
  description;
152
+ taskTitle;
151
153
  _inputSchema;
152
154
  defaultInput;
153
155
  _outputSchema;
@@ -343,7 +345,7 @@ export class Agent {
343
345
  async callHooks(hook, input, options) {
344
346
  const { context } = options;
345
347
  const result = {};
346
- for (const hooks of flat(options.hooks, this.hooks)) {
348
+ for (const hooks of flat(options.hooks, options.context.hooks, this.hooks)) {
347
349
  const h = hooks[hook];
348
350
  if (!h)
349
351
  continue;
@@ -100,7 +100,11 @@ export class ChatModel extends Agent {
100
100
  toolsMap[name] = originalTool;
101
101
  }
102
102
  this.validateToolNames(tools);
103
- Object.assign(input, { _toolsMap: toolsMap, tools });
103
+ Object.assign(input, { tools });
104
+ Object.defineProperty(input, "_toolsMap", {
105
+ value: toolsMap,
106
+ enumerable: false,
107
+ });
104
108
  }
105
109
  }
106
110
  /**
@@ -1,7 +1,7 @@
1
1
  import type { AIGNEObserver } from "@aigne/observability-api";
2
2
  import type { Span } from "@opentelemetry/api";
3
3
  import { Emitter } from "strict-event-emitter";
4
- import { type Agent, type AgentInvokeOptions, type AgentProcessAsyncGenerator, type AgentResponse, type AgentResponseStream, type Message } from "../agents/agent.js";
4
+ import { type Agent, type AgentHooks, type AgentInvokeOptions, type AgentProcessAsyncGenerator, type AgentResponse, type AgentResponseStream, type Message } from "../agents/agent.js";
5
5
  import type { ChatModel } from "../agents/chat-model.js";
6
6
  import { UserAgent } from "../agents/user-agent.js";
7
7
  import type { Memory } from "../memory/memory.js";
@@ -80,6 +80,7 @@ export interface Context<U extends UserContext = UserContext> extends TypedEvent
80
80
  limits?: ContextLimits;
81
81
  status?: "normal" | "timeout";
82
82
  userContext: U;
83
+ hooks?: AgentHooks[];
83
84
  memories: Pick<Memory, "content">[];
84
85
  /**
85
86
  * Create a user agent to consistently invoke an agent
@@ -164,11 +165,14 @@ export declare class AIGNEContext implements Context {
164
165
  set userContext(userContext: Context["userContext"]);
165
166
  get memories(): Context["memories"];
166
167
  set memories(memories: Context["memories"]);
168
+ get hooks(): AgentHooks[];
169
+ set hooks(hooks: AgentHooks[]);
167
170
  newContext({ reset }?: {
168
171
  reset?: boolean;
169
172
  }): AIGNEContext;
170
173
  invoke: Context["invoke"];
171
174
  private onInvocationResult;
175
+ private processOptions;
172
176
  publish: Context["publish"];
173
177
  subscribe: Context["subscribe"];
174
178
  unsubscribe: Context["unsubscribe"];
@@ -197,6 +201,7 @@ declare class AIGNEContextShared {
197
201
  usage: ContextUsage;
198
202
  userContext: Context["userContext"];
199
203
  memories: Context["memories"];
204
+ hooks: AgentHooks[];
200
205
  private abortController;
201
206
  private timer?;
202
207
  private initTimeout;
@@ -88,6 +88,12 @@ export class AIGNEContext {
88
88
  set memories(memories) {
89
89
  this.internal.memories = memories;
90
90
  }
91
+ get hooks() {
92
+ return this.internal.hooks;
93
+ }
94
+ set hooks(hooks) {
95
+ this.internal.hooks = hooks;
96
+ }
91
97
  newContext({ reset } = {}) {
92
98
  return new AIGNEContext(this, { reset });
93
99
  }
@@ -97,14 +103,7 @@ export class AIGNEContext {
97
103
  message,
98
104
  options,
99
105
  });
100
- if (options?.userContext) {
101
- Object.assign(this.userContext, options.userContext);
102
- options.userContext = undefined;
103
- }
104
- if (options?.memories?.length) {
105
- this.memories.push(...options.memories);
106
- options.memories = undefined;
107
- }
106
+ this.processOptions(options);
108
107
  if (isNil(message)) {
109
108
  return UserAgent.from({
110
109
  context: this,
@@ -170,7 +169,7 @@ export class AIGNEContext {
170
169
  },
171
170
  };
172
171
  }
173
- publish = ((topic, payload, options) => {
172
+ processOptions(options) {
174
173
  if (options?.userContext) {
175
174
  Object.assign(this.userContext, options.userContext);
176
175
  options.userContext = undefined;
@@ -179,6 +178,13 @@ export class AIGNEContext {
179
178
  this.memories.push(...options.memories);
180
179
  options.memories = undefined;
181
180
  }
181
+ if (options?.hooks) {
182
+ this.hooks.push(...flat(options.hooks));
183
+ options.hooks = undefined;
184
+ }
185
+ }
186
+ publish = ((topic, payload, options) => {
187
+ this.processOptions(options);
182
188
  const newContext = options?.newContext === false ? this : this.newContext();
183
189
  return this.internal.messageQueue.publish(topic, {
184
190
  ...toMessagePayload(payload),
@@ -311,6 +317,7 @@ class AIGNEContextShared {
311
317
  usage = newEmptyContextUsage();
312
318
  userContext = {};
313
319
  memories = [];
320
+ hooks = [];
314
321
  abortController = new AbortController();
315
322
  timer;
316
323
  initTimeout() {
@@ -19,6 +19,7 @@ export type NestAgentSchema = string | {
19
19
  export interface BaseAgentSchema {
20
20
  name?: string;
21
21
  description?: string;
22
+ taskTitle?: string;
22
23
  inputSchema?: ZodType<Record<string, any>>;
23
24
  defaultInput?: Record<string, any>;
24
25
  outputSchema?: ZodType<Record<string, any>>;
@@ -30,6 +30,7 @@ export async function parseAgentFile(path, data) {
30
30
  name: optionalize(z.string()),
31
31
  alias: optionalize(z.array(z.string())),
32
32
  description: optionalize(z.string()),
33
+ taskTitle: optionalize(z.string()),
33
34
  inputSchema: optionalize(inputOutputSchema({ path })).transform((v) => v ? jsonSchemaToZod(v) : undefined),
34
35
  defaultInput: optionalize(defaultInputSchema),
35
36
  outputSchema: optionalize(inputOutputSchema({ path })).transform((v) => v ? jsonSchemaToZod(v) : undefined),
@@ -13,9 +13,17 @@ export class ExtractMetadataTransform extends TransformStream {
13
13
  if (this.state === "none") {
14
14
  const found = findMatchIndex(this.buffer, this.cursor, start);
15
15
  if (found.start > this.cursor) {
16
- const text = this.buffer.slice(this.cursor, found.start);
16
+ let text = this.buffer.slice(this.cursor, found.start);
17
17
  this.cursor = found.start;
18
- controller.enqueue({ delta: { text: { text } } });
18
+ // Trim trailing whitespace from the text
19
+ const whitespace = text.match(/(?<whitespace>\s+)$/)?.groups?.whitespace;
20
+ if (whitespace) {
21
+ text = text.slice(0, -whitespace.length);
22
+ this.cursor -= whitespace.length;
23
+ }
24
+ if (text) {
25
+ controller.enqueue({ delta: { text: { text } } });
26
+ }
19
27
  }
20
28
  if (found.end) {
21
29
  this.state = "start";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@aigne/core",
3
- "version": "1.45.0",
4
- "description": "AIGNE core library for building AI-powered applications",
3
+ "version": "1.46.1",
4
+ "description": "The functional core of agentic AI",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -80,7 +80,6 @@
80
80
  "immer": "^10.1.1",
81
81
  "jaison": "^2.0.2",
82
82
  "jsonata": "^2.0.6",
83
- "mustache": "^4.2.0",
84
83
  "nunjucks": "^3.2.4",
85
84
  "p-retry": "^6.2.1",
86
85
  "raw-body": "^3.0.0",
@@ -91,14 +90,13 @@
91
90
  "zod": "^3.25.67",
92
91
  "zod-to-json-schema": "^3.24.6",
93
92
  "@aigne/observability-api": "^0.9.0",
94
- "@aigne/platform-helpers": "^0.5.1"
93
+ "@aigne/platform-helpers": "^0.6.0"
95
94
  },
96
95
  "devDependencies": {
97
96
  "@types/bun": "^1.2.18",
98
97
  "@types/compression": "^1.8.1",
99
98
  "@types/content-type": "^1.1.9",
100
99
  "@types/express": "^5.0.3",
101
- "@types/mustache": "^4.2.6",
102
100
  "@types/node": "^24.0.12",
103
101
  "@types/nunjucks": "^3.2.6",
104
102
  "compression": "^1.8.0",