@aigne/core 1.18.6 → 1.19.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/CHANGELOG.md CHANGED
@@ -5,6 +5,13 @@
5
5
 
6
6
  * add user context support ([#131](https://github.com/AIGNE-io/aigne-framework/issues/131)) ([4dd9d20](https://github.com/AIGNE-io/aigne-framework/commit/4dd9d20953f6ac33933723db56efd9b44bafeb02))
7
7
 
8
+ ## [1.19.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.18.6...core-v1.19.0) (2025-06-16)
9
+
10
+
11
+ ### Features
12
+
13
+ * support respond progressing chunks by enable `returnProgressChunks` option for aigne.invoke ([cf4c313](https://github.com/AIGNE-io/aigne-framework/commit/cf4c313ee69f255be799ac196da675b79f69bf76))
14
+
8
15
  ## [1.18.6](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.18.5...core-v1.18.6) (2025-06-11)
9
16
 
10
17
 
@@ -1,6 +1,6 @@
1
1
  import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
2
2
  import { ZodObject, type ZodType } from "zod";
3
- import type { Context, UserContext } from "../aigne/context.js";
3
+ import type { AgentEvent, Context, UserContext } from "../aigne/context.js";
4
4
  import type { MessagePayload } from "../aigne/message-queue.js";
5
5
  import type { Memory, MemoryAgent } from "../memory/memory.js";
6
6
  import type { MemoryRecorderInput } from "../memory/recorder.js";
@@ -594,7 +594,7 @@ export type AgentResponseStream<T> = ReadableStream<AgentResponseChunk<T>>;
594
594
  *
595
595
  * @template T Response data type
596
596
  */
597
- export type AgentResponseChunk<T> = AgentResponseDelta<T>;
597
+ export type AgentResponseChunk<T> = AgentResponseDelta<T> | AgentResponseProgress;
598
598
  /**
599
599
  * Check if a response chunk is empty
600
600
  *
@@ -622,6 +622,24 @@ export interface AgentResponseDelta<T> {
622
622
  json?: Partial<T> | TransferAgentOutput;
623
623
  };
624
624
  }
625
+ export declare function isAgentResponseDelta<T>(chunk: AgentResponseChunk<T>): chunk is AgentResponseDelta<T>;
626
+ export interface AgentResponseProgress {
627
+ progress: ({
628
+ event: "agentStarted";
629
+ input: Message;
630
+ } | {
631
+ event: "agentSucceed";
632
+ output: Message;
633
+ } | {
634
+ event: "agentFailed";
635
+ error: Error;
636
+ }) & Omit<AgentEvent, "agent"> & {
637
+ agent: {
638
+ name: string;
639
+ };
640
+ };
641
+ }
642
+ export declare function isAgentResponseProgress<T>(chunk: AgentResponseChunk<T>): chunk is AgentResponseProgress;
625
643
  /**
626
644
  * Creates a text delta for streaming responses
627
645
  *
@@ -38,6 +38,8 @@ var __importStar = (this && this.__importStar) || (function () {
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.FunctionAgent = exports.Agent = exports.agentOptionsSchema = void 0;
40
40
  exports.isEmptyChunk = isEmptyChunk;
41
+ exports.isAgentResponseDelta = isAgentResponseDelta;
42
+ exports.isAgentResponseProgress = isAgentResponseProgress;
41
43
  exports.textDelta = textDelta;
42
44
  exports.jsonDelta = jsonDelta;
43
45
  const index_js_1 = require("@aigne/platform-helpers/nodejs/index.js");
@@ -361,10 +363,11 @@ class Agent {
361
363
  : (0, stream_utils_js_1.isAsyncGenerator)(response)
362
364
  ? (0, stream_utils_js_1.asyncGeneratorToReadableStream)(response)
363
365
  : (0, stream_utils_js_1.objectToAgentResponseStream)(response);
364
- return this.checkResponseByGuideRails(message, (0, stream_utils_js_1.onAgentResponseStreamEnd)(stream, async (result) => {
365
- return await this.processAgentOutput(parsedInput, result, opts);
366
- }, {
367
- errorCallback: async (error) => {
366
+ return this.checkResponseByGuideRails(message, (0, stream_utils_js_1.onAgentResponseStreamEnd)(stream, {
367
+ onResult: async (result) => {
368
+ return await this.processAgentOutput(parsedInput, result, opts);
369
+ },
370
+ onError: async (error) => {
368
371
  return await this.processAgentError(message, error, opts);
369
372
  },
370
373
  }), opts);
@@ -464,14 +467,16 @@ class Agent {
464
467
  return output;
465
468
  const result = await output;
466
469
  if (result instanceof ReadableStream) {
467
- return (0, stream_utils_js_1.onAgentResponseStreamEnd)(result, async (result) => {
468
- const error = await this.runGuideRails(input, result, options);
469
- if (error) {
470
- return {
471
- ...(await this.onGuideRailError(error)),
472
- $status: "GuideRailError",
473
- };
474
- }
470
+ return (0, stream_utils_js_1.onAgentResponseStreamEnd)(result, {
471
+ onResult: async (result) => {
472
+ const error = await this.runGuideRails(input, result, options);
473
+ if (error) {
474
+ return {
475
+ ...(await this.onGuideRailError(error)),
476
+ $status: "GuideRailError",
477
+ };
478
+ }
479
+ },
475
480
  });
476
481
  }
477
482
  const error = await this.runGuideRails(input, result, options);
@@ -585,7 +590,13 @@ exports.Agent = Agent;
585
590
  * @returns True if the chunk is empty
586
591
  */
587
592
  function isEmptyChunk(chunk) {
588
- return (0, type_utils_js_1.isEmpty)(chunk.delta.json) && (0, type_utils_js_1.isEmpty)(chunk.delta.text);
593
+ return isAgentResponseDelta(chunk) && (0, type_utils_js_1.isEmpty)(chunk.delta.json) && (0, type_utils_js_1.isEmpty)(chunk.delta.text);
594
+ }
595
+ function isAgentResponseDelta(chunk) {
596
+ return "delta" in chunk;
597
+ }
598
+ function isAgentResponseProgress(chunk) {
599
+ return "progress" in chunk;
589
600
  }
590
601
  /**
591
602
  * Creates a text delta for streaming responses
@@ -191,8 +191,7 @@ class AIAgent extends agent_js_1.Agent {
191
191
  });
192
192
  const toolsMap = new Map(toolAgents?.map((i) => [i.name, i]));
193
193
  if (this.toolChoice === "router") {
194
- yield* this._processRouter(input, model, modelInput, options, toolsMap);
195
- return;
194
+ return yield* this._processRouter(input, model, modelInput, options, toolsMap);
196
195
  }
197
196
  const toolCallMessages = [];
198
197
  const outputKey = this.outputKey || prompt_builder_js_1.MESSAGE_KEY;
@@ -200,11 +199,13 @@ class AIAgent extends agent_js_1.Agent {
200
199
  const modelOutput = {};
201
200
  const stream = await options.context.invoke(model, { ...modelInput, messages: modelInput.messages.concat(toolCallMessages) }, { streaming: true });
202
201
  for await (const value of stream) {
203
- if (value.delta.text?.text) {
204
- yield { delta: { text: { [outputKey]: value.delta.text.text } } };
205
- }
206
- if (value.delta.json) {
207
- Object.assign(modelOutput, value.delta.json);
202
+ if ((0, agent_js_1.isAgentResponseDelta)(value)) {
203
+ if (value.delta.text?.text) {
204
+ yield { delta: { text: { [outputKey]: value.delta.text.text } } };
205
+ }
206
+ if (value.delta.json) {
207
+ Object.assign(modelOutput, value.delta.json);
208
+ }
208
209
  }
209
210
  }
210
211
  const { toolCalls, json, text } = modelOutput;
@@ -275,7 +276,7 @@ class AIAgent extends agent_js_1.Agent {
275
276
  if (!tool)
276
277
  throw new Error(`Tool not found: ${call.function.name}`);
277
278
  const stream = await options.context.invoke(tool, { ...call.function.arguments, ...input }, { streaming: true, sourceAgent: this });
278
- yield* stream;
279
+ return yield* stream;
279
280
  }
280
281
  }
281
282
  exports.AIAgent = AIAgent;
@@ -158,7 +158,7 @@ class TeamAgent extends agent_js_1.Agent {
158
158
  if (!done) {
159
159
  tasks.set(index, read(index, reader));
160
160
  }
161
- if (value) {
161
+ if (value && (0, agent_js_1.isAgentResponseDelta)(value)) {
162
162
  let { delta: { text, ...delta }, } = value;
163
163
  if (text) {
164
164
  for (const key of Object.keys(text)) {
@@ -41,6 +41,7 @@ export type ContextEmitEventMap = {
41
41
  */
42
42
  export interface InvokeOptions<U extends UserContext = UserContext> extends Partial<Omit<AgentInvokeOptions<U>, "context">> {
43
43
  returnActiveAgent?: boolean;
44
+ returnProgressChunks?: boolean;
44
45
  disableTransfer?: boolean;
45
46
  sourceAgent?: Agent;
46
47
  }
@@ -53,6 +54,8 @@ export interface UserContext extends Record<string, unknown> {
53
54
  * @hidden
54
55
  */
55
56
  export interface Context<U extends UserContext = UserContext> extends TypedEventEmitter<ContextEventMap, ContextEmitEventMap> {
57
+ id: string;
58
+ parentId?: string;
56
59
  model?: ChatModel;
57
60
  skills?: Agent[];
58
61
  usage: ContextUsage;
@@ -12,6 +12,7 @@ const agent_js_1 = require("../agents/agent.js");
12
12
  const types_js_1 = require("../agents/types.js");
13
13
  const user_agent_js_1 = require("../agents/user-agent.js");
14
14
  const prompt_builder_js_1 = require("../prompt/prompt-builder.js");
15
+ const event_stream_js_1 = require("../utils/event-stream.js");
15
16
  const promise_js_1 = require("../utils/promise.js");
16
17
  const stream_utils_js_1 = require("../utils/stream-utils.js");
17
18
  const type_utils_js_1 = require("../utils/type-utils.js");
@@ -96,11 +97,9 @@ class AIGNEContext {
96
97
  return output;
97
98
  }
98
99
  const activeAgentPromise = (0, promise_js_1.promiseWithResolvers)();
99
- const stream = (0, stream_utils_js_1.onAgentResponseStreamEnd)((0, stream_utils_js_1.asyncGeneratorToReadableStream)(response), async ({ __activeAgent__: activeAgent }) => {
100
- activeAgentPromise.resolve(activeAgent);
101
- }, {
102
- processChunk(chunk) {
103
- if (chunk.delta.json) {
100
+ const stream = (0, stream_utils_js_1.onAgentResponseStreamEnd)((0, stream_utils_js_1.asyncGeneratorToReadableStream)(response), {
101
+ onChunk(chunk) {
102
+ if ((0, agent_js_1.isAgentResponseDelta)(chunk) && chunk.delta.json) {
104
103
  return {
105
104
  ...chunk,
106
105
  delta: {
@@ -109,13 +108,18 @@ class AIGNEContext {
109
108
  },
110
109
  };
111
110
  }
112
- return chunk;
111
+ },
112
+ onResult({ __activeAgent__: activeAgent }) {
113
+ activeAgentPromise.resolve(activeAgent);
113
114
  },
114
115
  });
116
+ const finalStream = !options.returnProgressChunks
117
+ ? stream
118
+ : (0, stream_utils_js_1.mergeReadableStreams)(stream, new event_stream_js_1.AgentResponseProgressStream(newContext));
115
119
  if (options.returnActiveAgent) {
116
- return [stream, activeAgentPromise.promise];
120
+ return [finalStream, activeAgentPromise.promise];
117
121
  }
118
- return stream;
122
+ return finalStream;
119
123
  });
120
124
  });
121
125
  publish = ((topic, payload, options) => {
@@ -171,7 +175,6 @@ class AIGNEContextShared {
171
175
  this.memories = overrides?.memories ?? [];
172
176
  }
173
177
  messageQueue;
174
- // biome-ignore lint/suspicious/noExplicitAny: <explanation>
175
178
  events = new strict_event_emitter_1.Emitter();
176
179
  get model() {
177
180
  return this.parent?.model;
@@ -218,11 +221,13 @@ class AIGNEContextShared {
218
221
  }
219
222
  const stream = await activeAgent.invoke(input, { ...options, context, streaming: true });
220
223
  for await (const value of stream) {
221
- if (value.delta.json) {
222
- value.delta.json = omitExistsProperties(result, value.delta.json);
223
- Object.assign(result, value.delta.json);
224
+ if ((0, agent_js_1.isAgentResponseDelta)(value)) {
225
+ if (value.delta.json) {
226
+ value.delta.json = omitExistsProperties(result, value.delta.json);
227
+ Object.assign(result, value.delta.json);
228
+ }
229
+ delete value.delta.json?.[types_js_1.transferAgentOutputKey];
224
230
  }
225
- delete value.delta.json?.[types_js_1.transferAgentOutputKey];
226
231
  if ((0, agent_js_1.isEmptyChunk)(value))
227
232
  continue;
228
233
  yield value;
@@ -1,4 +1,5 @@
1
- import type { AgentResponseChunk, AgentResponseStream, Message } from "../agents/agent.js";
1
+ import { type AgentResponseChunk, type AgentResponseProgress, type AgentResponseStream, type Message } from "../agents/agent.js";
2
+ import type { Context } from "../aigne/context.js";
2
3
  export declare class EventStreamParser<T> extends TransformStream<string, T | Error> {
3
4
  constructor();
4
5
  }
@@ -9,3 +10,6 @@ export declare class AgentResponseStreamParser<O extends Message> extends Transf
9
10
  export declare class AgentResponseStreamSSE<O extends Message> extends ReadableStream<string> {
10
11
  constructor(stream: AgentResponseStream<O>);
11
12
  }
13
+ export declare class AgentResponseProgressStream extends ReadableStream<AgentResponseProgress> {
14
+ constructor(context: Context);
15
+ }
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AgentResponseStreamSSE = exports.AgentResponseStreamParser = exports.EventStreamParser = void 0;
3
+ exports.AgentResponseProgressStream = exports.AgentResponseStreamSSE = exports.AgentResponseStreamParser = exports.EventStreamParser = void 0;
4
4
  const eventsource_parser_1 = require("eventsource-parser");
5
5
  const immer_1 = require("immer");
6
+ const agent_js_1 = require("../agents/agent.js");
6
7
  const type_utils_js_1 = require("./type-utils.js");
7
8
  class EventStreamParser extends TransformStream {
8
9
  constructor() {
@@ -15,11 +16,16 @@ class EventStreamParser extends TransformStream {
15
16
  controller.enqueue(new Error(`Parse response chunk json error: ${e.message} ${event.data}`));
16
17
  });
17
18
  if (json) {
18
- if (event.event === "error") {
19
- controller.enqueue(new Error(json.message));
20
- }
21
- else {
22
- controller.enqueue(json);
19
+ switch (event.event) {
20
+ case "error":
21
+ controller.enqueue(new Error(json.message));
22
+ break;
23
+ default: {
24
+ if (!event.event)
25
+ controller.enqueue(json);
26
+ else
27
+ console.warn(`Unknown event type: ${event.event}`, event.data);
28
+ }
23
29
  }
24
30
  }
25
31
  },
@@ -42,25 +48,35 @@ class AgentResponseStreamParser extends TransformStream {
42
48
  controller.terminate();
43
49
  return;
44
50
  }
45
- this.json = (0, immer_1.produce)(this.json, (draft) => {
46
- if (chunk.delta.json)
47
- Object.assign(draft, chunk.delta.json);
48
- if (chunk.delta.text) {
49
- for (const [key, text] of Object.entries(chunk.delta.text)) {
50
- const original = draft[key];
51
- const t = (original || "") + (text || "");
52
- if (t)
53
- Object.assign(draft, { [key]: t });
51
+ if ((0, agent_js_1.isAgentResponseDelta)(chunk)) {
52
+ this.json = (0, immer_1.produce)(this.json, (draft) => {
53
+ if (chunk.delta.json)
54
+ Object.assign(draft, chunk.delta.json);
55
+ if (chunk.delta.text) {
56
+ for (const [key, text] of Object.entries(chunk.delta.text)) {
57
+ const original = draft[key];
58
+ const t = (original || "") + (text || "");
59
+ if (t)
60
+ Object.assign(draft, { [key]: t });
61
+ }
54
62
  }
63
+ });
64
+ controller.enqueue({
65
+ ...chunk,
66
+ delta: {
67
+ ...chunk.delta,
68
+ json: this.json,
69
+ },
70
+ });
71
+ }
72
+ else if ((0, agent_js_1.isAgentResponseProgress)(chunk)) {
73
+ if (chunk.progress.event === "agentFailed") {
74
+ const { name, message } = chunk.progress.error;
75
+ chunk.progress.error = new Error(message);
76
+ chunk.progress.error.name = name;
55
77
  }
56
- });
57
- controller.enqueue({
58
- ...chunk,
59
- delta: {
60
- ...chunk.delta,
61
- json: this.json,
62
- },
63
- });
78
+ controller.enqueue(chunk);
79
+ }
64
80
  },
65
81
  });
66
82
  }
@@ -78,6 +94,14 @@ class AgentResponseStreamSSE extends ReadableStream {
78
94
  controller.close();
79
95
  return;
80
96
  }
97
+ if ((0, agent_js_1.isAgentResponseProgress)(value)) {
98
+ if (value.progress.event === "agentFailed") {
99
+ value.progress.error = {
100
+ name: value.progress.error.name,
101
+ message: value.progress.error.message,
102
+ };
103
+ }
104
+ }
81
105
  controller.enqueue(`data: ${JSON.stringify(value)}\n\n`);
82
106
  }
83
107
  catch (error) {
@@ -89,3 +113,44 @@ class AgentResponseStreamSSE extends ReadableStream {
89
113
  }
90
114
  }
91
115
  exports.AgentResponseStreamSSE = AgentResponseStreamSSE;
116
+ class AgentResponseProgressStream extends ReadableStream {
117
+ constructor(context) {
118
+ super({
119
+ async start(controller) {
120
+ const writeEvent = (eventName, event) => {
121
+ const progress = {
122
+ ...event,
123
+ event: eventName,
124
+ agent: { name: event.agent.name },
125
+ };
126
+ controller.enqueue({ progress });
127
+ };
128
+ const close = () => {
129
+ context.off("agentStarted", onAgentStarted);
130
+ context.off("agentSucceed", onAgentSucceed);
131
+ context.off("agentFailed", onAgentFailed);
132
+ controller.close();
133
+ };
134
+ const onAgentStarted = (event) => {
135
+ writeEvent("agentStarted", event);
136
+ };
137
+ const onAgentSucceed = (event) => {
138
+ writeEvent("agentSucceed", event);
139
+ if (event.contextId === context.id) {
140
+ close();
141
+ }
142
+ };
143
+ const onAgentFailed = (event) => {
144
+ writeEvent("agentFailed", event);
145
+ if (event.contextId === context.id) {
146
+ close();
147
+ }
148
+ };
149
+ context.on("agentStarted", onAgentStarted);
150
+ context.on("agentSucceed", onAgentSucceed);
151
+ context.on("agentFailed", onAgentFailed);
152
+ },
153
+ });
154
+ }
155
+ }
156
+ exports.AgentResponseProgressStream = AgentResponseProgressStream;
@@ -6,10 +6,11 @@ export declare function objectToAgentResponseStream<T extends Message>(json: T):
6
6
  export declare function mergeAgentResponseChunk<T extends Message>(output: T, chunk: AgentResponseChunk<T>): T;
7
7
  export declare function agentResponseStreamToObject<T extends Message>(stream: AgentResponseStream<T> | AgentProcessAsyncGenerator<T>): Promise<T>;
8
8
  export declare function asyncGeneratorToReadableStream<T extends Message>(generator: AgentProcessAsyncGenerator<T>): AgentResponseStream<T>;
9
- export declare function onAgentResponseStreamEnd<T extends Message>(stream: AgentResponseStream<T>, callback: (result: T) => PromiseOrValue<Partial<T> | void>, options?: {
10
- errorCallback?: (error: Error) => PromiseOrValue<Error>;
11
- processChunk?: (chunk: AgentResponseChunk<T>) => AgentResponseChunk<T>;
12
- }): ReadableStream<any>;
9
+ export declare function onAgentResponseStreamEnd<T extends Message>(stream: AgentResponseStream<T>, options?: {
10
+ onChunk?: (chunk: AgentResponseChunk<T>) => PromiseOrValue<AgentResponseChunk<T> | undefined | void>;
11
+ onResult?: (result: T) => PromiseOrValue<Partial<T> | undefined | void>;
12
+ onError?: (error: Error) => PromiseOrValue<Error>;
13
+ }): AgentResponseStream<T>;
13
14
  export declare function isAsyncGenerator<T extends AsyncGenerator>(value: AsyncGenerator | unknown): value is T;
14
15
  export declare function arrayToAgentProcessAsyncGenerator<T extends Message>(chunks: (AgentResponseChunk<T> | Error)[], result?: Partial<T>): AgentProcessAsyncGenerator<T>;
15
16
  export declare function arrayToReadableStream<T>(chunks: (T | Error)[]): ReadableStream<T>;
@@ -17,8 +18,10 @@ export declare function readableStreamToArray<T>(stream: ReadableStream<T>, opti
17
18
  catchError: true;
18
19
  }): Promise<(T | Error)[]>;
19
20
  export declare function readableStreamToArray<T>(stream: ReadableStream<T>, options?: {
20
- catchError?: false;
21
+ catchError?: boolean;
21
22
  }): Promise<T[]>;
22
23
  export declare function stringToAgentResponseStream(str: string, key?: "text" | typeof MESSAGE_KEY | string): AgentResponseStream<Message>;
23
24
  export declare function toReadableStream(stream: NodeJS.ReadStream): ReadableStream<Uint8Array<ArrayBufferLike>>;
24
25
  export declare function readAllString(stream: NodeJS.ReadStream | ReadableStream): Promise<string>;
26
+ export declare function mergeReadableStreams<T1, T2>(s1: ReadableStream<T1>, s2: ReadableStream<T2>): ReadableStream<T1 | T2>;
27
+ export declare function mergeReadableStreams(...streams: ReadableStream<any>[]): ReadableStream<any>;
@@ -15,6 +15,7 @@ exports.readableStreamToArray = readableStreamToArray;
15
15
  exports.stringToAgentResponseStream = stringToAgentResponseStream;
16
16
  exports.toReadableStream = toReadableStream;
17
17
  exports.readAllString = readAllString;
18
+ exports.mergeReadableStreams = mergeReadableStreams;
18
19
  const fast_deep_equal_1 = __importDefault(require("fast-deep-equal"));
19
20
  const agent_js_1 = require("../agents/agent.js");
20
21
  const type_utils_js_1 = require("./type-utils.js");
@@ -28,16 +29,18 @@ function objectToAgentResponseStream(json) {
28
29
  });
29
30
  }
30
31
  function mergeAgentResponseChunk(output, chunk) {
31
- if (chunk.delta.text) {
32
- for (const [key, text] of Object.entries(chunk.delta.text)) {
33
- const original = output[key];
34
- const t = (original || "") + (text || "");
35
- if (t)
36
- Object.assign(output, { [key]: t });
32
+ if ((0, agent_js_1.isAgentResponseDelta)(chunk)) {
33
+ if (chunk.delta.text) {
34
+ for (const [key, text] of Object.entries(chunk.delta.text)) {
35
+ const original = output[key];
36
+ const t = (original || "") + (text || "");
37
+ if (t)
38
+ Object.assign(output, { [key]: t });
39
+ }
40
+ }
41
+ if (chunk.delta.json) {
42
+ Object.assign(output, (0, type_utils_js_1.omitBy)(chunk.delta.json, (v) => v === undefined));
37
43
  }
38
- }
39
- if (chunk.delta.json) {
40
- Object.assign(output, (0, type_utils_js_1.omitBy)(chunk.delta.json, (v) => v === undefined));
41
44
  }
42
45
  return output;
43
46
  }
@@ -88,7 +91,7 @@ function asyncGeneratorToReadableStream(generator) {
88
91
  },
89
92
  });
90
93
  }
91
- function onAgentResponseStreamEnd(stream, callback, options) {
94
+ function onAgentResponseStreamEnd(stream, options) {
92
95
  const json = {};
93
96
  const reader = stream.getReader();
94
97
  return new ReadableStream({
@@ -97,18 +100,17 @@ function onAgentResponseStreamEnd(stream, callback, options) {
97
100
  while (true) {
98
101
  const { value, done } = await reader.read();
99
102
  if (done) {
100
- const result = await callback(json);
103
+ const result = (await options?.onResult?.(json)) ?? json;
101
104
  if (result && !(0, fast_deep_equal_1.default)(result, json)) {
102
105
  let chunk = { delta: { json: result } };
103
- if (options?.processChunk)
104
- chunk = options.processChunk(chunk);
106
+ chunk = (await options?.onChunk?.(chunk)) ?? chunk;
105
107
  controller.enqueue(chunk);
106
108
  }
107
109
  controller.close();
108
110
  return;
109
111
  }
110
112
  mergeAgentResponseChunk(json, value);
111
- const chunk = options?.processChunk ? options.processChunk(value) : value;
113
+ const chunk = (await options?.onChunk?.(value)) ?? value;
112
114
  if (!(0, agent_js_1.isEmptyChunk)(chunk)) {
113
115
  controller.enqueue(chunk);
114
116
  break;
@@ -116,7 +118,7 @@ function onAgentResponseStreamEnd(stream, callback, options) {
116
118
  }
117
119
  }
118
120
  catch (error) {
119
- controller.error((await options?.errorCallback?.(error)) ?? error);
121
+ controller.error((await options?.onError?.(error)) ?? error);
120
122
  }
121
123
  },
122
124
  });
@@ -197,3 +199,34 @@ function toReadableStream(stream) {
197
199
  async function readAllString(stream) {
198
200
  return (await readableStreamToArray((stream instanceof ReadableStream ? stream : toReadableStream(stream)).pipeThrough(new TextDecoderStream()))).join("");
199
201
  }
202
+ function mergeReadableStreams(...streams) {
203
+ let readers;
204
+ return new ReadableStream({
205
+ async pull(controller) {
206
+ try {
207
+ readers ??= streams.map((s) => ({ reader: s.getReader(), data: [] }));
208
+ while (readers.length) {
209
+ const chunk = await Promise.race(readers.map((i) => {
210
+ i.reading ??= i.reader.read().then((result) => ({ result, item: i }));
211
+ return i.reading;
212
+ }));
213
+ if (chunk.result.value) {
214
+ controller.enqueue(chunk.result.value);
215
+ chunk.item.reading = undefined;
216
+ return;
217
+ }
218
+ if (chunk.result.done) {
219
+ readers = readers.filter((i) => i !== chunk.item);
220
+ }
221
+ }
222
+ controller.close();
223
+ }
224
+ catch (error) {
225
+ controller.error(error);
226
+ if (readers)
227
+ for (const item of readers)
228
+ item.reader.releaseLock();
229
+ }
230
+ },
231
+ });
232
+ }
@@ -15,6 +15,7 @@ export declare function isNotEmpty<T>(arr: T[]): arr is [T, ...T[]];
15
15
  export declare function duplicates<T>(arr: T[], key?: (item: T) => unknown): T[];
16
16
  export declare function remove<T>(arr: T[], remove: T[] | ((item: T) => boolean)): T[];
17
17
  export declare function unique<T>(arr: T[], key?: (item: T) => unknown): T[];
18
+ export declare function omit<T extends Record<string, unknown>, K extends keyof T>(obj: T, ...keys: (K | K[])[]): Omit<T, K>;
18
19
  export declare function omitBy<T extends Record<string, unknown>, K extends keyof T>(obj: T, predicate: (value: T[K], key: K) => boolean): Partial<T>;
19
20
  export declare function orArrayToArray<T>(value?: T | T[]): T[];
20
21
  export declare function createAccessorArray<T>(array: T[], accessor: (array: T[], name: string) => T | undefined): T[] & {
@@ -8,6 +8,7 @@ exports.isNotEmpty = isNotEmpty;
8
8
  exports.duplicates = duplicates;
9
9
  exports.remove = remove;
10
10
  exports.unique = unique;
11
+ exports.omit = omit;
11
12
  exports.omitBy = omitBy;
12
13
  exports.orArrayToArray = orArrayToArray;
13
14
  exports.createAccessorArray = createAccessorArray;
@@ -73,6 +74,10 @@ function unique(arr, key = (item) => item) {
73
74
  return true;
74
75
  });
75
76
  }
77
+ function omit(obj, ...keys) {
78
+ const flattenedKeys = new Set(keys.flat());
79
+ return Object.fromEntries(Object.entries(obj).filter(([key]) => !flattenedKeys.has(key)));
80
+ }
76
81
  function omitBy(obj, predicate) {
77
82
  return Object.fromEntries(Object.entries(obj).filter(([key, value]) => {
78
83
  const k = key;
@@ -1,6 +1,6 @@
1
1
  import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
2
2
  import { ZodObject, type ZodType } from "zod";
3
- import type { Context, UserContext } from "../aigne/context.js";
3
+ import type { AgentEvent, Context, UserContext } from "../aigne/context.js";
4
4
  import type { MessagePayload } from "../aigne/message-queue.js";
5
5
  import type { Memory, MemoryAgent } from "../memory/memory.js";
6
6
  import type { MemoryRecorderInput } from "../memory/recorder.js";
@@ -594,7 +594,7 @@ export type AgentResponseStream<T> = ReadableStream<AgentResponseChunk<T>>;
594
594
  *
595
595
  * @template T Response data type
596
596
  */
597
- export type AgentResponseChunk<T> = AgentResponseDelta<T>;
597
+ export type AgentResponseChunk<T> = AgentResponseDelta<T> | AgentResponseProgress;
598
598
  /**
599
599
  * Check if a response chunk is empty
600
600
  *
@@ -622,6 +622,24 @@ export interface AgentResponseDelta<T> {
622
622
  json?: Partial<T> | TransferAgentOutput;
623
623
  };
624
624
  }
625
+ export declare function isAgentResponseDelta<T>(chunk: AgentResponseChunk<T>): chunk is AgentResponseDelta<T>;
626
+ export interface AgentResponseProgress {
627
+ progress: ({
628
+ event: "agentStarted";
629
+ input: Message;
630
+ } | {
631
+ event: "agentSucceed";
632
+ output: Message;
633
+ } | {
634
+ event: "agentFailed";
635
+ error: Error;
636
+ }) & Omit<AgentEvent, "agent"> & {
637
+ agent: {
638
+ name: string;
639
+ };
640
+ };
641
+ }
642
+ export declare function isAgentResponseProgress<T>(chunk: AgentResponseChunk<T>): chunk is AgentResponseProgress;
625
643
  /**
626
644
  * Creates a text delta for streaming responses
627
645
  *
@@ -41,6 +41,7 @@ export type ContextEmitEventMap = {
41
41
  */
42
42
  export interface InvokeOptions<U extends UserContext = UserContext> extends Partial<Omit<AgentInvokeOptions<U>, "context">> {
43
43
  returnActiveAgent?: boolean;
44
+ returnProgressChunks?: boolean;
44
45
  disableTransfer?: boolean;
45
46
  sourceAgent?: Agent;
46
47
  }
@@ -53,6 +54,8 @@ export interface UserContext extends Record<string, unknown> {
53
54
  * @hidden
54
55
  */
55
56
  export interface Context<U extends UserContext = UserContext> extends TypedEventEmitter<ContextEventMap, ContextEmitEventMap> {
57
+ id: string;
58
+ parentId?: string;
56
59
  model?: ChatModel;
57
60
  skills?: Agent[];
58
61
  usage: ContextUsage;