@aigne/core 1.33.2 → 1.36.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 +29 -0
- package/lib/cjs/agents/agent.d.ts +71 -10
- package/lib/cjs/agents/agent.js +73 -28
- package/lib/cjs/agents/ai-agent.js +6 -3
- package/lib/cjs/agents/team-agent.js +3 -13
- package/lib/cjs/aigne/context.d.ts +1 -0
- package/lib/cjs/aigne/context.js +25 -10
- package/lib/cjs/loader/agent-js.d.ts +2 -11
- package/lib/cjs/loader/agent-js.js +4 -8
- package/lib/cjs/loader/agent-yaml.d.ts +18 -2
- package/lib/cjs/loader/agent-yaml.js +32 -13
- package/lib/cjs/loader/index.d.ts +2 -2
- package/lib/cjs/loader/index.js +48 -15
- package/lib/cjs/loader/schema.d.ts +10 -0
- package/lib/cjs/loader/schema.js +17 -1
- package/lib/cjs/package.json +3 -1
- package/lib/cjs/utils/type-utils.d.ts +1 -1
- package/lib/cjs/utils/type-utils.js +2 -4
- package/lib/dts/agents/agent.d.ts +71 -10
- package/lib/dts/aigne/context.d.ts +1 -0
- package/lib/dts/loader/agent-js.d.ts +2 -11
- package/lib/dts/loader/agent-yaml.d.ts +18 -2
- package/lib/dts/loader/index.d.ts +2 -2
- package/lib/dts/loader/schema.d.ts +10 -0
- package/lib/dts/utils/type-utils.d.ts +1 -1
- package/lib/esm/agents/agent.d.ts +71 -10
- package/lib/esm/agents/agent.js +73 -28
- package/lib/esm/agents/ai-agent.js +6 -3
- package/lib/esm/agents/team-agent.js +3 -13
- package/lib/esm/aigne/context.d.ts +1 -0
- package/lib/esm/aigne/context.js +25 -10
- package/lib/esm/loader/agent-js.d.ts +2 -11
- package/lib/esm/loader/agent-js.js +5 -6
- package/lib/esm/loader/agent-yaml.d.ts +18 -2
- package/lib/esm/loader/agent-yaml.js +33 -11
- package/lib/esm/loader/index.d.ts +2 -2
- package/lib/esm/loader/index.js +49 -16
- package/lib/esm/loader/schema.d.ts +10 -0
- package/lib/esm/loader/schema.js +12 -0
- package/lib/esm/package.json +3 -1
- package/lib/esm/utils/type-utils.d.ts +1 -1
- package/lib/esm/utils/type-utils.js +2 -4
- package/package.json +4 -4
|
@@ -10,6 +10,7 @@ import { type Nullish, type PromiseOrValue, type XOr } from "../utils/type-utils
|
|
|
10
10
|
import type { GuideRailAgent, GuideRailAgentOutput } from "./guide-rail-agent.js";
|
|
11
11
|
import { type TransferAgentOutput } from "./types.js";
|
|
12
12
|
export * from "./types.js";
|
|
13
|
+
export declare const DEFAULT_INPUT_ACTION_GET = "$get";
|
|
13
14
|
/**
|
|
14
15
|
* Basic message type that can contain any key-value pairs
|
|
15
16
|
*/
|
|
@@ -72,6 +73,11 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
|
|
|
72
73
|
* Used to validate that input messages conform to the expected format
|
|
73
74
|
*/
|
|
74
75
|
inputSchema?: AgentInputOutputSchema<I>;
|
|
76
|
+
/**
|
|
77
|
+
* Default input message for the agent, it can be used to provide partial input
|
|
78
|
+
* or default values for the agent's input schema.
|
|
79
|
+
*/
|
|
80
|
+
defaultInput?: Agent<I, O>["defaultInput"];
|
|
75
81
|
/**
|
|
76
82
|
* Zod schema defining the output message structure
|
|
77
83
|
*
|
|
@@ -106,7 +112,7 @@ export interface AgentOptions<I extends Message = Message, O extends Message = M
|
|
|
106
112
|
* Maximum number of memory items to retrieve
|
|
107
113
|
*/
|
|
108
114
|
maxRetrieveMemoryCount?: number;
|
|
109
|
-
hooks?: AgentHooks<I, O
|
|
115
|
+
hooks?: AgentHooks<I, O> | AgentHooks<I, O>[];
|
|
110
116
|
}
|
|
111
117
|
export declare const agentOptionsSchema: ZodObject<{
|
|
112
118
|
[key in keyof AgentOptions]: ZodType<AgentOptions[key]>;
|
|
@@ -137,6 +143,10 @@ export interface AgentInvokeOptions<U extends UserContext = UserContext> {
|
|
|
137
143
|
* and returns the final JSON result
|
|
138
144
|
*/
|
|
139
145
|
streaming?: boolean;
|
|
146
|
+
/**
|
|
147
|
+
* Optional hooks for agent invocation
|
|
148
|
+
*/
|
|
149
|
+
hooks?: AgentHooks<any, any>;
|
|
140
150
|
}
|
|
141
151
|
/**
|
|
142
152
|
* Agent is the base class for all agents.
|
|
@@ -190,7 +200,7 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
|
|
|
190
200
|
* Here's an example of using hooks:
|
|
191
201
|
* {@includeCode ../../test/agents/agent.test.ts#example-agent-hooks}
|
|
192
202
|
*/
|
|
193
|
-
readonly hooks: AgentHooks<I, O
|
|
203
|
+
readonly hooks: AgentHooks<I, O>[];
|
|
194
204
|
/**
|
|
195
205
|
* List of GuideRail agents applied to this agent
|
|
196
206
|
*
|
|
@@ -232,6 +242,11 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
|
|
|
232
242
|
*/
|
|
233
243
|
readonly description?: string;
|
|
234
244
|
private readonly _inputSchema?;
|
|
245
|
+
defaultInput?: Partial<{
|
|
246
|
+
[key in keyof I]: {
|
|
247
|
+
[DEFAULT_INPUT_ACTION_GET]: string;
|
|
248
|
+
} | I[key];
|
|
249
|
+
}>;
|
|
235
250
|
private readonly _outputSchema?;
|
|
236
251
|
/**
|
|
237
252
|
* Get the input data schema for this agent
|
|
@@ -372,6 +387,8 @@ export declare abstract class Agent<I extends Message = any, O extends Message =
|
|
|
372
387
|
* @returns Agent response (streaming or regular)
|
|
373
388
|
*/
|
|
374
389
|
invoke(input: I & Message, options?: Partial<AgentInvokeOptions>): Promise<AgentResponse<O>>;
|
|
390
|
+
private callHooks;
|
|
391
|
+
private mergeDefaultInput;
|
|
375
392
|
protected invokeSkill<I extends Message, O extends Message>(skill: Agent<I, O>, input: I & Message, options: AgentInvokeOptions): Promise<O>;
|
|
376
393
|
/**
|
|
377
394
|
* Process agent output
|
|
@@ -517,11 +534,15 @@ export interface AgentHooks<I extends Message = Message, O extends Message = Mes
|
|
|
517
534
|
*
|
|
518
535
|
* @param event Object containing the input message
|
|
519
536
|
*/
|
|
520
|
-
onStart?: (event: {
|
|
537
|
+
onStart?: ((event: {
|
|
521
538
|
context: Context;
|
|
522
539
|
input: I;
|
|
523
540
|
}) => PromiseOrValue<void | {
|
|
524
541
|
input?: I;
|
|
542
|
+
}>) | Agent<{
|
|
543
|
+
input: I;
|
|
544
|
+
}, {
|
|
545
|
+
input?: I;
|
|
525
546
|
}>;
|
|
526
547
|
/**
|
|
527
548
|
* Called when agent processing completes or fails
|
|
@@ -532,13 +553,39 @@ export interface AgentHooks<I extends Message = Message, O extends Message = Mes
|
|
|
532
553
|
*
|
|
533
554
|
* @param event Object containing the input message and either output or error
|
|
534
555
|
*/
|
|
535
|
-
onEnd?: (event: XOr<{
|
|
556
|
+
onEnd?: ((event: XOr<{
|
|
536
557
|
context: Context;
|
|
537
558
|
input: I;
|
|
538
559
|
output: O;
|
|
539
560
|
error: Error;
|
|
540
561
|
}, "output", "error">) => PromiseOrValue<void | {
|
|
541
562
|
output?: O;
|
|
563
|
+
}>) | Agent<XOr<{
|
|
564
|
+
input: I;
|
|
565
|
+
output: O;
|
|
566
|
+
error: Error;
|
|
567
|
+
}, "output", "error">, {
|
|
568
|
+
output?: O;
|
|
569
|
+
}>;
|
|
570
|
+
onSuccess?: ((event: {
|
|
571
|
+
context: Context;
|
|
572
|
+
input: I;
|
|
573
|
+
output: O;
|
|
574
|
+
}) => PromiseOrValue<void | {
|
|
575
|
+
output?: O;
|
|
576
|
+
}>) | Agent<{
|
|
577
|
+
input: I;
|
|
578
|
+
output: O;
|
|
579
|
+
}, {
|
|
580
|
+
output?: O;
|
|
581
|
+
}>;
|
|
582
|
+
onError?: ((event: {
|
|
583
|
+
context: Context;
|
|
584
|
+
input: I;
|
|
585
|
+
error: Error;
|
|
586
|
+
}) => void) | Agent<{
|
|
587
|
+
input: I;
|
|
588
|
+
error: Error;
|
|
542
589
|
}>;
|
|
543
590
|
/**
|
|
544
591
|
* Called before a skill (sub-agent) is invoked
|
|
@@ -548,11 +595,14 @@ export interface AgentHooks<I extends Message = Message, O extends Message = Mes
|
|
|
548
595
|
*
|
|
549
596
|
* @param event Object containing the skill being used and input message
|
|
550
597
|
*/
|
|
551
|
-
onSkillStart?: (event: {
|
|
598
|
+
onSkillStart?: ((event: {
|
|
552
599
|
context: Context;
|
|
553
600
|
skill: Agent;
|
|
554
601
|
input: Message;
|
|
555
|
-
}) => PromiseOrValue<void
|
|
602
|
+
}) => PromiseOrValue<void>) | Agent<{
|
|
603
|
+
skill: Agent;
|
|
604
|
+
input: Message;
|
|
605
|
+
}>;
|
|
556
606
|
/**
|
|
557
607
|
* Called after a skill (sub-agent) completes or fails
|
|
558
608
|
*
|
|
@@ -562,13 +612,18 @@ export interface AgentHooks<I extends Message = Message, O extends Message = Mes
|
|
|
562
612
|
*
|
|
563
613
|
* @param event Object containing the skill used, input message, and either output or error
|
|
564
614
|
*/
|
|
565
|
-
onSkillEnd?: (event: XOr<{
|
|
615
|
+
onSkillEnd?: ((event: XOr<{
|
|
566
616
|
context: Context;
|
|
567
617
|
skill: Agent;
|
|
568
618
|
input: Message;
|
|
569
619
|
output: Message;
|
|
570
620
|
error: Error;
|
|
571
|
-
}, "output", "error">) => PromiseOrValue<void
|
|
621
|
+
}, "output", "error">) => PromiseOrValue<void>) | Agent<XOr<{
|
|
622
|
+
skill: Agent;
|
|
623
|
+
input: Message;
|
|
624
|
+
output: Message;
|
|
625
|
+
error: Error;
|
|
626
|
+
}, "output", "error">>;
|
|
572
627
|
/**
|
|
573
628
|
* Called when an agent hands off processing to another agent
|
|
574
629
|
*
|
|
@@ -578,13 +633,19 @@ export interface AgentHooks<I extends Message = Message, O extends Message = Mes
|
|
|
578
633
|
*
|
|
579
634
|
* @param event Object containing the source agent, target agent, and input message
|
|
580
635
|
*/
|
|
581
|
-
onHandoff?: (event: {
|
|
636
|
+
onHandoff?: ((event: {
|
|
582
637
|
context: Context;
|
|
583
638
|
source: Agent;
|
|
584
639
|
target: Agent;
|
|
585
640
|
input: I;
|
|
586
|
-
}) => PromiseOrValue<void
|
|
641
|
+
}) => PromiseOrValue<void>) | Agent<{
|
|
642
|
+
source: Agent;
|
|
643
|
+
target: Agent;
|
|
644
|
+
input: I;
|
|
645
|
+
}>;
|
|
587
646
|
}
|
|
647
|
+
export type AgentHookInput<H extends keyof AgentHooks, Hook extends AgentHooks[H] = AgentHooks[H]> = Hook extends (input: infer I) => any ? Omit<I, "context"> : never;
|
|
648
|
+
export type AgentHookOutput<H extends keyof AgentHooks, Hook extends AgentHooks[H] = AgentHooks[H]> = Hook extends (...args: any[]) => any ? Exclude<Awaited<ReturnType<Hook>>, void> | undefined : never;
|
|
588
649
|
/**
|
|
589
650
|
* Response type for an agent, can be:
|
|
590
651
|
* - Direct response object
|
package/lib/esm/agents/agent.js
CHANGED
|
@@ -2,9 +2,17 @@ import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
|
|
|
2
2
|
import { ZodObject, z } from "zod";
|
|
3
3
|
import { logger } from "../utils/logger.js";
|
|
4
4
|
import { agentResponseStreamToObject, asyncGeneratorToReadableStream, isAsyncGenerator, objectToAgentResponseStream, onAgentResponseStreamEnd, } from "../utils/stream-utils.js";
|
|
5
|
-
import { checkArguments, createAccessorArray, flat, isEmpty, isRecord, } from "../utils/type-utils.js";
|
|
5
|
+
import { checkArguments, createAccessorArray, flat, isEmpty, isNil, isRecord, } from "../utils/type-utils.js";
|
|
6
6
|
import { replaceTransferAgentToName, transferToAgentOutput, } from "./types.js";
|
|
7
7
|
export * from "./types.js";
|
|
8
|
+
export const DEFAULT_INPUT_ACTION_GET = "$get";
|
|
9
|
+
const hooksSchema = z.object({
|
|
10
|
+
onStart: z.custom().optional(),
|
|
11
|
+
onEnd: z.custom().optional(),
|
|
12
|
+
onSkillStart: z.custom().optional(),
|
|
13
|
+
onSkillEnd: z.custom().optional(),
|
|
14
|
+
onHandoff: z.custom().optional(),
|
|
15
|
+
});
|
|
8
16
|
export const agentOptionsSchema = z.object({
|
|
9
17
|
subscribeTopic: z.union([z.string(), z.array(z.string())]).optional(),
|
|
10
18
|
publishTopic: z
|
|
@@ -13,21 +21,14 @@ export const agentOptionsSchema = z.object({
|
|
|
13
21
|
name: z.string().optional(),
|
|
14
22
|
description: z.string().optional(),
|
|
15
23
|
inputSchema: z.custom().optional(),
|
|
24
|
+
defaultInput: z.record(z.any()).optional(),
|
|
16
25
|
outputSchema: z.custom().optional(),
|
|
17
26
|
includeInputInOutput: z.boolean().optional(),
|
|
18
27
|
skills: z.array(z.union([z.custom(), z.custom()])).optional(),
|
|
19
28
|
disableEvents: z.boolean().optional(),
|
|
20
29
|
memory: z.union([z.custom(), z.array(z.custom())]).optional(),
|
|
21
30
|
maxRetrieveMemoryCount: z.number().optional(),
|
|
22
|
-
hooks: z
|
|
23
|
-
.object({
|
|
24
|
-
onStart: z.custom().optional(),
|
|
25
|
-
onEnd: z.custom().optional(),
|
|
26
|
-
onSkillStart: z.custom().optional(),
|
|
27
|
-
onSkillEnd: z.custom().optional(),
|
|
28
|
-
onHandoff: z.custom().optional(),
|
|
29
|
-
})
|
|
30
|
-
.optional(),
|
|
31
|
+
hooks: z.union([z.array(hooksSchema), hooksSchema]).optional(),
|
|
31
32
|
guideRails: z.array(z.custom()).optional(),
|
|
32
33
|
});
|
|
33
34
|
/**
|
|
@@ -62,6 +63,7 @@ export class Agent {
|
|
|
62
63
|
if (outputSchema)
|
|
63
64
|
checkAgentInputOutputSchema(outputSchema);
|
|
64
65
|
this._inputSchema = inputSchema;
|
|
66
|
+
this.defaultInput = options.defaultInput;
|
|
65
67
|
this._outputSchema = outputSchema;
|
|
66
68
|
this.includeInputInOutput = options.includeInputInOutput;
|
|
67
69
|
this.subscribeTopic = options.subscribeTopic;
|
|
@@ -76,7 +78,7 @@ export class Agent {
|
|
|
76
78
|
this.memories.push(options.memory);
|
|
77
79
|
}
|
|
78
80
|
this.maxRetrieveMemoryCount = options.maxRetrieveMemoryCount;
|
|
79
|
-
this.hooks = options.hooks
|
|
81
|
+
this.hooks = flat(options.hooks);
|
|
80
82
|
this.guideRails = options.guideRails;
|
|
81
83
|
}
|
|
82
84
|
/**
|
|
@@ -142,6 +144,7 @@ export class Agent {
|
|
|
142
144
|
*/
|
|
143
145
|
description;
|
|
144
146
|
_inputSchema;
|
|
147
|
+
defaultInput;
|
|
145
148
|
_outputSchema;
|
|
146
149
|
/**
|
|
147
150
|
* Get the input data schema for this agent
|
|
@@ -291,17 +294,23 @@ export class Agent {
|
|
|
291
294
|
...options,
|
|
292
295
|
context: options.context ?? (await this.newDefaultContext()),
|
|
293
296
|
};
|
|
297
|
+
input = this.mergeDefaultInput(input);
|
|
294
298
|
logger.debug("Invoke agent %s started with input: %O", this.name, input);
|
|
295
299
|
if (!this.disableEvents)
|
|
296
300
|
opts.context.emit("agentStarted", { agent: this, input });
|
|
297
301
|
try {
|
|
298
|
-
let
|
|
299
|
-
|
|
300
|
-
|
|
302
|
+
let response;
|
|
303
|
+
const s = await this.callHooks("onStart", { input }, opts);
|
|
304
|
+
if (s?.input)
|
|
305
|
+
input = s.input;
|
|
306
|
+
input = checkArguments(`Agent ${this.name} input`, this.inputSchema, input);
|
|
307
|
+
await this.preprocess(input, opts);
|
|
301
308
|
this.checkContextStatus(opts);
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
response
|
|
309
|
+
if (!response) {
|
|
310
|
+
response = await this.process(input, opts);
|
|
311
|
+
if (response instanceof Agent) {
|
|
312
|
+
response = transferToAgentOutput(response);
|
|
313
|
+
}
|
|
305
314
|
}
|
|
306
315
|
if (opts.streaming) {
|
|
307
316
|
const stream = response instanceof ReadableStream
|
|
@@ -311,29 +320,62 @@ export class Agent {
|
|
|
311
320
|
: objectToAgentResponseStream(response);
|
|
312
321
|
return this.checkResponseByGuideRails(input, onAgentResponseStreamEnd(stream, {
|
|
313
322
|
onResult: async (result) => {
|
|
314
|
-
return await this.processAgentOutput(
|
|
323
|
+
return await this.processAgentOutput(input, result, opts);
|
|
315
324
|
},
|
|
316
325
|
onError: async (error) => {
|
|
317
326
|
return await this.processAgentError(input, error, opts);
|
|
318
327
|
},
|
|
319
328
|
}), opts);
|
|
320
329
|
}
|
|
321
|
-
return await this.checkResponseByGuideRails(input, this.processAgentOutput(
|
|
330
|
+
return await this.checkResponseByGuideRails(input, this.processAgentOutput(input, await agentProcessResultToObject(response), opts), opts);
|
|
322
331
|
}
|
|
323
332
|
catch (error) {
|
|
324
333
|
throw await this.processAgentError(input, error, opts);
|
|
325
334
|
}
|
|
326
335
|
}
|
|
336
|
+
async callHooks(hook, input, options) {
|
|
337
|
+
const { context } = options;
|
|
338
|
+
const result = {};
|
|
339
|
+
for (const hooks of flat(options.hooks, this.hooks)) {
|
|
340
|
+
const h = hooks[hook];
|
|
341
|
+
if (!h)
|
|
342
|
+
continue;
|
|
343
|
+
if (typeof h === "function") {
|
|
344
|
+
Object.assign(result, await h({ ...input, context }));
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
Object.assign(result, await context.invoke(h, input));
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return result;
|
|
351
|
+
}
|
|
352
|
+
mergeDefaultInput(input) {
|
|
353
|
+
const defaultInput = Object.fromEntries(Object.entries(this.defaultInput ?? {}).filter(([, v]) => !(typeof v === "object" && DEFAULT_INPUT_ACTION_GET in v)));
|
|
354
|
+
input = { ...defaultInput, ...input };
|
|
355
|
+
for (const key of Object.keys(this.defaultInput ?? {})) {
|
|
356
|
+
const v = this.defaultInput?.[key];
|
|
357
|
+
if (v &&
|
|
358
|
+
typeof v === "object" &&
|
|
359
|
+
DEFAULT_INPUT_ACTION_GET in v &&
|
|
360
|
+
typeof v[DEFAULT_INPUT_ACTION_GET] === "string" &&
|
|
361
|
+
isNil(input[key])) {
|
|
362
|
+
const value = input[v[DEFAULT_INPUT_ACTION_GET]];
|
|
363
|
+
if (!isNil(value))
|
|
364
|
+
Object.assign(input, { [key]: value });
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return input;
|
|
368
|
+
}
|
|
327
369
|
async invokeSkill(skill, input, options) {
|
|
328
370
|
const { context } = options;
|
|
329
|
-
await this.
|
|
371
|
+
await this.callHooks("onSkillStart", { skill, input }, options);
|
|
330
372
|
try {
|
|
331
373
|
const output = await context.invoke(skill, input);
|
|
332
|
-
await this.
|
|
374
|
+
await this.callHooks("onSkillEnd", { skill, input, output }, options);
|
|
333
375
|
return output;
|
|
334
376
|
}
|
|
335
377
|
catch (error) {
|
|
336
|
-
await this.
|
|
378
|
+
await this.callHooks("onSkillEnd", { skill, input, error }, options);
|
|
337
379
|
throw error;
|
|
338
380
|
}
|
|
339
381
|
}
|
|
@@ -353,14 +395,17 @@ export class Agent {
|
|
|
353
395
|
throw new Error(`expect to return a record type such as {result: ...}, but got (${typeof output}): ${output}`);
|
|
354
396
|
}
|
|
355
397
|
const parsedOutput = checkArguments(`Agent ${this.name} output`, this.outputSchema, output);
|
|
356
|
-
|
|
398
|
+
let finalOutput = this.includeInputInOutput ? { ...input, ...parsedOutput } : parsedOutput;
|
|
357
399
|
await this.postprocess(input, finalOutput, options);
|
|
358
400
|
logger.debug("Invoke agent %s succeed with output: %O", this.name, finalOutput);
|
|
359
401
|
if (!this.disableEvents)
|
|
360
402
|
context.emit("agentSucceed", { agent: this, output: finalOutput });
|
|
361
|
-
|
|
362
|
-
if (o)
|
|
363
|
-
|
|
403
|
+
let o = await this.callHooks("onSuccess", { input, output: finalOutput }, options);
|
|
404
|
+
if (o?.output)
|
|
405
|
+
finalOutput = o.output;
|
|
406
|
+
o = await this.callHooks("onEnd", { input, output: finalOutput }, options);
|
|
407
|
+
if (o?.output)
|
|
408
|
+
finalOutput = o.output;
|
|
364
409
|
return finalOutput;
|
|
365
410
|
}
|
|
366
411
|
/**
|
|
@@ -375,8 +420,8 @@ export class Agent {
|
|
|
375
420
|
logger.error("Invoke agent %s failed with error: %O", this.name, error);
|
|
376
421
|
if (!this.disableEvents)
|
|
377
422
|
options.context.emit("agentFailed", { agent: this, error });
|
|
378
|
-
|
|
379
|
-
await this.
|
|
423
|
+
await this.callHooks("onError", { input, error }, options);
|
|
424
|
+
await this.callHooks("onEnd", { input, error }, options);
|
|
380
425
|
return error;
|
|
381
426
|
}
|
|
382
427
|
/**
|
|
@@ -240,7 +240,7 @@ export class AIAgent extends Agent {
|
|
|
240
240
|
const outputKey = this.outputKey;
|
|
241
241
|
for (;;) {
|
|
242
242
|
const modelOutput = {};
|
|
243
|
-
let stream = await options.context.invoke(model, { ...modelInput, messages: modelInput.messages.concat(toolCallMessages) }, { streaming: true });
|
|
243
|
+
let stream = await options.context.invoke(model, { ...modelInput, messages: modelInput.messages.concat(toolCallMessages) }, { ...options, streaming: true });
|
|
244
244
|
if (this.structuredStreamMode) {
|
|
245
245
|
const { metadataStart, metadataEnd, parse } = this.customStructuredStreamInstructions || STRUCTURED_STREAM_INSTRUCTIONS;
|
|
246
246
|
stream = stream.pipeThrough(new ExtractMetadataTransform({ start: metadataStart, end: metadataEnd, parse }));
|
|
@@ -315,14 +315,17 @@ export class AIAgent extends Agent {
|
|
|
315
315
|
* @protected
|
|
316
316
|
*/
|
|
317
317
|
async *_processRouter(input, model, modelInput, options, toolsMap) {
|
|
318
|
-
const { toolCalls: [call] = [] } = await options.context.invoke(model, modelInput
|
|
318
|
+
const { toolCalls: [call] = [] } = await options.context.invoke(model, modelInput, {
|
|
319
|
+
...options,
|
|
320
|
+
streaming: false,
|
|
321
|
+
});
|
|
319
322
|
if (!call) {
|
|
320
323
|
throw new Error("Router toolChoice requires exactly one tool to be executed");
|
|
321
324
|
}
|
|
322
325
|
const tool = toolsMap.get(call.function.name);
|
|
323
326
|
if (!tool)
|
|
324
327
|
throw new Error(`Tool not found: ${call.function.name}`);
|
|
325
|
-
const stream = await options.context.invoke(tool, { ...call.function.arguments, ...input }, { streaming: true, sourceAgent: this });
|
|
328
|
+
const stream = await options.context.invoke(tool, { ...call.function.arguments, ...input }, { ...options, streaming: true, sourceAgent: this });
|
|
326
329
|
return yield* stream;
|
|
327
330
|
}
|
|
328
331
|
}
|
|
@@ -165,19 +165,13 @@ export class TeamAgent extends Agent {
|
|
|
165
165
|
*/
|
|
166
166
|
async *_processSequential(input, options) {
|
|
167
167
|
const output = {};
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const newAgents = [];
|
|
171
|
-
for (const agent of agents) {
|
|
172
|
-
const [o, transferToAgent] = await options.context.invoke(agent, { ...input, ...output }, { returnActiveAgent: true, streaming: true });
|
|
168
|
+
for (const agent of this.skills) {
|
|
169
|
+
const o = await options.context.invoke(agent, { ...input, ...output }, { ...options, streaming: true });
|
|
173
170
|
for await (const chunk of o) {
|
|
174
171
|
yield chunk;
|
|
175
172
|
mergeAgentResponseChunk(output, chunk);
|
|
176
173
|
}
|
|
177
|
-
newAgents.push(await transferToAgent);
|
|
178
174
|
}
|
|
179
|
-
this.skills.splice(0);
|
|
180
|
-
this.skills.push(...newAgents);
|
|
181
175
|
}
|
|
182
176
|
/**
|
|
183
177
|
* Process input in parallel through all agents in the team.
|
|
@@ -194,8 +188,7 @@ export class TeamAgent extends Agent {
|
|
|
194
188
|
* @private
|
|
195
189
|
*/
|
|
196
190
|
async *_processParallel(input, options) {
|
|
197
|
-
const
|
|
198
|
-
const streams = result.map((i) => i[0]);
|
|
191
|
+
const streams = await Promise.all(this.skills.map((agent) => options.context.invoke(agent, input, { ...options, streaming: true })));
|
|
199
192
|
const read = async (index, reader) => {
|
|
200
193
|
const promise = reader.read();
|
|
201
194
|
return promise.then((result) => ({ ...result, reader, index }));
|
|
@@ -230,8 +223,5 @@ export class TeamAgent extends Agent {
|
|
|
230
223
|
yield { delta: { ...delta, text } };
|
|
231
224
|
}
|
|
232
225
|
}
|
|
233
|
-
const agents = await Promise.all(result.map((i) => i[1]));
|
|
234
|
-
this.skills.splice(0);
|
|
235
|
-
this.skills.push(...agents);
|
|
236
226
|
}
|
|
237
227
|
}
|
|
@@ -180,6 +180,7 @@ declare class AIGNEContextShared {
|
|
|
180
180
|
span?: Span;
|
|
181
181
|
constructor(parent?: (Pick<Context, "model" | "skills" | "limits" | "observer"> & {
|
|
182
182
|
messageQueue?: MessageQueue;
|
|
183
|
+
events?: Emitter<any>;
|
|
183
184
|
}) | undefined);
|
|
184
185
|
readonly messageQueue: MessageQueue;
|
|
185
186
|
readonly events: Emitter<any>;
|
package/lib/esm/aigne/context.js
CHANGED
|
@@ -34,7 +34,7 @@ export class AIGNEContext {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
else {
|
|
37
|
-
this.internal = new AIGNEContextShared(parent);
|
|
37
|
+
this.internal = new AIGNEContextShared(parent instanceof AIGNEContext ? parent.internal : parent);
|
|
38
38
|
this.span = tracer?.startSpan("AIGNEContext");
|
|
39
39
|
// 修改了 rootId 是否会之前的有影响?,之前为 this.id
|
|
40
40
|
this.rootId = this.span?.spanContext?.().traceId ?? v7();
|
|
@@ -265,9 +265,10 @@ class AIGNEContextShared {
|
|
|
265
265
|
constructor(parent) {
|
|
266
266
|
this.parent = parent;
|
|
267
267
|
this.messageQueue = this.parent?.messageQueue ?? new MessageQueue();
|
|
268
|
+
this.events = this.parent?.events ?? new Emitter();
|
|
268
269
|
}
|
|
269
270
|
messageQueue;
|
|
270
|
-
events
|
|
271
|
+
events;
|
|
271
272
|
get model() {
|
|
272
273
|
return this.parent?.model;
|
|
273
274
|
}
|
|
@@ -302,21 +303,35 @@ class AIGNEContextShared {
|
|
|
302
303
|
this.initTimeout();
|
|
303
304
|
return withAbortSignal(this.abortController.signal, new Error("AIGNEContext is timeout"), () => this.invokeAgent(agent, input, context, options));
|
|
304
305
|
}
|
|
305
|
-
async *invokeAgent(agent, input, context, options) {
|
|
306
|
+
async *invokeAgent(agent, input, context, options = {}) {
|
|
306
307
|
const startedAt = Date.now();
|
|
307
308
|
try {
|
|
308
309
|
let activeAgent = agent;
|
|
309
310
|
for (;;) {
|
|
310
311
|
const result = {};
|
|
311
312
|
if (options?.sourceAgent && activeAgent !== options.sourceAgent) {
|
|
312
|
-
options.sourceAgent.hooks
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
313
|
+
for (const { onHandoff } of [options.hooks ?? {}, ...options.sourceAgent.hooks]) {
|
|
314
|
+
if (!onHandoff)
|
|
315
|
+
continue;
|
|
316
|
+
await (typeof onHandoff === "function"
|
|
317
|
+
? onHandoff({
|
|
318
|
+
context,
|
|
319
|
+
source: options.sourceAgent,
|
|
320
|
+
target: activeAgent,
|
|
321
|
+
input,
|
|
322
|
+
})
|
|
323
|
+
: context.invoke(onHandoff, {
|
|
324
|
+
source: options.sourceAgent,
|
|
325
|
+
target: activeAgent,
|
|
326
|
+
input,
|
|
327
|
+
}));
|
|
328
|
+
}
|
|
318
329
|
}
|
|
319
|
-
const stream = await activeAgent.invoke(input, {
|
|
330
|
+
const stream = await activeAgent.invoke(input, {
|
|
331
|
+
hooks: options.hooks,
|
|
332
|
+
context,
|
|
333
|
+
streaming: true,
|
|
334
|
+
});
|
|
320
335
|
for await (const value of stream) {
|
|
321
336
|
if (isAgentResponseDelta(value)) {
|
|
322
337
|
if (value.delta.json) {
|
|
@@ -1,17 +1,8 @@
|
|
|
1
|
-
import { type ZodObject, type ZodType, z } from "zod";
|
|
2
1
|
import { Agent, type FunctionAgentFn } from "../agents/agent.js";
|
|
3
2
|
export declare function loadAgentFromJsFile(path: string): Promise<Agent<any, any> | {
|
|
4
3
|
process: FunctionAgentFn;
|
|
5
4
|
name: string;
|
|
6
5
|
description?: string | undefined;
|
|
7
|
-
inputSchema?:
|
|
8
|
-
|
|
9
|
-
}, {
|
|
10
|
-
[x: string]: any;
|
|
11
|
-
}> | undefined;
|
|
12
|
-
outputSchema?: ZodObject<Record<string, ZodType<any, z.ZodTypeDef, any>>, z.UnknownKeysParam, z.ZodTypeAny, {
|
|
13
|
-
[x: string]: any;
|
|
14
|
-
}, {
|
|
15
|
-
[x: string]: any;
|
|
16
|
-
}> | undefined;
|
|
6
|
+
inputSchema?: any;
|
|
7
|
+
outputSchema?: any;
|
|
17
8
|
}>;
|
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
import { jsonSchemaToZod } from "@aigne/json-schema-to-zod";
|
|
2
|
-
import camelize from "camelize-ts";
|
|
3
2
|
import { z } from "zod";
|
|
4
3
|
import { Agent } from "../agents/agent.js";
|
|
5
4
|
import { tryOrThrow } from "../utils/type-utils.js";
|
|
6
|
-
import { inputOutputSchema, optionalize } from "./schema.js";
|
|
5
|
+
import { camelizeSchema, inputOutputSchema, optionalize } from "./schema.js";
|
|
7
6
|
export async function loadAgentFromJsFile(path) {
|
|
8
|
-
const agentJsFileSchema = z.object({
|
|
7
|
+
const agentJsFileSchema = camelizeSchema(z.object({
|
|
9
8
|
name: z.string(),
|
|
10
9
|
description: optionalize(z.string()),
|
|
11
10
|
inputSchema: optionalize(inputOutputSchema({ path })).transform((v) => v ? jsonSchemaToZod(v) : undefined),
|
|
12
11
|
outputSchema: optionalize(inputOutputSchema({ path })).transform((v) => v ? jsonSchemaToZod(v) : undefined),
|
|
13
12
|
process: z.custom(),
|
|
14
|
-
});
|
|
13
|
+
}));
|
|
15
14
|
const { default: agent } = await tryOrThrow(() => import(/* @vite-ignore */ path), (error) => new Error(`Failed to load agent definition from ${path}: ${error.message}`));
|
|
16
15
|
if (agent instanceof Agent)
|
|
17
16
|
return agent;
|
|
18
17
|
if (typeof agent !== "function") {
|
|
19
18
|
throw new Error(`Agent file ${path} must export a default function, but got ${typeof agent}`);
|
|
20
19
|
}
|
|
21
|
-
return tryOrThrow(() => agentJsFileSchema.parseAsync(
|
|
20
|
+
return tryOrThrow(() => agentJsFileSchema.parseAsync({
|
|
22
21
|
...agent,
|
|
23
22
|
name: agent.agent_name || agent.agentName || agent.name,
|
|
24
23
|
process: agent,
|
|
25
|
-
})
|
|
24
|
+
}), (error) => new Error(`Failed to parse agent from ${path}: ${error.message}`));
|
|
26
25
|
}
|
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
import { type ZodType } from "zod";
|
|
2
2
|
import { AIAgentToolChoice } from "../agents/ai-agent.js";
|
|
3
3
|
import { ProcessMode } from "../agents/team-agent.js";
|
|
4
|
+
export interface HooksSchema {
|
|
5
|
+
onStart?: NestAgentSchema;
|
|
6
|
+
onSuccess?: NestAgentSchema;
|
|
7
|
+
onError?: NestAgentSchema;
|
|
8
|
+
onEnd?: NestAgentSchema;
|
|
9
|
+
onSkillStart?: NestAgentSchema;
|
|
10
|
+
onSkillEnd?: NestAgentSchema;
|
|
11
|
+
onHandoff?: NestAgentSchema;
|
|
12
|
+
}
|
|
13
|
+
export type NestAgentSchema = string | {
|
|
14
|
+
url: string;
|
|
15
|
+
defaultInput?: Record<string, any>;
|
|
16
|
+
hooks?: HooksSchema | HooksSchema[];
|
|
17
|
+
} | AgentSchema;
|
|
4
18
|
interface BaseAgentSchema {
|
|
5
19
|
name?: string;
|
|
6
20
|
description?: string;
|
|
7
21
|
inputSchema?: ZodType<Record<string, any>>;
|
|
22
|
+
defaultInput?: Record<string, any>;
|
|
8
23
|
outputSchema?: ZodType<Record<string, any>>;
|
|
9
|
-
skills?:
|
|
24
|
+
skills?: NestAgentSchema[];
|
|
25
|
+
hooks?: HooksSchema | HooksSchema[];
|
|
10
26
|
memory?: boolean | {
|
|
11
27
|
provider: string;
|
|
12
28
|
subscribeTopic?: string[];
|
|
@@ -19,7 +35,7 @@ interface AIAgentSchema extends BaseAgentSchema {
|
|
|
19
35
|
outputKey?: string;
|
|
20
36
|
toolChoice?: AIAgentToolChoice;
|
|
21
37
|
}
|
|
22
|
-
interface MCPAgentSchema {
|
|
38
|
+
interface MCPAgentSchema extends BaseAgentSchema {
|
|
23
39
|
type: "mcp";
|
|
24
40
|
url?: string;
|
|
25
41
|
command?: string;
|