@aigne/core 1.31.0 → 1.32.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 +29 -0
- package/lib/cjs/agents/agent.js +3 -0
- package/lib/cjs/agents/ai-agent.js +1 -1
- package/lib/cjs/aigne/context.js +0 -10
- package/lib/cjs/loader/index.js +3 -0
- package/lib/cjs/prompt/prompt-builder.d.ts +5 -1
- package/lib/cjs/prompt/prompt-builder.js +12 -10
- package/lib/cjs/prompt/template.d.ts +21 -7
- package/lib/cjs/prompt/template.js +57 -19
- package/lib/cjs/utils/stream-utils.js +3 -0
- package/lib/dts/prompt/prompt-builder.d.ts +5 -1
- package/lib/dts/prompt/template.d.ts +21 -7
- package/lib/esm/agents/agent.js +4 -1
- package/lib/esm/agents/ai-agent.js +1 -1
- package/lib/esm/aigne/context.js +0 -10
- package/lib/esm/loader/index.js +3 -0
- package/lib/esm/prompt/prompt-builder.d.ts +5 -1
- package/lib/esm/prompt/prompt-builder.js +12 -10
- package/lib/esm/prompt/template.d.ts +21 -7
- package/lib/esm/prompt/template.js +54 -17
- package/lib/esm/utils/stream-utils.js +4 -1
- package/package.json +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,35 @@
|
|
|
12
12
|
* dependencies
|
|
13
13
|
* @aigne/observability bumped to 0.1.0
|
|
14
14
|
|
|
15
|
+
## [1.32.1](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.32.0...core-v1.32.1) (2025-07-09)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Dependencies
|
|
19
|
+
|
|
20
|
+
* The following workspace dependencies were updated
|
|
21
|
+
* dependencies
|
|
22
|
+
* @aigne/observability-api bumped to 0.7.0
|
|
23
|
+
|
|
24
|
+
## [1.32.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.31.0...core-v1.32.0) (2025-07-08)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Features
|
|
28
|
+
|
|
29
|
+
* **core:** add jinja syntax support for prompt builder ([#230](https://github.com/AIGNE-io/aigne-framework/issues/230)) ([74436a7](https://github.com/AIGNE-io/aigne-framework/commit/74436a7faac0c59a32b0153481386162649f4357))
|
|
30
|
+
* support setting component id to different component data ([#226](https://github.com/AIGNE-io/aigne-framework/issues/226)) ([c7b3224](https://github.com/AIGNE-io/aigne-framework/commit/c7b32240e6660f34974615bcb9b91978a1191e3e))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
### Bug Fixes
|
|
34
|
+
|
|
35
|
+
* **core:** ensure output is a record type ([#228](https://github.com/AIGNE-io/aigne-framework/issues/228)) ([dfd9104](https://github.com/AIGNE-io/aigne-framework/commit/dfd910451e5f1f9edd94a719857e36d34fadbe45))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
### Dependencies
|
|
39
|
+
|
|
40
|
+
* The following workspace dependencies were updated
|
|
41
|
+
* dependencies
|
|
42
|
+
* @aigne/observability-api bumped to 0.6.0
|
|
43
|
+
|
|
15
44
|
## [1.31.0](https://github.com/AIGNE-io/aigne-framework/compare/core-v1.30.0...core-v1.31.0) (2025-07-04)
|
|
16
45
|
|
|
17
46
|
|
package/lib/cjs/agents/agent.js
CHANGED
|
@@ -394,6 +394,9 @@ class Agent {
|
|
|
394
394
|
*/
|
|
395
395
|
async processAgentOutput(input, output, options) {
|
|
396
396
|
const { context } = options;
|
|
397
|
+
if (!(0, type_utils_js_1.isRecord)(output)) {
|
|
398
|
+
throw new Error(`expect to return a record type such as {result: ...}, but got (${typeof output}): ${output}`);
|
|
399
|
+
}
|
|
397
400
|
const parsedOutput = (0, type_utils_js_1.checkArguments)(`Agent ${this.name} output`, this.outputSchema, output);
|
|
398
401
|
const finalOutput = this.includeInputInOutput ? { ...input, ...parsedOutput } : parsedOutput;
|
|
399
402
|
await this.postprocess(input, finalOutput, options);
|
|
@@ -286,7 +286,7 @@ class AIAgent extends agent_js_1.Agent {
|
|
|
286
286
|
}
|
|
287
287
|
// Continue LLM function calling loop if any tools were executed
|
|
288
288
|
if (executedToolCalls.length) {
|
|
289
|
-
toolCallMessages.push(template_js_1.AgentMessageTemplate.from(undefined, executedToolCalls.map(({ call }) => call)).format(), ...executedToolCalls.map(({ call, output }) => template_js_1.ToolMessageTemplate.from(output, call.id).format()));
|
|
289
|
+
toolCallMessages.push(await template_js_1.AgentMessageTemplate.from(undefined, executedToolCalls.map(({ call }) => call)).format(), ...(await Promise.all(executedToolCalls.map(({ call, output }) => template_js_1.ToolMessageTemplate.from(output, call.id).format()))));
|
|
290
290
|
continue;
|
|
291
291
|
}
|
|
292
292
|
}
|
package/lib/cjs/aigne/context.js
CHANGED
|
@@ -237,22 +237,12 @@ class AIGNEContext {
|
|
|
237
237
|
span.setAttribute("output", JSON.stringify({}));
|
|
238
238
|
}
|
|
239
239
|
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
240
|
-
await this.observer?.traceExporter
|
|
241
|
-
?.upsertInitialSpan?.(span)
|
|
242
|
-
.catch((err) => {
|
|
243
|
-
logger_js_1.logger.error("upsertInitialSpan error", err?.message || err);
|
|
244
|
-
});
|
|
245
240
|
span.end();
|
|
246
241
|
break;
|
|
247
242
|
}
|
|
248
243
|
case "agentFailed": {
|
|
249
244
|
const { error } = args[0];
|
|
250
245
|
span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: error.message });
|
|
251
|
-
await this.observer?.traceExporter
|
|
252
|
-
?.upsertInitialSpan?.(span)
|
|
253
|
-
.catch((err) => {
|
|
254
|
-
logger_js_1.logger.error("upsertInitialSpan error", err?.message || err);
|
|
255
|
-
});
|
|
256
246
|
span.end();
|
|
257
247
|
break;
|
|
258
248
|
}
|
package/lib/cjs/loader/index.js
CHANGED
|
@@ -12,6 +12,7 @@ const ai_agent_js_1 = require("../agents/ai-agent.js");
|
|
|
12
12
|
const mcp_agent_js_1 = require("../agents/mcp-agent.js");
|
|
13
13
|
const team_agent_js_1 = require("../agents/team-agent.js");
|
|
14
14
|
const transform_agent_js_1 = require("../agents/transform-agent.js");
|
|
15
|
+
const prompt_builder_js_1 = require("../prompt/prompt-builder.js");
|
|
15
16
|
const type_utils_js_1 = require("../utils/type-utils.js");
|
|
16
17
|
const agent_js_js_1 = require("./agent-js.js");
|
|
17
18
|
const agent_yaml_js_1 = require("./agent-yaml.js");
|
|
@@ -61,6 +62,8 @@ async function parseAgent(path, agent, options) {
|
|
|
61
62
|
case "ai": {
|
|
62
63
|
return ai_agent_js_1.AIAgent.from({
|
|
63
64
|
...agent,
|
|
65
|
+
instructions: agent.instructions &&
|
|
66
|
+
prompt_builder_js_1.PromptBuilder.from(agent.instructions, { workingDir: index_js_1.nodejs.path.dirname(path) }),
|
|
64
67
|
memory,
|
|
65
68
|
skills,
|
|
66
69
|
});
|
|
@@ -5,6 +5,7 @@ import type { ChatModel, ChatModelInput } from "../agents/chat-model.js";
|
|
|
5
5
|
import { ChatMessagesTemplate } from "./template.js";
|
|
6
6
|
export interface PromptBuilderOptions {
|
|
7
7
|
instructions?: string | ChatMessagesTemplate;
|
|
8
|
+
workingDir?: string;
|
|
8
9
|
}
|
|
9
10
|
export interface PromptBuildOptions extends Partial<Pick<AgentInvokeOptions, "context">> {
|
|
10
11
|
agent?: AIAgent;
|
|
@@ -15,11 +16,14 @@ export interface PromptBuildOptions extends Partial<Pick<AgentInvokeOptions, "co
|
|
|
15
16
|
export declare class PromptBuilder {
|
|
16
17
|
static from(instructions: string | {
|
|
17
18
|
path: string;
|
|
18
|
-
} | GetPromptResult
|
|
19
|
+
} | GetPromptResult, { workingDir }?: {
|
|
20
|
+
workingDir?: string;
|
|
21
|
+
}): PromptBuilder;
|
|
19
22
|
private static fromFile;
|
|
20
23
|
private static fromMCPPromptResult;
|
|
21
24
|
constructor(options?: PromptBuilderOptions);
|
|
22
25
|
instructions?: string | ChatMessagesTemplate;
|
|
26
|
+
workingDir?: string;
|
|
23
27
|
build(options: PromptBuildOptions): Promise<ChatModelInput & {
|
|
24
28
|
toolAgents?: Agent[];
|
|
25
29
|
}>;
|
|
@@ -12,18 +12,18 @@ const memory_message_template_js_1 = require("./prompts/memory-message-template.
|
|
|
12
12
|
const structured_stream_instructions_js_1 = require("./prompts/structured-stream-instructions.js");
|
|
13
13
|
const template_js_1 = require("./template.js");
|
|
14
14
|
class PromptBuilder {
|
|
15
|
-
static from(instructions) {
|
|
15
|
+
static from(instructions, { workingDir } = {}) {
|
|
16
16
|
if (typeof instructions === "string")
|
|
17
|
-
return new PromptBuilder({ instructions });
|
|
17
|
+
return new PromptBuilder({ instructions, workingDir: workingDir });
|
|
18
18
|
if (isFromPromptResult(instructions))
|
|
19
19
|
return PromptBuilder.fromMCPPromptResult(instructions);
|
|
20
20
|
if (isFromPath(instructions))
|
|
21
|
-
return PromptBuilder.fromFile(instructions.path);
|
|
21
|
+
return PromptBuilder.fromFile(instructions.path, { workingDir });
|
|
22
22
|
throw new Error(`Invalid instructions ${instructions}`);
|
|
23
23
|
}
|
|
24
|
-
static fromFile(path) {
|
|
24
|
+
static fromFile(path, { workingDir }) {
|
|
25
25
|
const text = index_js_1.nodejs.fsSync.readFileSync(path, "utf-8");
|
|
26
|
-
return PromptBuilder.from(text);
|
|
26
|
+
return PromptBuilder.from(text, { workingDir: workingDir || index_js_1.nodejs.path.dirname(path) });
|
|
27
27
|
}
|
|
28
28
|
static fromMCPPromptResult(result) {
|
|
29
29
|
return new PromptBuilder({
|
|
@@ -55,8 +55,10 @@ class PromptBuilder {
|
|
|
55
55
|
}
|
|
56
56
|
constructor(options) {
|
|
57
57
|
this.instructions = options?.instructions;
|
|
58
|
+
this.workingDir = options?.workingDir;
|
|
58
59
|
}
|
|
59
60
|
instructions;
|
|
61
|
+
workingDir;
|
|
60
62
|
async build(options) {
|
|
61
63
|
return {
|
|
62
64
|
messages: await this.buildMessages(options),
|
|
@@ -70,9 +72,9 @@ class PromptBuilder {
|
|
|
70
72
|
const { input } = options;
|
|
71
73
|
const inputKey = options.agent?.inputKey;
|
|
72
74
|
const message = inputKey && typeof input?.[inputKey] === "string" ? input[inputKey] : undefined;
|
|
73
|
-
const messages = (typeof this.instructions === "string"
|
|
75
|
+
const messages = (await (typeof this.instructions === "string"
|
|
74
76
|
? template_js_1.ChatMessagesTemplate.from([template_js_1.SystemMessageTemplate.from(this.instructions)])
|
|
75
|
-
: this.instructions)?.format(options.input) ?? [];
|
|
77
|
+
: this.instructions)?.format(options.input, { workingDir: this.workingDir })) ?? [];
|
|
76
78
|
const memories = [];
|
|
77
79
|
if (options.agent && options.context) {
|
|
78
80
|
memories.push(...(await options.agent.retrieveMemories({ search: message }, { context: options.context })));
|
|
@@ -81,7 +83,7 @@ class PromptBuilder {
|
|
|
81
83
|
memories.push(...options.context.memories);
|
|
82
84
|
}
|
|
83
85
|
if (memories.length)
|
|
84
|
-
messages.push(...this.convertMemoriesToMessages(memories, options));
|
|
86
|
+
messages.push(...(await this.convertMemoriesToMessages(memories, options)));
|
|
85
87
|
// if the agent is using structured stream mode, add the instructions
|
|
86
88
|
const { structuredStreamMode, outputSchema } = options.agent || {};
|
|
87
89
|
if (structuredStreamMode && outputSchema) {
|
|
@@ -102,7 +104,7 @@ class PromptBuilder {
|
|
|
102
104
|
}
|
|
103
105
|
return messages;
|
|
104
106
|
}
|
|
105
|
-
convertMemoriesToMessages(memories, options) {
|
|
107
|
+
async convertMemoriesToMessages(memories, options) {
|
|
106
108
|
const messages = [];
|
|
107
109
|
const other = [];
|
|
108
110
|
const stringOrStringify = (value) => typeof value === "string" ? value : (0, yaml_1.stringify)(value);
|
|
@@ -117,7 +119,7 @@ class PromptBuilder {
|
|
|
117
119
|
if (other.length) {
|
|
118
120
|
messages.unshift({
|
|
119
121
|
role: "system",
|
|
120
|
-
content: template_js_1.PromptTemplate.from(options.agent?.memoryPromptTemplate || memory_message_template_js_1.MEMORY_MESSAGE_TEMPLATE).format({ memories: (0, yaml_1.stringify)(other) }),
|
|
122
|
+
content: await template_js_1.PromptTemplate.from(options.agent?.memoryPromptTemplate || memory_message_template_js_1.MEMORY_MESSAGE_TEMPLATE).format({ memories: (0, yaml_1.stringify)(other) }),
|
|
121
123
|
});
|
|
122
124
|
}
|
|
123
125
|
return messages;
|
|
@@ -1,16 +1,30 @@
|
|
|
1
|
+
import nunjucks, { type Callback, type LoaderSource } from "nunjucks";
|
|
1
2
|
import type { ChatModelInputMessage, ChatModelInputMessageContent, ChatModelOutputToolCall } from "../agents/chat-model.js";
|
|
3
|
+
export interface FormatOptions {
|
|
4
|
+
workingDir?: string;
|
|
5
|
+
}
|
|
2
6
|
export declare class PromptTemplate {
|
|
3
7
|
template: string;
|
|
4
8
|
static from(template: string): PromptTemplate;
|
|
5
9
|
constructor(template: string);
|
|
6
|
-
format(variables?: Record<string, unknown
|
|
10
|
+
format(variables?: Record<string, unknown>, options?: FormatOptions): Promise<string>;
|
|
11
|
+
}
|
|
12
|
+
export declare class CustomLoader extends nunjucks.Loader {
|
|
13
|
+
options: {
|
|
14
|
+
workingDir: string;
|
|
15
|
+
};
|
|
16
|
+
constructor(options: {
|
|
17
|
+
workingDir: string;
|
|
18
|
+
});
|
|
19
|
+
async: boolean;
|
|
20
|
+
getSource(name: string, callback: Callback<Error, LoaderSource>): LoaderSource;
|
|
7
21
|
}
|
|
8
22
|
export declare class ChatMessageTemplate {
|
|
9
23
|
role: "system" | "user" | "agent" | "tool";
|
|
10
24
|
content?: ChatModelInputMessage["content"];
|
|
11
25
|
name?: string | undefined;
|
|
12
26
|
constructor(role: "system" | "user" | "agent" | "tool", content?: ChatModelInputMessage["content"], name?: string | undefined);
|
|
13
|
-
format(variables?: Record<string, unknown
|
|
27
|
+
format(variables?: Record<string, unknown>, options?: FormatOptions): Promise<ChatModelInputMessage>;
|
|
14
28
|
}
|
|
15
29
|
export declare class SystemMessageTemplate extends ChatMessageTemplate {
|
|
16
30
|
static from(content: string, name?: string): SystemMessageTemplate;
|
|
@@ -22,19 +36,19 @@ export declare class AgentMessageTemplate extends ChatMessageTemplate {
|
|
|
22
36
|
toolCalls?: ChatModelOutputToolCall[] | undefined;
|
|
23
37
|
static from(template?: ChatModelInputMessage["content"], toolCalls?: ChatModelOutputToolCall[], name?: string): AgentMessageTemplate;
|
|
24
38
|
constructor(content?: ChatModelInputMessage["content"], toolCalls?: ChatModelOutputToolCall[] | undefined, name?: string);
|
|
25
|
-
format(variables?: Record<string, unknown
|
|
39
|
+
format(variables?: Record<string, unknown>, options?: FormatOptions): Promise<{
|
|
26
40
|
toolCalls: ChatModelOutputToolCall[] | undefined;
|
|
27
41
|
role: import("../agents/chat-model.js").Role;
|
|
28
42
|
content?: ChatModelInputMessageContent;
|
|
29
43
|
toolCallId?: string;
|
|
30
44
|
name?: string;
|
|
31
|
-
}
|
|
45
|
+
}>;
|
|
32
46
|
}
|
|
33
47
|
export declare class ToolMessageTemplate extends ChatMessageTemplate {
|
|
34
48
|
toolCallId: string;
|
|
35
49
|
static from(content: object | string, toolCallId: string, name?: string): ToolMessageTemplate;
|
|
36
50
|
constructor(content: object | string, toolCallId: string, name?: string);
|
|
37
|
-
format(variables?: Record<string, unknown
|
|
51
|
+
format(variables?: Record<string, unknown>, options?: FormatOptions): Promise<{
|
|
38
52
|
toolCallId: string;
|
|
39
53
|
role: import("../agents/chat-model.js").Role;
|
|
40
54
|
content?: ChatModelInputMessageContent;
|
|
@@ -47,12 +61,12 @@ export declare class ToolMessageTemplate extends ChatMessageTemplate {
|
|
|
47
61
|
};
|
|
48
62
|
}[];
|
|
49
63
|
name?: string;
|
|
50
|
-
}
|
|
64
|
+
}>;
|
|
51
65
|
}
|
|
52
66
|
export declare class ChatMessagesTemplate {
|
|
53
67
|
messages: ChatMessageTemplate[];
|
|
54
68
|
static from(messages: ChatMessageTemplate[] | string): ChatMessagesTemplate;
|
|
55
69
|
constructor(messages: ChatMessageTemplate[]);
|
|
56
|
-
format(variables?: Record<string, unknown
|
|
70
|
+
format(variables?: Record<string, unknown>, options?: FormatOptions): Promise<ChatModelInputMessage[]>;
|
|
57
71
|
}
|
|
58
72
|
export declare function parseChatMessages(messages: unknown): ChatMessageTemplate[] | undefined;
|
|
@@ -3,10 +3,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.ChatMessagesTemplate = exports.ToolMessageTemplate = exports.AgentMessageTemplate = exports.UserMessageTemplate = exports.SystemMessageTemplate = exports.ChatMessageTemplate = exports.PromptTemplate = void 0;
|
|
6
|
+
exports.ChatMessagesTemplate = exports.ToolMessageTemplate = exports.AgentMessageTemplate = exports.UserMessageTemplate = exports.SystemMessageTemplate = exports.ChatMessageTemplate = exports.CustomLoader = exports.PromptTemplate = void 0;
|
|
7
7
|
exports.parseChatMessages = parseChatMessages;
|
|
8
|
-
const
|
|
8
|
+
const index_js_1 = require("@aigne/platform-helpers/nodejs/index.js");
|
|
9
|
+
const nunjucks_1 = __importDefault(require("nunjucks"));
|
|
9
10
|
const zod_1 = require("zod");
|
|
11
|
+
const type_utils_js_1 = require("../utils/type-utils.js");
|
|
12
|
+
nunjucks_1.default.runtime.suppressValue = (v) => {
|
|
13
|
+
if ((0, type_utils_js_1.isNil)(v))
|
|
14
|
+
return "";
|
|
15
|
+
return typeof v === "object" ? JSON.stringify(v) : v;
|
|
16
|
+
};
|
|
10
17
|
class PromptTemplate {
|
|
11
18
|
template;
|
|
12
19
|
static from(template) {
|
|
@@ -15,15 +22,46 @@ class PromptTemplate {
|
|
|
15
22
|
constructor(template) {
|
|
16
23
|
this.template = template;
|
|
17
24
|
}
|
|
18
|
-
format(variables) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
async format(variables = {}, options) {
|
|
26
|
+
let env = new nunjucks_1.default.Environment();
|
|
27
|
+
if (options?.workingDir) {
|
|
28
|
+
env = new nunjucks_1.default.Environment(new CustomLoader({ workingDir: options.workingDir }));
|
|
29
|
+
}
|
|
30
|
+
return new Promise((resolve, reject) => env.renderString(this.template, variables, (err, res) => {
|
|
31
|
+
if (err || !res) {
|
|
32
|
+
reject(err || new Error(`Failed to render template: ${this.template}`));
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
resolve(res);
|
|
36
|
+
}
|
|
37
|
+
}));
|
|
24
38
|
}
|
|
25
39
|
}
|
|
26
40
|
exports.PromptTemplate = PromptTemplate;
|
|
41
|
+
class CustomLoader extends nunjucks_1.default.Loader {
|
|
42
|
+
options;
|
|
43
|
+
constructor(options) {
|
|
44
|
+
super();
|
|
45
|
+
this.options = options;
|
|
46
|
+
}
|
|
47
|
+
async = true;
|
|
48
|
+
getSource(name, callback) {
|
|
49
|
+
let result = null;
|
|
50
|
+
index_js_1.nodejs.fs.readFile(index_js_1.nodejs.path.join(this.options.workingDir, name), "utf-8").then((content) => {
|
|
51
|
+
result = {
|
|
52
|
+
src: content,
|
|
53
|
+
path: name,
|
|
54
|
+
noCache: true,
|
|
55
|
+
};
|
|
56
|
+
callback(null, result);
|
|
57
|
+
}, (error) => {
|
|
58
|
+
callback(error, null);
|
|
59
|
+
});
|
|
60
|
+
// nunjucks expects return LoaderSource synchronously, but we handle it asynchronously.
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.CustomLoader = CustomLoader;
|
|
27
65
|
class ChatMessageTemplate {
|
|
28
66
|
role;
|
|
29
67
|
content;
|
|
@@ -33,17 +71,17 @@ class ChatMessageTemplate {
|
|
|
33
71
|
this.content = content;
|
|
34
72
|
this.name = name;
|
|
35
73
|
}
|
|
36
|
-
format(variables) {
|
|
74
|
+
async format(variables, options) {
|
|
37
75
|
let { content } = this;
|
|
38
76
|
if (Array.isArray(content)) {
|
|
39
|
-
content = content.map((i) => {
|
|
77
|
+
content = await Promise.all(content.map(async (i) => {
|
|
40
78
|
if (i.type === "text")
|
|
41
|
-
return { ...i, text: PromptTemplate.from(i.text).format(variables) };
|
|
79
|
+
return { ...i, text: await PromptTemplate.from(i.text).format(variables, options) };
|
|
42
80
|
return i;
|
|
43
|
-
});
|
|
81
|
+
}));
|
|
44
82
|
}
|
|
45
83
|
else if (typeof content === "string") {
|
|
46
|
-
content = PromptTemplate.from(content).format(variables);
|
|
84
|
+
content = await PromptTemplate.from(content).format(variables, options);
|
|
47
85
|
}
|
|
48
86
|
return {
|
|
49
87
|
role: this.role,
|
|
@@ -74,9 +112,9 @@ class AgentMessageTemplate extends ChatMessageTemplate {
|
|
|
74
112
|
super("agent", content, name);
|
|
75
113
|
this.toolCalls = toolCalls;
|
|
76
114
|
}
|
|
77
|
-
format(variables) {
|
|
115
|
+
async format(variables, options) {
|
|
78
116
|
return {
|
|
79
|
-
...super.format(variables),
|
|
117
|
+
...(await super.format(variables, options)),
|
|
80
118
|
toolCalls: this.toolCalls,
|
|
81
119
|
};
|
|
82
120
|
}
|
|
@@ -93,9 +131,9 @@ class ToolMessageTemplate extends ChatMessageTemplate {
|
|
|
93
131
|
: JSON.stringify(content, (_, value) => typeof value === "bigint" ? value.toString() : value), name);
|
|
94
132
|
this.toolCallId = toolCallId;
|
|
95
133
|
}
|
|
96
|
-
format(variables) {
|
|
134
|
+
async format(variables, options) {
|
|
97
135
|
return {
|
|
98
|
-
...super.format(variables),
|
|
136
|
+
...(await super.format(variables, options)),
|
|
99
137
|
toolCallId: this.toolCallId,
|
|
100
138
|
};
|
|
101
139
|
}
|
|
@@ -109,8 +147,8 @@ class ChatMessagesTemplate {
|
|
|
109
147
|
constructor(messages) {
|
|
110
148
|
this.messages = messages;
|
|
111
149
|
}
|
|
112
|
-
format(variables) {
|
|
113
|
-
return this.messages.map((message) => message.format(variables));
|
|
150
|
+
async format(variables, options) {
|
|
151
|
+
return Promise.all(this.messages.map((message) => message.format(variables, options)));
|
|
114
152
|
}
|
|
115
153
|
}
|
|
116
154
|
exports.ChatMessagesTemplate = ChatMessagesTemplate;
|
|
@@ -21,6 +21,9 @@ const agent_js_1 = require("../agents/agent.js");
|
|
|
21
21
|
const type_utils_js_1 = require("./type-utils.js");
|
|
22
22
|
require("./stream-polyfill.js");
|
|
23
23
|
function objectToAgentResponseStream(json) {
|
|
24
|
+
if (!(0, type_utils_js_1.isRecord)(json)) {
|
|
25
|
+
throw new Error(`expect to return a record type such as {result: ...}, but got (${typeof json}): ${json}`);
|
|
26
|
+
}
|
|
24
27
|
return new ReadableStream({
|
|
25
28
|
pull(controller) {
|
|
26
29
|
controller.enqueue({ delta: { json } });
|
|
@@ -5,6 +5,7 @@ import type { ChatModel, ChatModelInput } from "../agents/chat-model.js";
|
|
|
5
5
|
import { ChatMessagesTemplate } from "./template.js";
|
|
6
6
|
export interface PromptBuilderOptions {
|
|
7
7
|
instructions?: string | ChatMessagesTemplate;
|
|
8
|
+
workingDir?: string;
|
|
8
9
|
}
|
|
9
10
|
export interface PromptBuildOptions extends Partial<Pick<AgentInvokeOptions, "context">> {
|
|
10
11
|
agent?: AIAgent;
|
|
@@ -15,11 +16,14 @@ export interface PromptBuildOptions extends Partial<Pick<AgentInvokeOptions, "co
|
|
|
15
16
|
export declare class PromptBuilder {
|
|
16
17
|
static from(instructions: string | {
|
|
17
18
|
path: string;
|
|
18
|
-
} | GetPromptResult
|
|
19
|
+
} | GetPromptResult, { workingDir }?: {
|
|
20
|
+
workingDir?: string;
|
|
21
|
+
}): PromptBuilder;
|
|
19
22
|
private static fromFile;
|
|
20
23
|
private static fromMCPPromptResult;
|
|
21
24
|
constructor(options?: PromptBuilderOptions);
|
|
22
25
|
instructions?: string | ChatMessagesTemplate;
|
|
26
|
+
workingDir?: string;
|
|
23
27
|
build(options: PromptBuildOptions): Promise<ChatModelInput & {
|
|
24
28
|
toolAgents?: Agent[];
|
|
25
29
|
}>;
|
|
@@ -1,16 +1,30 @@
|
|
|
1
|
+
import nunjucks, { type Callback, type LoaderSource } from "nunjucks";
|
|
1
2
|
import type { ChatModelInputMessage, ChatModelInputMessageContent, ChatModelOutputToolCall } from "../agents/chat-model.js";
|
|
3
|
+
export interface FormatOptions {
|
|
4
|
+
workingDir?: string;
|
|
5
|
+
}
|
|
2
6
|
export declare class PromptTemplate {
|
|
3
7
|
template: string;
|
|
4
8
|
static from(template: string): PromptTemplate;
|
|
5
9
|
constructor(template: string);
|
|
6
|
-
format(variables?: Record<string, unknown
|
|
10
|
+
format(variables?: Record<string, unknown>, options?: FormatOptions): Promise<string>;
|
|
11
|
+
}
|
|
12
|
+
export declare class CustomLoader extends nunjucks.Loader {
|
|
13
|
+
options: {
|
|
14
|
+
workingDir: string;
|
|
15
|
+
};
|
|
16
|
+
constructor(options: {
|
|
17
|
+
workingDir: string;
|
|
18
|
+
});
|
|
19
|
+
async: boolean;
|
|
20
|
+
getSource(name: string, callback: Callback<Error, LoaderSource>): LoaderSource;
|
|
7
21
|
}
|
|
8
22
|
export declare class ChatMessageTemplate {
|
|
9
23
|
role: "system" | "user" | "agent" | "tool";
|
|
10
24
|
content?: ChatModelInputMessage["content"];
|
|
11
25
|
name?: string | undefined;
|
|
12
26
|
constructor(role: "system" | "user" | "agent" | "tool", content?: ChatModelInputMessage["content"], name?: string | undefined);
|
|
13
|
-
format(variables?: Record<string, unknown
|
|
27
|
+
format(variables?: Record<string, unknown>, options?: FormatOptions): Promise<ChatModelInputMessage>;
|
|
14
28
|
}
|
|
15
29
|
export declare class SystemMessageTemplate extends ChatMessageTemplate {
|
|
16
30
|
static from(content: string, name?: string): SystemMessageTemplate;
|
|
@@ -22,19 +36,19 @@ export declare class AgentMessageTemplate extends ChatMessageTemplate {
|
|
|
22
36
|
toolCalls?: ChatModelOutputToolCall[] | undefined;
|
|
23
37
|
static from(template?: ChatModelInputMessage["content"], toolCalls?: ChatModelOutputToolCall[], name?: string): AgentMessageTemplate;
|
|
24
38
|
constructor(content?: ChatModelInputMessage["content"], toolCalls?: ChatModelOutputToolCall[] | undefined, name?: string);
|
|
25
|
-
format(variables?: Record<string, unknown
|
|
39
|
+
format(variables?: Record<string, unknown>, options?: FormatOptions): Promise<{
|
|
26
40
|
toolCalls: ChatModelOutputToolCall[] | undefined;
|
|
27
41
|
role: import("../agents/chat-model.js").Role;
|
|
28
42
|
content?: ChatModelInputMessageContent;
|
|
29
43
|
toolCallId?: string;
|
|
30
44
|
name?: string;
|
|
31
|
-
}
|
|
45
|
+
}>;
|
|
32
46
|
}
|
|
33
47
|
export declare class ToolMessageTemplate extends ChatMessageTemplate {
|
|
34
48
|
toolCallId: string;
|
|
35
49
|
static from(content: object | string, toolCallId: string, name?: string): ToolMessageTemplate;
|
|
36
50
|
constructor(content: object | string, toolCallId: string, name?: string);
|
|
37
|
-
format(variables?: Record<string, unknown
|
|
51
|
+
format(variables?: Record<string, unknown>, options?: FormatOptions): Promise<{
|
|
38
52
|
toolCallId: string;
|
|
39
53
|
role: import("../agents/chat-model.js").Role;
|
|
40
54
|
content?: ChatModelInputMessageContent;
|
|
@@ -47,12 +61,12 @@ export declare class ToolMessageTemplate extends ChatMessageTemplate {
|
|
|
47
61
|
};
|
|
48
62
|
}[];
|
|
49
63
|
name?: string;
|
|
50
|
-
}
|
|
64
|
+
}>;
|
|
51
65
|
}
|
|
52
66
|
export declare class ChatMessagesTemplate {
|
|
53
67
|
messages: ChatMessageTemplate[];
|
|
54
68
|
static from(messages: ChatMessageTemplate[] | string): ChatMessagesTemplate;
|
|
55
69
|
constructor(messages: ChatMessageTemplate[]);
|
|
56
|
-
format(variables?: Record<string, unknown
|
|
70
|
+
format(variables?: Record<string, unknown>, options?: FormatOptions): Promise<ChatModelInputMessage[]>;
|
|
57
71
|
}
|
|
58
72
|
export declare function parseChatMessages(messages: unknown): ChatMessageTemplate[] | undefined;
|
package/lib/esm/agents/agent.js
CHANGED
|
@@ -2,7 +2,7 @@ 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, } from "../utils/type-utils.js";
|
|
5
|
+
import { checkArguments, createAccessorArray, flat, isEmpty, isRecord, } from "../utils/type-utils.js";
|
|
6
6
|
import { replaceTransferAgentToName, transferToAgentOutput, } from "./types.js";
|
|
7
7
|
export * from "./types.js";
|
|
8
8
|
export const agentOptionsSchema = z.object({
|
|
@@ -349,6 +349,9 @@ export class Agent {
|
|
|
349
349
|
*/
|
|
350
350
|
async processAgentOutput(input, output, options) {
|
|
351
351
|
const { context } = options;
|
|
352
|
+
if (!isRecord(output)) {
|
|
353
|
+
throw new Error(`expect to return a record type such as {result: ...}, but got (${typeof output}): ${output}`);
|
|
354
|
+
}
|
|
352
355
|
const parsedOutput = checkArguments(`Agent ${this.name} output`, this.outputSchema, output);
|
|
353
356
|
const finalOutput = this.includeInputInOutput ? { ...input, ...parsedOutput } : parsedOutput;
|
|
354
357
|
await this.postprocess(input, finalOutput, options);
|
|
@@ -283,7 +283,7 @@ export class AIAgent extends Agent {
|
|
|
283
283
|
}
|
|
284
284
|
// Continue LLM function calling loop if any tools were executed
|
|
285
285
|
if (executedToolCalls.length) {
|
|
286
|
-
toolCallMessages.push(AgentMessageTemplate.from(undefined, executedToolCalls.map(({ call }) => call)).format(), ...executedToolCalls.map(({ call, output }) => ToolMessageTemplate.from(output, call.id).format()));
|
|
286
|
+
toolCallMessages.push(await AgentMessageTemplate.from(undefined, executedToolCalls.map(({ call }) => call)).format(), ...(await Promise.all(executedToolCalls.map(({ call, output }) => ToolMessageTemplate.from(output, call.id).format()))));
|
|
287
287
|
continue;
|
|
288
288
|
}
|
|
289
289
|
}
|
package/lib/esm/aigne/context.js
CHANGED
|
@@ -231,22 +231,12 @@ export class AIGNEContext {
|
|
|
231
231
|
span.setAttribute("output", JSON.stringify({}));
|
|
232
232
|
}
|
|
233
233
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
234
|
-
await this.observer?.traceExporter
|
|
235
|
-
?.upsertInitialSpan?.(span)
|
|
236
|
-
.catch((err) => {
|
|
237
|
-
logger.error("upsertInitialSpan error", err?.message || err);
|
|
238
|
-
});
|
|
239
234
|
span.end();
|
|
240
235
|
break;
|
|
241
236
|
}
|
|
242
237
|
case "agentFailed": {
|
|
243
238
|
const { error } = args[0];
|
|
244
239
|
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
|
|
245
|
-
await this.observer?.traceExporter
|
|
246
|
-
?.upsertInitialSpan?.(span)
|
|
247
|
-
.catch((err) => {
|
|
248
|
-
logger.error("upsertInitialSpan error", err?.message || err);
|
|
249
|
-
});
|
|
250
240
|
span.end();
|
|
251
241
|
break;
|
|
252
242
|
}
|
package/lib/esm/loader/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { AIAgent } from "../agents/ai-agent.js";
|
|
|
6
6
|
import { MCPAgent } from "../agents/mcp-agent.js";
|
|
7
7
|
import { TeamAgent } from "../agents/team-agent.js";
|
|
8
8
|
import { TransformAgent } from "../agents/transform-agent.js";
|
|
9
|
+
import { PromptBuilder } from "../prompt/prompt-builder.js";
|
|
9
10
|
import { tryOrThrow } from "../utils/type-utils.js";
|
|
10
11
|
import { loadAgentFromJsFile } from "./agent-js.js";
|
|
11
12
|
import { loadAgentFromYamlFile } from "./agent-yaml.js";
|
|
@@ -55,6 +56,8 @@ async function parseAgent(path, agent, options) {
|
|
|
55
56
|
case "ai": {
|
|
56
57
|
return AIAgent.from({
|
|
57
58
|
...agent,
|
|
59
|
+
instructions: agent.instructions &&
|
|
60
|
+
PromptBuilder.from(agent.instructions, { workingDir: nodejs.path.dirname(path) }),
|
|
58
61
|
memory,
|
|
59
62
|
skills,
|
|
60
63
|
});
|
|
@@ -5,6 +5,7 @@ import type { ChatModel, ChatModelInput } from "../agents/chat-model.js";
|
|
|
5
5
|
import { ChatMessagesTemplate } from "./template.js";
|
|
6
6
|
export interface PromptBuilderOptions {
|
|
7
7
|
instructions?: string | ChatMessagesTemplate;
|
|
8
|
+
workingDir?: string;
|
|
8
9
|
}
|
|
9
10
|
export interface PromptBuildOptions extends Partial<Pick<AgentInvokeOptions, "context">> {
|
|
10
11
|
agent?: AIAgent;
|
|
@@ -15,11 +16,14 @@ export interface PromptBuildOptions extends Partial<Pick<AgentInvokeOptions, "co
|
|
|
15
16
|
export declare class PromptBuilder {
|
|
16
17
|
static from(instructions: string | {
|
|
17
18
|
path: string;
|
|
18
|
-
} | GetPromptResult
|
|
19
|
+
} | GetPromptResult, { workingDir }?: {
|
|
20
|
+
workingDir?: string;
|
|
21
|
+
}): PromptBuilder;
|
|
19
22
|
private static fromFile;
|
|
20
23
|
private static fromMCPPromptResult;
|
|
21
24
|
constructor(options?: PromptBuilderOptions);
|
|
22
25
|
instructions?: string | ChatMessagesTemplate;
|
|
26
|
+
workingDir?: string;
|
|
23
27
|
build(options: PromptBuildOptions): Promise<ChatModelInput & {
|
|
24
28
|
toolAgents?: Agent[];
|
|
25
29
|
}>;
|
|
@@ -9,18 +9,18 @@ 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";
|
|
11
11
|
export class PromptBuilder {
|
|
12
|
-
static from(instructions) {
|
|
12
|
+
static from(instructions, { workingDir } = {}) {
|
|
13
13
|
if (typeof instructions === "string")
|
|
14
|
-
return new PromptBuilder({ instructions });
|
|
14
|
+
return new PromptBuilder({ instructions, workingDir: workingDir });
|
|
15
15
|
if (isFromPromptResult(instructions))
|
|
16
16
|
return PromptBuilder.fromMCPPromptResult(instructions);
|
|
17
17
|
if (isFromPath(instructions))
|
|
18
|
-
return PromptBuilder.fromFile(instructions.path);
|
|
18
|
+
return PromptBuilder.fromFile(instructions.path, { workingDir });
|
|
19
19
|
throw new Error(`Invalid instructions ${instructions}`);
|
|
20
20
|
}
|
|
21
|
-
static fromFile(path) {
|
|
21
|
+
static fromFile(path, { workingDir }) {
|
|
22
22
|
const text = nodejs.fsSync.readFileSync(path, "utf-8");
|
|
23
|
-
return PromptBuilder.from(text);
|
|
23
|
+
return PromptBuilder.from(text, { workingDir: workingDir || nodejs.path.dirname(path) });
|
|
24
24
|
}
|
|
25
25
|
static fromMCPPromptResult(result) {
|
|
26
26
|
return new PromptBuilder({
|
|
@@ -52,8 +52,10 @@ export class PromptBuilder {
|
|
|
52
52
|
}
|
|
53
53
|
constructor(options) {
|
|
54
54
|
this.instructions = options?.instructions;
|
|
55
|
+
this.workingDir = options?.workingDir;
|
|
55
56
|
}
|
|
56
57
|
instructions;
|
|
58
|
+
workingDir;
|
|
57
59
|
async build(options) {
|
|
58
60
|
return {
|
|
59
61
|
messages: await this.buildMessages(options),
|
|
@@ -67,9 +69,9 @@ export class PromptBuilder {
|
|
|
67
69
|
const { input } = options;
|
|
68
70
|
const inputKey = options.agent?.inputKey;
|
|
69
71
|
const message = inputKey && typeof input?.[inputKey] === "string" ? input[inputKey] : undefined;
|
|
70
|
-
const messages = (typeof this.instructions === "string"
|
|
72
|
+
const messages = (await (typeof this.instructions === "string"
|
|
71
73
|
? ChatMessagesTemplate.from([SystemMessageTemplate.from(this.instructions)])
|
|
72
|
-
: this.instructions)?.format(options.input) ?? [];
|
|
74
|
+
: this.instructions)?.format(options.input, { workingDir: this.workingDir })) ?? [];
|
|
73
75
|
const memories = [];
|
|
74
76
|
if (options.agent && options.context) {
|
|
75
77
|
memories.push(...(await options.agent.retrieveMemories({ search: message }, { context: options.context })));
|
|
@@ -78,7 +80,7 @@ export class PromptBuilder {
|
|
|
78
80
|
memories.push(...options.context.memories);
|
|
79
81
|
}
|
|
80
82
|
if (memories.length)
|
|
81
|
-
messages.push(...this.convertMemoriesToMessages(memories, options));
|
|
83
|
+
messages.push(...(await this.convertMemoriesToMessages(memories, options)));
|
|
82
84
|
// if the agent is using structured stream mode, add the instructions
|
|
83
85
|
const { structuredStreamMode, outputSchema } = options.agent || {};
|
|
84
86
|
if (structuredStreamMode && outputSchema) {
|
|
@@ -99,7 +101,7 @@ export class PromptBuilder {
|
|
|
99
101
|
}
|
|
100
102
|
return messages;
|
|
101
103
|
}
|
|
102
|
-
convertMemoriesToMessages(memories, options) {
|
|
104
|
+
async convertMemoriesToMessages(memories, options) {
|
|
103
105
|
const messages = [];
|
|
104
106
|
const other = [];
|
|
105
107
|
const stringOrStringify = (value) => typeof value === "string" ? value : stringify(value);
|
|
@@ -114,7 +116,7 @@ export class PromptBuilder {
|
|
|
114
116
|
if (other.length) {
|
|
115
117
|
messages.unshift({
|
|
116
118
|
role: "system",
|
|
117
|
-
content: PromptTemplate.from(options.agent?.memoryPromptTemplate || MEMORY_MESSAGE_TEMPLATE).format({ memories: stringify(other) }),
|
|
119
|
+
content: await PromptTemplate.from(options.agent?.memoryPromptTemplate || MEMORY_MESSAGE_TEMPLATE).format({ memories: stringify(other) }),
|
|
118
120
|
});
|
|
119
121
|
}
|
|
120
122
|
return messages;
|
|
@@ -1,16 +1,30 @@
|
|
|
1
|
+
import nunjucks, { type Callback, type LoaderSource } from "nunjucks";
|
|
1
2
|
import type { ChatModelInputMessage, ChatModelInputMessageContent, ChatModelOutputToolCall } from "../agents/chat-model.js";
|
|
3
|
+
export interface FormatOptions {
|
|
4
|
+
workingDir?: string;
|
|
5
|
+
}
|
|
2
6
|
export declare class PromptTemplate {
|
|
3
7
|
template: string;
|
|
4
8
|
static from(template: string): PromptTemplate;
|
|
5
9
|
constructor(template: string);
|
|
6
|
-
format(variables?: Record<string, unknown
|
|
10
|
+
format(variables?: Record<string, unknown>, options?: FormatOptions): Promise<string>;
|
|
11
|
+
}
|
|
12
|
+
export declare class CustomLoader extends nunjucks.Loader {
|
|
13
|
+
options: {
|
|
14
|
+
workingDir: string;
|
|
15
|
+
};
|
|
16
|
+
constructor(options: {
|
|
17
|
+
workingDir: string;
|
|
18
|
+
});
|
|
19
|
+
async: boolean;
|
|
20
|
+
getSource(name: string, callback: Callback<Error, LoaderSource>): LoaderSource;
|
|
7
21
|
}
|
|
8
22
|
export declare class ChatMessageTemplate {
|
|
9
23
|
role: "system" | "user" | "agent" | "tool";
|
|
10
24
|
content?: ChatModelInputMessage["content"];
|
|
11
25
|
name?: string | undefined;
|
|
12
26
|
constructor(role: "system" | "user" | "agent" | "tool", content?: ChatModelInputMessage["content"], name?: string | undefined);
|
|
13
|
-
format(variables?: Record<string, unknown
|
|
27
|
+
format(variables?: Record<string, unknown>, options?: FormatOptions): Promise<ChatModelInputMessage>;
|
|
14
28
|
}
|
|
15
29
|
export declare class SystemMessageTemplate extends ChatMessageTemplate {
|
|
16
30
|
static from(content: string, name?: string): SystemMessageTemplate;
|
|
@@ -22,19 +36,19 @@ export declare class AgentMessageTemplate extends ChatMessageTemplate {
|
|
|
22
36
|
toolCalls?: ChatModelOutputToolCall[] | undefined;
|
|
23
37
|
static from(template?: ChatModelInputMessage["content"], toolCalls?: ChatModelOutputToolCall[], name?: string): AgentMessageTemplate;
|
|
24
38
|
constructor(content?: ChatModelInputMessage["content"], toolCalls?: ChatModelOutputToolCall[] | undefined, name?: string);
|
|
25
|
-
format(variables?: Record<string, unknown
|
|
39
|
+
format(variables?: Record<string, unknown>, options?: FormatOptions): Promise<{
|
|
26
40
|
toolCalls: ChatModelOutputToolCall[] | undefined;
|
|
27
41
|
role: import("../agents/chat-model.js").Role;
|
|
28
42
|
content?: ChatModelInputMessageContent;
|
|
29
43
|
toolCallId?: string;
|
|
30
44
|
name?: string;
|
|
31
|
-
}
|
|
45
|
+
}>;
|
|
32
46
|
}
|
|
33
47
|
export declare class ToolMessageTemplate extends ChatMessageTemplate {
|
|
34
48
|
toolCallId: string;
|
|
35
49
|
static from(content: object | string, toolCallId: string, name?: string): ToolMessageTemplate;
|
|
36
50
|
constructor(content: object | string, toolCallId: string, name?: string);
|
|
37
|
-
format(variables?: Record<string, unknown
|
|
51
|
+
format(variables?: Record<string, unknown>, options?: FormatOptions): Promise<{
|
|
38
52
|
toolCallId: string;
|
|
39
53
|
role: import("../agents/chat-model.js").Role;
|
|
40
54
|
content?: ChatModelInputMessageContent;
|
|
@@ -47,12 +61,12 @@ export declare class ToolMessageTemplate extends ChatMessageTemplate {
|
|
|
47
61
|
};
|
|
48
62
|
}[];
|
|
49
63
|
name?: string;
|
|
50
|
-
}
|
|
64
|
+
}>;
|
|
51
65
|
}
|
|
52
66
|
export declare class ChatMessagesTemplate {
|
|
53
67
|
messages: ChatMessageTemplate[];
|
|
54
68
|
static from(messages: ChatMessageTemplate[] | string): ChatMessagesTemplate;
|
|
55
69
|
constructor(messages: ChatMessageTemplate[]);
|
|
56
|
-
format(variables?: Record<string, unknown
|
|
70
|
+
format(variables?: Record<string, unknown>, options?: FormatOptions): Promise<ChatModelInputMessage[]>;
|
|
57
71
|
}
|
|
58
72
|
export declare function parseChatMessages(messages: unknown): ChatMessageTemplate[] | undefined;
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { nodejs } from "@aigne/platform-helpers/nodejs/index.js";
|
|
2
|
+
import nunjucks from "nunjucks";
|
|
2
3
|
import { z } from "zod";
|
|
4
|
+
import { isNil } from "../utils/type-utils.js";
|
|
5
|
+
nunjucks.runtime.suppressValue = (v) => {
|
|
6
|
+
if (isNil(v))
|
|
7
|
+
return "";
|
|
8
|
+
return typeof v === "object" ? JSON.stringify(v) : v;
|
|
9
|
+
};
|
|
3
10
|
export class PromptTemplate {
|
|
4
11
|
template;
|
|
5
12
|
static from(template) {
|
|
@@ -8,12 +15,42 @@ export class PromptTemplate {
|
|
|
8
15
|
constructor(template) {
|
|
9
16
|
this.template = template;
|
|
10
17
|
}
|
|
11
|
-
format(variables) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
async format(variables = {}, options) {
|
|
19
|
+
let env = new nunjucks.Environment();
|
|
20
|
+
if (options?.workingDir) {
|
|
21
|
+
env = new nunjucks.Environment(new CustomLoader({ workingDir: options.workingDir }));
|
|
22
|
+
}
|
|
23
|
+
return new Promise((resolve, reject) => env.renderString(this.template, variables, (err, res) => {
|
|
24
|
+
if (err || !res) {
|
|
25
|
+
reject(err || new Error(`Failed to render template: ${this.template}`));
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
resolve(res);
|
|
29
|
+
}
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export class CustomLoader extends nunjucks.Loader {
|
|
34
|
+
options;
|
|
35
|
+
constructor(options) {
|
|
36
|
+
super();
|
|
37
|
+
this.options = options;
|
|
38
|
+
}
|
|
39
|
+
async = true;
|
|
40
|
+
getSource(name, callback) {
|
|
41
|
+
let result = null;
|
|
42
|
+
nodejs.fs.readFile(nodejs.path.join(this.options.workingDir, name), "utf-8").then((content) => {
|
|
43
|
+
result = {
|
|
44
|
+
src: content,
|
|
45
|
+
path: name,
|
|
46
|
+
noCache: true,
|
|
47
|
+
};
|
|
48
|
+
callback(null, result);
|
|
49
|
+
}, (error) => {
|
|
50
|
+
callback(error, null);
|
|
16
51
|
});
|
|
52
|
+
// nunjucks expects return LoaderSource synchronously, but we handle it asynchronously.
|
|
53
|
+
return result;
|
|
17
54
|
}
|
|
18
55
|
}
|
|
19
56
|
export class ChatMessageTemplate {
|
|
@@ -25,17 +62,17 @@ export class ChatMessageTemplate {
|
|
|
25
62
|
this.content = content;
|
|
26
63
|
this.name = name;
|
|
27
64
|
}
|
|
28
|
-
format(variables) {
|
|
65
|
+
async format(variables, options) {
|
|
29
66
|
let { content } = this;
|
|
30
67
|
if (Array.isArray(content)) {
|
|
31
|
-
content = content.map((i) => {
|
|
68
|
+
content = await Promise.all(content.map(async (i) => {
|
|
32
69
|
if (i.type === "text")
|
|
33
|
-
return { ...i, text: PromptTemplate.from(i.text).format(variables) };
|
|
70
|
+
return { ...i, text: await PromptTemplate.from(i.text).format(variables, options) };
|
|
34
71
|
return i;
|
|
35
|
-
});
|
|
72
|
+
}));
|
|
36
73
|
}
|
|
37
74
|
else if (typeof content === "string") {
|
|
38
|
-
content = PromptTemplate.from(content).format(variables);
|
|
75
|
+
content = await PromptTemplate.from(content).format(variables, options);
|
|
39
76
|
}
|
|
40
77
|
return {
|
|
41
78
|
role: this.role,
|
|
@@ -63,9 +100,9 @@ export class AgentMessageTemplate extends ChatMessageTemplate {
|
|
|
63
100
|
super("agent", content, name);
|
|
64
101
|
this.toolCalls = toolCalls;
|
|
65
102
|
}
|
|
66
|
-
format(variables) {
|
|
103
|
+
async format(variables, options) {
|
|
67
104
|
return {
|
|
68
|
-
...super.format(variables),
|
|
105
|
+
...(await super.format(variables, options)),
|
|
69
106
|
toolCalls: this.toolCalls,
|
|
70
107
|
};
|
|
71
108
|
}
|
|
@@ -81,9 +118,9 @@ export class ToolMessageTemplate extends ChatMessageTemplate {
|
|
|
81
118
|
: JSON.stringify(content, (_, value) => typeof value === "bigint" ? value.toString() : value), name);
|
|
82
119
|
this.toolCallId = toolCallId;
|
|
83
120
|
}
|
|
84
|
-
format(variables) {
|
|
121
|
+
async format(variables, options) {
|
|
85
122
|
return {
|
|
86
|
-
...super.format(variables),
|
|
123
|
+
...(await super.format(variables, options)),
|
|
87
124
|
toolCallId: this.toolCallId,
|
|
88
125
|
};
|
|
89
126
|
}
|
|
@@ -96,8 +133,8 @@ export class ChatMessagesTemplate {
|
|
|
96
133
|
constructor(messages) {
|
|
97
134
|
this.messages = messages;
|
|
98
135
|
}
|
|
99
|
-
format(variables) {
|
|
100
|
-
return this.messages.map((message) => message.format(variables));
|
|
136
|
+
async format(variables, options) {
|
|
137
|
+
return Promise.all(this.messages.map((message) => message.format(variables, options)));
|
|
101
138
|
}
|
|
102
139
|
}
|
|
103
140
|
const systemChatMessageSchema = z.object({
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import equal from "fast-deep-equal";
|
|
2
2
|
import { isAgentResponseDelta, isEmptyChunk, } from "../agents/agent.js";
|
|
3
|
-
import { omitBy } from "./type-utils.js";
|
|
3
|
+
import { isRecord, omitBy } from "./type-utils.js";
|
|
4
4
|
import "./stream-polyfill.js";
|
|
5
5
|
export function objectToAgentResponseStream(json) {
|
|
6
|
+
if (!isRecord(json)) {
|
|
7
|
+
throw new Error(`expect to return a record type such as {result: ...}, but got (${typeof json}): ${json}`);
|
|
8
|
+
}
|
|
6
9
|
return new ReadableStream({
|
|
7
10
|
pull(controller) {
|
|
8
11
|
controller.enqueue({ delta: { json } });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.32.1",
|
|
4
4
|
"description": "AIGNE core library for building AI-powered applications",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
"jsonata": "^2.0.6",
|
|
75
75
|
"mustache": "^4.2.0",
|
|
76
76
|
"nanoid": "^5.1.5",
|
|
77
|
+
"nunjucks": "^3.2.4",
|
|
77
78
|
"p-retry": "^6.2.1",
|
|
78
79
|
"raw-body": "^3.0.0",
|
|
79
80
|
"strict-event-emitter": "^0.5.1",
|
|
@@ -82,7 +83,7 @@
|
|
|
82
83
|
"yaml": "^2.8.0",
|
|
83
84
|
"zod": "^3.25.67",
|
|
84
85
|
"zod-to-json-schema": "^3.24.6",
|
|
85
|
-
"@aigne/observability-api": "^0.
|
|
86
|
+
"@aigne/observability-api": "^0.7.0",
|
|
86
87
|
"@aigne/platform-helpers": "^0.3.0"
|
|
87
88
|
},
|
|
88
89
|
"devDependencies": {
|
|
@@ -92,6 +93,7 @@
|
|
|
92
93
|
"@types/express": "^5.0.3",
|
|
93
94
|
"@types/mustache": "^4.2.6",
|
|
94
95
|
"@types/node": "^24.0.10",
|
|
96
|
+
"@types/nunjucks": "^3.2.6",
|
|
95
97
|
"compression": "^1.8.0",
|
|
96
98
|
"detect-port": "^2.1.0",
|
|
97
99
|
"express": "^5.1.0",
|