@iqai/adk 0.2.4 → 0.3.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 +30 -0
- package/dist/index.d.mts +96 -60
- package/dist/index.d.ts +96 -60
- package/dist/index.js +544 -213
- package/dist/index.mjs +465 -134
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -30,98 +30,269 @@ import chalk from "chalk";
|
|
|
30
30
|
function isDebugEnabled() {
|
|
31
31
|
return process.env.NODE_ENV === "development" || process.env.ADK_DEBUG === "true";
|
|
32
32
|
}
|
|
33
|
-
var Logger;
|
|
33
|
+
var LOG_LEVELS, Logger;
|
|
34
34
|
var init_logger = __esm({
|
|
35
35
|
"src/logger/index.ts"() {
|
|
36
|
+
LOG_LEVELS = {
|
|
37
|
+
debug: { icon: "\u{1F41B}", color: chalk.blue, method: console.log },
|
|
38
|
+
info: { icon: "\u2139\uFE0F", color: chalk.cyan, method: console.debug },
|
|
39
|
+
warn: { icon: "\u{1F6A7}", color: chalk.yellow, method: console.warn },
|
|
40
|
+
error: { icon: "\u274C", color: chalk.red, method: console.error }
|
|
41
|
+
};
|
|
36
42
|
Logger = class {
|
|
37
43
|
name;
|
|
38
44
|
isDebugEnabled = isDebugEnabled();
|
|
39
45
|
constructor({ name }) {
|
|
40
46
|
this.name = name;
|
|
41
47
|
}
|
|
42
|
-
colorize(message) {
|
|
43
|
-
return chalk.blue(message);
|
|
44
|
-
}
|
|
45
48
|
debug(message, ...args) {
|
|
46
49
|
if (this.isDebugEnabled) {
|
|
47
|
-
|
|
48
|
-
console.log(
|
|
49
|
-
this.colorize(`[${time}] \u{1F41B} [${this.name}] ${message}`),
|
|
50
|
-
...args
|
|
51
|
-
);
|
|
50
|
+
this.log("debug", message, ...args);
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
53
|
info(message, ...args) {
|
|
55
|
-
|
|
56
|
-
console.debug(
|
|
57
|
-
this.colorize(`[${time}] \u2139\uFE0F [${this.name}] ${message}`),
|
|
58
|
-
...args
|
|
59
|
-
);
|
|
54
|
+
this.log("info", message, ...args);
|
|
60
55
|
}
|
|
61
56
|
warn(message, ...args) {
|
|
62
|
-
|
|
63
|
-
console.warn(
|
|
64
|
-
this.colorize(`[${time}] \u{1F6A7} [${this.name}] ${message}`),
|
|
65
|
-
...args
|
|
66
|
-
);
|
|
57
|
+
this.log("warn", message, ...args);
|
|
67
58
|
}
|
|
68
59
|
error(message, ...args) {
|
|
60
|
+
this.log("error", message, ...args);
|
|
61
|
+
}
|
|
62
|
+
log(level, message, ...args) {
|
|
63
|
+
const { icon, color, method } = LOG_LEVELS[level];
|
|
69
64
|
const time = (/* @__PURE__ */ new Date()).toLocaleTimeString();
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
65
|
+
const isProd = process.env.NODE_ENV === "production";
|
|
66
|
+
const forceBoxes = process.env.ADK_FORCE_BOXES === "true";
|
|
67
|
+
const { meta, otherArgs } = this.extractMeta(args);
|
|
68
|
+
const lines = this.formatArgs(otherArgs, level === "error");
|
|
69
|
+
if (meta.suggestion) lines.unshift(`\u2022 Suggestion: ${meta.suggestion}`);
|
|
70
|
+
if (meta.context && Object.keys(meta.context).length) {
|
|
71
|
+
const contextStr = Object.entries(meta.context).map(([k, v]) => `${k}=${this.stringify(v)}`).join(" ");
|
|
72
|
+
lines.unshift(`\u2022 Context: ${contextStr}`);
|
|
73
|
+
}
|
|
74
|
+
if (isProd && !forceBoxes) {
|
|
75
|
+
const header = `[${time}] ${icon} [${this.name}] ${message}`;
|
|
76
|
+
const output = lines.length ? [header, ...lines].join("\n") : header;
|
|
77
|
+
method(color(output));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (level === "warn" || level === "error") {
|
|
81
|
+
const box = this.formatBox({
|
|
82
|
+
title: `${icon} ${this.capitalize(level)} @ ${time} (${this.name})`,
|
|
83
|
+
description: message,
|
|
84
|
+
lines,
|
|
85
|
+
color
|
|
86
|
+
});
|
|
87
|
+
method(box);
|
|
88
|
+
} else {
|
|
89
|
+
const header = `[${time}] ${icon} [${this.name}] ${message}`;
|
|
90
|
+
const output = lines.length ? [header, ...lines].join("\n") : header;
|
|
91
|
+
method(color(output));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
extractMeta(args) {
|
|
95
|
+
const meta = {};
|
|
96
|
+
const otherArgs = [];
|
|
97
|
+
let metaFound = false;
|
|
98
|
+
for (const arg of args) {
|
|
99
|
+
if (!arg) continue;
|
|
100
|
+
if (!metaFound && typeof arg === "object" && !(arg instanceof Error) && ("suggestion" in arg || "context" in arg)) {
|
|
101
|
+
meta.suggestion = arg.suggestion;
|
|
102
|
+
meta.context = arg.context;
|
|
103
|
+
metaFound = true;
|
|
104
|
+
} else {
|
|
105
|
+
otherArgs.push(arg);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return { meta, otherArgs };
|
|
109
|
+
}
|
|
110
|
+
formatArgs(args, includeStack = false) {
|
|
111
|
+
const lines = [];
|
|
112
|
+
const maxFrames = Number(process.env.ADK_ERROR_STACK_FRAMES || 8);
|
|
113
|
+
for (const arg of args) {
|
|
114
|
+
if (!arg) continue;
|
|
115
|
+
if (arg instanceof Error) {
|
|
116
|
+
lines.push(`\u2022 ${arg.name}: ${arg.message}`);
|
|
117
|
+
if (includeStack && arg.stack) {
|
|
118
|
+
const frames = this.parseStackFrames(arg.stack, maxFrames);
|
|
119
|
+
if (frames.length) {
|
|
120
|
+
lines.push("\u2022 Stack:", ...frames);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
lines.push(`\u2022 ${this.stringify(arg)}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return lines;
|
|
128
|
+
}
|
|
129
|
+
parseStackFrames(stack, maxFrames) {
|
|
130
|
+
const frames = stack.split(/\n/).slice(1).map((f) => f.trim()).filter(Boolean).slice(0, maxFrames);
|
|
131
|
+
const result = frames.map((frame) => {
|
|
132
|
+
const cleaned = frame.replace(/^at\s+/, "").replace(process.cwd(), ".");
|
|
133
|
+
return ` \u21B3 ${cleaned}`;
|
|
134
|
+
});
|
|
135
|
+
const totalFrames = stack.split(/\n/).length - 1;
|
|
136
|
+
if (totalFrames > maxFrames) {
|
|
137
|
+
result.push(` \u21B3 \u2026 ${totalFrames - maxFrames} more frames`);
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
stringify(value) {
|
|
142
|
+
if (typeof value === "string") return value;
|
|
143
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
144
|
+
return String(value);
|
|
145
|
+
if (value === null || value === void 0) return String(value);
|
|
146
|
+
try {
|
|
147
|
+
return JSON.stringify(value);
|
|
148
|
+
} catch {
|
|
149
|
+
return String(value);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
capitalize(str) {
|
|
153
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
154
|
+
}
|
|
155
|
+
formatBox(params) {
|
|
156
|
+
const {
|
|
157
|
+
title,
|
|
158
|
+
description,
|
|
159
|
+
lines = [],
|
|
160
|
+
width = 60,
|
|
161
|
+
maxWidthPct = 0.9,
|
|
162
|
+
color = chalk.yellow,
|
|
163
|
+
pad = 1,
|
|
164
|
+
borderChar = "\u2500"
|
|
165
|
+
} = params;
|
|
166
|
+
const isProd = process.env.NODE_ENV === "production";
|
|
167
|
+
const forceBoxes = process.env.ADK_FORCE_BOXES === "true";
|
|
168
|
+
if (isProd && !forceBoxes) {
|
|
169
|
+
return [`${title}: ${description}`, ...lines].join("\n");
|
|
170
|
+
}
|
|
171
|
+
const termWidth = process.stdout.columns || 80;
|
|
172
|
+
const maxWidth = Math.floor(termWidth * maxWidthPct);
|
|
173
|
+
const contentWidth = Math.max(
|
|
174
|
+
width,
|
|
175
|
+
title.length + 2,
|
|
176
|
+
description.length,
|
|
177
|
+
...lines.map((l) => l.length)
|
|
73
178
|
);
|
|
179
|
+
const innerWidth = Math.min(contentWidth + pad * 2, maxWidth - 2);
|
|
180
|
+
const horizontal = borderChar.repeat(innerWidth + 2);
|
|
181
|
+
const top = `\u250C${horizontal}\u2510`;
|
|
182
|
+
const separator = `\u251C${horizontal}\u2524`;
|
|
183
|
+
const bottom = `\u2514${horizontal}\u2518`;
|
|
184
|
+
const padLine = (text) => {
|
|
185
|
+
const maxContent = innerWidth - pad * 2;
|
|
186
|
+
const truncated = text.length > maxContent ? `${text.slice(0, maxContent - 1)}\u2026` : text;
|
|
187
|
+
const padded = " ".repeat(pad) + truncated;
|
|
188
|
+
return padded + " ".repeat(innerWidth - padded.length);
|
|
189
|
+
};
|
|
190
|
+
const content = [
|
|
191
|
+
top,
|
|
192
|
+
`\u2502 ${padLine(title)} \u2502`,
|
|
193
|
+
separator,
|
|
194
|
+
`\u2502 ${padLine(description)} \u2502`,
|
|
195
|
+
...lines.map((line) => `\u2502 ${padLine(line)} \u2502`),
|
|
196
|
+
bottom
|
|
197
|
+
];
|
|
198
|
+
return `
|
|
199
|
+
${content.map((line) => color(line)).join("\n")}`;
|
|
74
200
|
}
|
|
75
201
|
/**
|
|
76
|
-
*
|
|
77
|
-
* Uses vertical layout for better readability and respects debug settings.
|
|
202
|
+
* Structured warning with code, suggestion, context.
|
|
78
203
|
*/
|
|
204
|
+
warnStructured(warning, opts = {}) {
|
|
205
|
+
const format = opts.format || process.env.ADK_WARN_FORMAT || "pretty";
|
|
206
|
+
const verbose = opts.verbose || process.env.ADK_AGENT_BUILDER_WARN === "verbose";
|
|
207
|
+
const timestamp = warning.timestamp || (/* @__PURE__ */ new Date()).toISOString();
|
|
208
|
+
const severity = warning.severity || "warn";
|
|
209
|
+
if (format === "json") {
|
|
210
|
+
this.warn(
|
|
211
|
+
JSON.stringify({
|
|
212
|
+
level: severity,
|
|
213
|
+
source: this.name,
|
|
214
|
+
timestamp,
|
|
215
|
+
...warning
|
|
216
|
+
})
|
|
217
|
+
);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const { icon } = LOG_LEVELS[severity] || LOG_LEVELS.warn;
|
|
221
|
+
const base = `${icon} ${warning.code} ${warning.message}`;
|
|
222
|
+
const parts = [base];
|
|
223
|
+
if (warning.suggestion) {
|
|
224
|
+
parts.push(` \u2022 Suggestion: ${warning.suggestion}`);
|
|
225
|
+
}
|
|
226
|
+
if (verbose && warning.context && Object.keys(warning.context).length) {
|
|
227
|
+
const contextStr = Object.entries(warning.context).map(([k, v]) => `${k}=${this.stringify(v)}`).join(" ");
|
|
228
|
+
parts.push(` \u2022 Context: ${contextStr}`);
|
|
229
|
+
}
|
|
230
|
+
if (format === "pretty") {
|
|
231
|
+
this.warn(parts.join("\n"));
|
|
232
|
+
} else {
|
|
233
|
+
const textParts = [`[${warning.code}] ${warning.message}`];
|
|
234
|
+
if (warning.suggestion) textParts.push(` -> ${warning.suggestion}`);
|
|
235
|
+
if (verbose && warning.context && Object.keys(warning.context).length) {
|
|
236
|
+
const contextStr = Object.entries(warning.context).map(([k, v]) => `${k}=${this.stringify(v)}`).join(" ");
|
|
237
|
+
textParts.push(` \u2022 Context: ${contextStr}`);
|
|
238
|
+
}
|
|
239
|
+
this.warn(textParts.join("\n"));
|
|
240
|
+
}
|
|
241
|
+
}
|
|
79
242
|
debugStructured(title, data) {
|
|
80
243
|
if (!this.isDebugEnabled) return;
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
console.log(this.colorize(`\u2502 ${title.padEnd(contentWidth)} \u2502`));
|
|
89
|
-
console.log(this.colorize(middleBorder));
|
|
90
|
-
Object.entries(data).forEach(([key, value]) => {
|
|
91
|
-
const formattedKey = key.padEnd(20);
|
|
92
|
-
const formattedValue = String(value);
|
|
93
|
-
const availableValueSpace = contentWidth - 20 - 2;
|
|
94
|
-
const truncatedValue = formattedValue.length > availableValueSpace ? `${formattedValue.substring(0, availableValueSpace - 3)}...` : formattedValue;
|
|
95
|
-
const content = `${formattedKey}: ${truncatedValue}`;
|
|
96
|
-
const paddedContent = content.padEnd(contentWidth);
|
|
97
|
-
console.log(this.colorize(`\u2502 ${paddedContent} \u2502`));
|
|
244
|
+
const time = (/* @__PURE__ */ new Date()).toLocaleTimeString();
|
|
245
|
+
const lines = this.objectToLines(data);
|
|
246
|
+
const box = this.formatBox({
|
|
247
|
+
title: `\u{1F41B} Debug @ ${time} (${this.name})`,
|
|
248
|
+
description: title,
|
|
249
|
+
lines,
|
|
250
|
+
color: chalk.blue
|
|
98
251
|
});
|
|
99
|
-
console.log(
|
|
252
|
+
console.log(box);
|
|
100
253
|
}
|
|
101
|
-
/**
|
|
102
|
-
* Logs array data in a compact, readable format.
|
|
103
|
-
*/
|
|
104
254
|
debugArray(title, items) {
|
|
105
255
|
if (!this.isDebugEnabled) return;
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
256
|
+
const time = (/* @__PURE__ */ new Date()).toLocaleTimeString();
|
|
257
|
+
const lines = this.arrayToLines(items);
|
|
258
|
+
const box = this.formatBox({
|
|
259
|
+
title: `\u{1F41B} Debug List @ ${time} (${this.name})`,
|
|
260
|
+
description: title,
|
|
261
|
+
lines,
|
|
262
|
+
color: chalk.blue,
|
|
263
|
+
width: 78,
|
|
264
|
+
maxWidthPct: 0.95
|
|
265
|
+
});
|
|
266
|
+
console.log(box);
|
|
267
|
+
}
|
|
268
|
+
objectToLines(obj) {
|
|
269
|
+
const entries = Object.entries(obj || {});
|
|
270
|
+
if (!entries.length) return ["(empty)"];
|
|
271
|
+
const keyWidth = Math.min(
|
|
272
|
+
30,
|
|
273
|
+
Math.max(6, ...entries.map(([k]) => k.length))
|
|
274
|
+
);
|
|
275
|
+
return entries.slice(0, 200).map(([k, v]) => {
|
|
276
|
+
const value = this.stringify(v);
|
|
277
|
+
const truncated = value.length > 140 ? `${value.slice(0, 139)}\u2026` : value;
|
|
278
|
+
return `${k.padEnd(keyWidth)}: ${truncated}`;
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
arrayToLines(items) {
|
|
282
|
+
if (!items.length) return ["(empty list)"];
|
|
283
|
+
const maxItems = 50;
|
|
284
|
+
const lines = items.slice(0, maxItems).map((obj, i) => {
|
|
285
|
+
const props = Object.entries(obj).map(([k, v]) => {
|
|
286
|
+
const value = this.stringify(v);
|
|
287
|
+
const truncated = value.length > 160 ? `${value.slice(0, 159)}\u2026` : value;
|
|
288
|
+
return `${k}=${truncated}`;
|
|
289
|
+
}).join(" \u2022 ");
|
|
290
|
+
return `[${i + 1}] ${props}`;
|
|
123
291
|
});
|
|
124
|
-
|
|
292
|
+
if (items.length > maxItems) {
|
|
293
|
+
lines.push(`\u2026 ${items.length - maxItems} more items omitted`);
|
|
294
|
+
}
|
|
295
|
+
return lines;
|
|
125
296
|
}
|
|
126
297
|
};
|
|
127
298
|
}
|
|
@@ -7111,6 +7282,7 @@ var AuthLlmRequestProcessor = class extends BaseLlmRequestProcessor {
|
|
|
7111
7282
|
var requestProcessor = new AuthLlmRequestProcessor();
|
|
7112
7283
|
|
|
7113
7284
|
// src/flows/llm-flows/basic.ts
|
|
7285
|
+
init_logger();
|
|
7114
7286
|
var BasicLlmRequestProcessor = class extends BaseLlmRequestProcessor {
|
|
7115
7287
|
async *runAsync(invocationContext, llmRequest) {
|
|
7116
7288
|
const agent = invocationContext.agent;
|
|
@@ -7126,7 +7298,21 @@ var BasicLlmRequestProcessor = class extends BaseLlmRequestProcessor {
|
|
|
7126
7298
|
llmRequest.config = {};
|
|
7127
7299
|
}
|
|
7128
7300
|
if (agent.outputSchema) {
|
|
7129
|
-
|
|
7301
|
+
const hasTools = (await agent.canonicalTools?.(invocationContext))?.length > 0;
|
|
7302
|
+
const hasTransfers = !!("subAgents" in agent && agent.subAgents && agent.subAgents.length > 0 && !(agent.disallowTransferToParent && agent.disallowTransferToPeers));
|
|
7303
|
+
if (!hasTools && !hasTransfers) {
|
|
7304
|
+
llmRequest.setOutputSchema(agent.outputSchema);
|
|
7305
|
+
} else {
|
|
7306
|
+
(() => {
|
|
7307
|
+
try {
|
|
7308
|
+
const logger = new Logger({ name: "BasicLlmRequestProcessor" });
|
|
7309
|
+
logger.debug(
|
|
7310
|
+
`Skipping request-level output schema for agent ${agent.name} because tools/transfers are present. Schema will be validated during response processing.`
|
|
7311
|
+
);
|
|
7312
|
+
} catch (e) {
|
|
7313
|
+
}
|
|
7314
|
+
})();
|
|
7315
|
+
}
|
|
7130
7316
|
}
|
|
7131
7317
|
const runConfig = invocationContext.runConfig;
|
|
7132
7318
|
if (!llmRequest.liveConnectConfig) {
|
|
@@ -8278,10 +8464,11 @@ var InstructionsLlmRequestProcessor = class extends BaseLlmRequestProcessor {
|
|
|
8278
8464
|
});
|
|
8279
8465
|
const { $schema, ...json } = raw || {};
|
|
8280
8466
|
llmRequest.appendInstructions([
|
|
8281
|
-
"You must respond with application/json that validates against this JSON Schema:",
|
|
8282
|
-
|
|
8283
|
-
|
|
8284
|
-
|
|
8467
|
+
"You must respond with application/json that validates against this JSON Schema (do NOT wrap the output in markdown or code fences):",
|
|
8468
|
+
JSON.stringify(json, null, 2)
|
|
8469
|
+
]);
|
|
8470
|
+
llmRequest.appendInstructions([
|
|
8471
|
+
'IMPORTANT: After any tool calls, function calls, or agent transfers have completed, produce ONE final assistant message whose entire content is ONLY the JSON object that conforms to the schema provided above. Do NOT include any explanatory text, markdown, or additional messages. Do NOT wrap the JSON in code fences (for example, do NOT use ```json or ```). If you cannot produce valid JSON that matches the schema, return a JSON object with an "error" field describing the problem.'
|
|
8285
8472
|
]);
|
|
8286
8473
|
} catch {
|
|
8287
8474
|
}
|
|
@@ -8578,6 +8765,7 @@ var requestProcessor7 = new NlPlanningRequestProcessor();
|
|
|
8578
8765
|
var responseProcessor2 = new NlPlanningResponseProcessor();
|
|
8579
8766
|
|
|
8580
8767
|
// src/flows/llm-flows/output-schema.ts
|
|
8768
|
+
import { jsonrepair } from "jsonrepair";
|
|
8581
8769
|
init_logger();
|
|
8582
8770
|
var OutputSchemaResponseProcessor = class extends BaseLlmResponseProcessor {
|
|
8583
8771
|
logger = new Logger({ name: "OutputSchemaResponseProcessor" });
|
|
@@ -8599,7 +8787,8 @@ var OutputSchemaResponseProcessor = class extends BaseLlmResponseProcessor {
|
|
|
8599
8787
|
return;
|
|
8600
8788
|
}
|
|
8601
8789
|
try {
|
|
8602
|
-
const
|
|
8790
|
+
const candidate = this.stripCodeFences(textContent);
|
|
8791
|
+
const parsed = this.tryParseJson(candidate, agent.name);
|
|
8603
8792
|
const validated = agent.outputSchema.parse(parsed);
|
|
8604
8793
|
textContent = JSON.stringify(validated, null, 2);
|
|
8605
8794
|
llmResponse.content.parts = llmResponse.content.parts.map((part) => {
|
|
@@ -8647,6 +8836,38 @@ var OutputSchemaResponseProcessor = class extends BaseLlmResponseProcessor {
|
|
|
8647
8836
|
yield errorEvent;
|
|
8648
8837
|
}
|
|
8649
8838
|
}
|
|
8839
|
+
// Strip common code fences and surrounding explanatory text from LLM output.
|
|
8840
|
+
stripCodeFences(raw) {
|
|
8841
|
+
const fencePattern = /```(?:json)?\s*([\s\S]*?)```/i;
|
|
8842
|
+
const fenceMatch = raw.match(fencePattern);
|
|
8843
|
+
if (fenceMatch?.[1]) {
|
|
8844
|
+
return fenceMatch[1].trim();
|
|
8845
|
+
}
|
|
8846
|
+
const lines = raw.split(/\r?\n/).map((l) => l.trim());
|
|
8847
|
+
const startIdx = lines.findIndex(
|
|
8848
|
+
(l) => l.startsWith("{") || l.startsWith("[")
|
|
8849
|
+
);
|
|
8850
|
+
if (startIdx >= 0) {
|
|
8851
|
+
return lines.slice(startIdx).join("\n").trim();
|
|
8852
|
+
}
|
|
8853
|
+
return raw.trim();
|
|
8854
|
+
}
|
|
8855
|
+
// Try parsing JSON; if parse fails, attempt to repair using jsonrepair and parse again.
|
|
8856
|
+
tryParseJson(candidate, agentName) {
|
|
8857
|
+
try {
|
|
8858
|
+
return JSON.parse(candidate);
|
|
8859
|
+
} catch (err) {
|
|
8860
|
+
this.logger.debug("Initial JSON.parse failed, attempting jsonrepair", {
|
|
8861
|
+
agent: agentName
|
|
8862
|
+
});
|
|
8863
|
+
try {
|
|
8864
|
+
const repaired = jsonrepair(candidate);
|
|
8865
|
+
return JSON.parse(repaired);
|
|
8866
|
+
} catch (repairErr) {
|
|
8867
|
+
throw err;
|
|
8868
|
+
}
|
|
8869
|
+
}
|
|
8870
|
+
}
|
|
8650
8871
|
};
|
|
8651
8872
|
var responseProcessor3 = new OutputSchemaResponseProcessor();
|
|
8652
8873
|
|
|
@@ -9069,19 +9290,17 @@ var LlmAgent = class _LlmAgent extends BaseAgent {
|
|
|
9069
9290
|
}
|
|
9070
9291
|
if (!this.disallowTransferToParent || !this.disallowTransferToPeers) {
|
|
9071
9292
|
this.logger.warn(
|
|
9072
|
-
`
|
|
9293
|
+
`Agent ${this.name}: outputSchema is set while transfer flags allow transfers. The output schema will be applied in response post-processing to preserve tool-calling and transfer behavior.`
|
|
9073
9294
|
);
|
|
9074
|
-
this.disallowTransferToParent = true;
|
|
9075
|
-
this.disallowTransferToPeers = true;
|
|
9076
9295
|
}
|
|
9077
9296
|
if (this.subAgents && this.subAgents.length > 0) {
|
|
9078
|
-
|
|
9079
|
-
`
|
|
9297
|
+
this.logger.warn(
|
|
9298
|
+
`Agent ${this.name}: outputSchema is set and subAgents are present. Agent transfers to sub-agents will remain enabled; the schema will be validated after transfers/tools complete.`
|
|
9080
9299
|
);
|
|
9081
9300
|
}
|
|
9082
9301
|
if (this.tools && this.tools.length > 0) {
|
|
9083
|
-
|
|
9084
|
-
`
|
|
9302
|
+
this.logger.warn(
|
|
9303
|
+
`Agent ${this.name}: outputSchema is set and tools are configured. Tools will be callable; the output schema will be applied during response post-processing.`
|
|
9085
9304
|
);
|
|
9086
9305
|
}
|
|
9087
9306
|
}
|
|
@@ -9243,37 +9462,29 @@ async function* mergeAgentRun(agentRuns) {
|
|
|
9243
9462
|
if (agentRuns.length === 0) {
|
|
9244
9463
|
return;
|
|
9245
9464
|
}
|
|
9246
|
-
const
|
|
9247
|
-
|
|
9248
|
-
|
|
9249
|
-
|
|
9250
|
-
|
|
9251
|
-
|
|
9465
|
+
const nextFor = (gen, index) => gen.next().then((result) => ({ index, result })).catch((error) => ({
|
|
9466
|
+
index,
|
|
9467
|
+
result: { done: true, value: void 0 },
|
|
9468
|
+
error
|
|
9469
|
+
}));
|
|
9470
|
+
const entries = agentRuns.map((gen, i) => ({ index: i, promise: nextFor(gen, i) }));
|
|
9471
|
+
const activePromises = () => entries.filter((e) => !!e).map((e) => e.promise);
|
|
9472
|
+
while (true) {
|
|
9473
|
+
const currentActivePromises = activePromises();
|
|
9474
|
+
if (currentActivePromises.length === 0) {
|
|
9475
|
+
break;
|
|
9252
9476
|
}
|
|
9253
|
-
|
|
9254
|
-
let pendingPromises = [...promises];
|
|
9255
|
-
while (pendingPromises.length > 0) {
|
|
9256
|
-
const { index, result, error } = await Promise.race(pendingPromises);
|
|
9257
|
-
pendingPromises = pendingPromises.filter((_, i) => i !== index);
|
|
9477
|
+
const { index, result, error } = await Promise.race(currentActivePromises);
|
|
9258
9478
|
if (error) {
|
|
9259
9479
|
console.error(`Error in parallel agent ${index}:`, error);
|
|
9480
|
+
entries[index] = void 0;
|
|
9260
9481
|
continue;
|
|
9261
9482
|
}
|
|
9262
9483
|
if (!result.done) {
|
|
9263
9484
|
yield result.value;
|
|
9264
|
-
|
|
9265
|
-
|
|
9266
|
-
|
|
9267
|
-
return { index, result: nextResult };
|
|
9268
|
-
} catch (nextError) {
|
|
9269
|
-
return {
|
|
9270
|
-
index,
|
|
9271
|
-
result: { done: true, value: void 0 },
|
|
9272
|
-
error: nextError
|
|
9273
|
-
};
|
|
9274
|
-
}
|
|
9275
|
-
})();
|
|
9276
|
-
pendingPromises.push(nextPromise);
|
|
9485
|
+
entries[index] = { index, promise: nextFor(agentRuns[index], index) };
|
|
9486
|
+
} else {
|
|
9487
|
+
entries[index] = void 0;
|
|
9277
9488
|
}
|
|
9278
9489
|
}
|
|
9279
9490
|
}
|
|
@@ -10432,8 +10643,20 @@ var AgentBuilder = class _AgentBuilder {
|
|
|
10432
10643
|
// If provided, reuse directly
|
|
10433
10644
|
definitionLocked = false;
|
|
10434
10645
|
// Lock further definition mutation after withAgent
|
|
10435
|
-
warnedMethods = /* @__PURE__ */ new Set();
|
|
10436
10646
|
logger = new Logger({ name: "AgentBuilder" });
|
|
10647
|
+
/**
|
|
10648
|
+
* Warn (once per method) if the definition has been locked by withAgent().
|
|
10649
|
+
*/
|
|
10650
|
+
warnIfLocked(method) {
|
|
10651
|
+
if (!this.definitionLocked) return;
|
|
10652
|
+
this.logger.warn(
|
|
10653
|
+
`AgentBuilder: ${method}() ignored because builder is locked by withAgent()`,
|
|
10654
|
+
{
|
|
10655
|
+
suggestion: "Configure model/tools/etc. before calling withAgent(), or avoid withAgent() if you intend to mutate afterwards.",
|
|
10656
|
+
context: { method, agentName: this.config.name }
|
|
10657
|
+
}
|
|
10658
|
+
);
|
|
10659
|
+
}
|
|
10437
10660
|
/**
|
|
10438
10661
|
* Private constructor - use static create() method
|
|
10439
10662
|
*/
|
|
@@ -10493,6 +10716,16 @@ var AgentBuilder = class _AgentBuilder {
|
|
|
10493
10716
|
}
|
|
10494
10717
|
withOutputSchema(schema) {
|
|
10495
10718
|
this.warnIfLocked("withOutputSchema");
|
|
10719
|
+
if (this.agentType === "sequential" || this.agentType === "parallel") {
|
|
10720
|
+
const msg = "Output schemas cannot be applied to sequential or parallel agents. Define output schemas on each sub-agent instead.";
|
|
10721
|
+
this.logger.error(msg, {
|
|
10722
|
+
suggestion: "Apply outputSchema to each sub-agent individually.",
|
|
10723
|
+
context: {
|
|
10724
|
+
agentType: this.agentType
|
|
10725
|
+
}
|
|
10726
|
+
});
|
|
10727
|
+
throw new Error(msg);
|
|
10728
|
+
}
|
|
10496
10729
|
this.config.outputSchema = schema;
|
|
10497
10730
|
return this;
|
|
10498
10731
|
}
|
|
@@ -10533,6 +10766,16 @@ var AgentBuilder = class _AgentBuilder {
|
|
|
10533
10766
|
*/
|
|
10534
10767
|
withOutputKey(outputKey) {
|
|
10535
10768
|
this.warnIfLocked("withOutputKey");
|
|
10769
|
+
if (this.agentType === "sequential" || this.agentType === "parallel") {
|
|
10770
|
+
this.logger.warn(
|
|
10771
|
+
"AgentBuilder: outputKey ignored for sequential/parallel aggregator",
|
|
10772
|
+
{
|
|
10773
|
+
suggestion: "Set outputKey on each sub-agent instead.",
|
|
10774
|
+
context: { attemptedOutputKey: outputKey, agentType: this.agentType }
|
|
10775
|
+
}
|
|
10776
|
+
);
|
|
10777
|
+
return this;
|
|
10778
|
+
}
|
|
10536
10779
|
this.config.outputKey = outputKey;
|
|
10537
10780
|
return this;
|
|
10538
10781
|
}
|
|
@@ -10584,9 +10827,37 @@ var AgentBuilder = class _AgentBuilder {
|
|
|
10584
10827
|
* @returns This builder instance for chaining
|
|
10585
10828
|
*/
|
|
10586
10829
|
asSequential(subAgents) {
|
|
10587
|
-
this.
|
|
10830
|
+
if (this.definitionLocked) {
|
|
10831
|
+
this.logger.warn(
|
|
10832
|
+
"AgentBuilder: asSequential() ignored; builder locked by withAgent()",
|
|
10833
|
+
{
|
|
10834
|
+
suggestion: "Call asSequential() before withAgent().",
|
|
10835
|
+
context: { agentName: this.config.name }
|
|
10836
|
+
}
|
|
10837
|
+
);
|
|
10838
|
+
return this;
|
|
10839
|
+
}
|
|
10588
10840
|
this.agentType = "sequential";
|
|
10589
10841
|
this.config.subAgents = subAgents;
|
|
10842
|
+
if (this.config.outputKey) {
|
|
10843
|
+
this.logger.warn(
|
|
10844
|
+
"AgentBuilder: outputKey ignored for sequential agent aggregator; removed",
|
|
10845
|
+
{
|
|
10846
|
+
suggestion: "Assign outputKey on individual sub-agents if needed.",
|
|
10847
|
+
context: { previousValue: this.config.outputKey }
|
|
10848
|
+
}
|
|
10849
|
+
);
|
|
10850
|
+
this.config.outputKey = void 0;
|
|
10851
|
+
}
|
|
10852
|
+
if (this.config.outputSchema) {
|
|
10853
|
+
this.logger.warn(
|
|
10854
|
+
"AgentBuilder: outputSchema cannot be applied to sequential aggregator; removed",
|
|
10855
|
+
{
|
|
10856
|
+
suggestion: "Apply schemas to sub-agents individually."
|
|
10857
|
+
}
|
|
10858
|
+
);
|
|
10859
|
+
this.config.outputSchema = void 0;
|
|
10860
|
+
}
|
|
10590
10861
|
return this;
|
|
10591
10862
|
}
|
|
10592
10863
|
/**
|
|
@@ -10595,9 +10866,37 @@ var AgentBuilder = class _AgentBuilder {
|
|
|
10595
10866
|
* @returns This builder instance for chaining
|
|
10596
10867
|
*/
|
|
10597
10868
|
asParallel(subAgents) {
|
|
10598
|
-
this.
|
|
10869
|
+
if (this.definitionLocked) {
|
|
10870
|
+
this.logger.warn(
|
|
10871
|
+
"AgentBuilder: asParallel() ignored; builder locked by withAgent()",
|
|
10872
|
+
{
|
|
10873
|
+
suggestion: "Call asParallel() before withAgent().",
|
|
10874
|
+
context: { agentName: this.config.name }
|
|
10875
|
+
}
|
|
10876
|
+
);
|
|
10877
|
+
return this;
|
|
10878
|
+
}
|
|
10599
10879
|
this.agentType = "parallel";
|
|
10600
10880
|
this.config.subAgents = subAgents;
|
|
10881
|
+
if (this.config.outputKey) {
|
|
10882
|
+
this.logger.warn(
|
|
10883
|
+
"AgentBuilder: outputKey ignored for parallel agent aggregator; removed",
|
|
10884
|
+
{
|
|
10885
|
+
suggestion: "Assign outputKey on individual sub-agents if needed.",
|
|
10886
|
+
context: { previousValue: this.config.outputKey }
|
|
10887
|
+
}
|
|
10888
|
+
);
|
|
10889
|
+
this.config.outputKey = void 0;
|
|
10890
|
+
}
|
|
10891
|
+
if (this.config.outputSchema) {
|
|
10892
|
+
this.logger.warn(
|
|
10893
|
+
"AgentBuilder: outputSchema cannot be applied to parallel aggregator; removed",
|
|
10894
|
+
{
|
|
10895
|
+
suggestion: "Apply schemas to sub-agents individually."
|
|
10896
|
+
}
|
|
10897
|
+
);
|
|
10898
|
+
this.config.outputSchema = void 0;
|
|
10899
|
+
}
|
|
10601
10900
|
return this;
|
|
10602
10901
|
}
|
|
10603
10902
|
/**
|
|
@@ -10650,9 +10949,11 @@ var AgentBuilder = class _AgentBuilder {
|
|
|
10650
10949
|
*/
|
|
10651
10950
|
withSession(session) {
|
|
10652
10951
|
if (!this.sessionService) {
|
|
10653
|
-
|
|
10654
|
-
|
|
10655
|
-
|
|
10952
|
+
const msg = "Session service must be configured before using withSession(). Call withSessionService() first, or use withQuickSession() for in-memory sessions.";
|
|
10953
|
+
this.logger.error(msg, {
|
|
10954
|
+
suggestion: "Invoke withSessionService() prior to withSession()."
|
|
10955
|
+
});
|
|
10956
|
+
throw new Error(msg);
|
|
10656
10957
|
}
|
|
10657
10958
|
this.sessionOptions = {
|
|
10658
10959
|
...this.sessionOptions,
|
|
@@ -10723,7 +11024,12 @@ var AgentBuilder = class _AgentBuilder {
|
|
|
10723
11024
|
const baseRunner = new Runner(runnerConfig);
|
|
10724
11025
|
runner = this.createEnhancedRunner(baseRunner, session);
|
|
10725
11026
|
}
|
|
10726
|
-
return {
|
|
11027
|
+
return {
|
|
11028
|
+
agent,
|
|
11029
|
+
runner,
|
|
11030
|
+
session,
|
|
11031
|
+
sessionService: this.sessionService
|
|
11032
|
+
};
|
|
10727
11033
|
}
|
|
10728
11034
|
/**
|
|
10729
11035
|
* Type-safe build method for agents with output schemas
|
|
@@ -10751,7 +11057,11 @@ var AgentBuilder = class _AgentBuilder {
|
|
|
10751
11057
|
switch (this.agentType) {
|
|
10752
11058
|
case "llm": {
|
|
10753
11059
|
if (!this.config.model) {
|
|
10754
|
-
|
|
11060
|
+
const msg = "Model is required for LLM agent";
|
|
11061
|
+
this.logger.error(msg, {
|
|
11062
|
+
suggestion: "Call withModel() before build()."
|
|
11063
|
+
});
|
|
11064
|
+
throw new Error(msg);
|
|
10755
11065
|
}
|
|
10756
11066
|
const model = this.config.model;
|
|
10757
11067
|
return new LlmAgent({
|
|
@@ -10775,7 +11085,11 @@ var AgentBuilder = class _AgentBuilder {
|
|
|
10775
11085
|
}
|
|
10776
11086
|
case "sequential":
|
|
10777
11087
|
if (!this.config.subAgents || !Array.isArray(this.config.subAgents) || this.config.subAgents.length === 0) {
|
|
10778
|
-
|
|
11088
|
+
const msg = "Sub-agents required for sequential agent";
|
|
11089
|
+
this.logger.error(msg, {
|
|
11090
|
+
suggestion: "Provide at least one sub-agent."
|
|
11091
|
+
});
|
|
11092
|
+
throw new Error(msg);
|
|
10779
11093
|
}
|
|
10780
11094
|
return new SequentialAgent({
|
|
10781
11095
|
name: this.config.name,
|
|
@@ -10784,7 +11098,11 @@ var AgentBuilder = class _AgentBuilder {
|
|
|
10784
11098
|
});
|
|
10785
11099
|
case "parallel":
|
|
10786
11100
|
if (!this.config.subAgents || !Array.isArray(this.config.subAgents) || this.config.subAgents.length === 0) {
|
|
10787
|
-
|
|
11101
|
+
const msg = "Sub-agents required for parallel agent";
|
|
11102
|
+
this.logger.error(msg, {
|
|
11103
|
+
suggestion: "Provide at least one sub-agent."
|
|
11104
|
+
});
|
|
11105
|
+
throw new Error(msg);
|
|
10788
11106
|
}
|
|
10789
11107
|
return new ParallelAgent({
|
|
10790
11108
|
name: this.config.name,
|
|
@@ -10793,7 +11111,11 @@ var AgentBuilder = class _AgentBuilder {
|
|
|
10793
11111
|
});
|
|
10794
11112
|
case "loop":
|
|
10795
11113
|
if (!this.config.subAgents || !Array.isArray(this.config.subAgents) || this.config.subAgents.length === 0) {
|
|
10796
|
-
|
|
11114
|
+
const msg = "Sub-agents required for loop agent";
|
|
11115
|
+
this.logger.error(msg, {
|
|
11116
|
+
suggestion: "Provide at least one sub-agent."
|
|
11117
|
+
});
|
|
11118
|
+
throw new Error(msg);
|
|
10797
11119
|
}
|
|
10798
11120
|
return new LoopAgent({
|
|
10799
11121
|
name: this.config.name,
|
|
@@ -10803,7 +11125,11 @@ var AgentBuilder = class _AgentBuilder {
|
|
|
10803
11125
|
});
|
|
10804
11126
|
case "langgraph":
|
|
10805
11127
|
if (!this.config.nodes || !Array.isArray(this.config.nodes) || this.config.nodes.length === 0 || !this.config.rootNode || typeof this.config.rootNode !== "string") {
|
|
10806
|
-
|
|
11128
|
+
const msg = "Nodes and root node required for LangGraph agent";
|
|
11129
|
+
this.logger.error(msg, {
|
|
11130
|
+
suggestion: "Provide nodes[] and a valid rootNode string."
|
|
11131
|
+
});
|
|
11132
|
+
throw new Error(msg);
|
|
10807
11133
|
}
|
|
10808
11134
|
return new LangGraphAgent({
|
|
10809
11135
|
name: this.config.name,
|
|
@@ -10837,11 +11163,16 @@ var AgentBuilder = class _AgentBuilder {
|
|
|
10837
11163
|
createEnhancedRunner(baseRunner, session) {
|
|
10838
11164
|
const sessionOptions = this.sessionOptions;
|
|
10839
11165
|
const outputSchema = this.config.outputSchema;
|
|
11166
|
+
const agentType = this.agentType;
|
|
11167
|
+
const isMulti = agentType === "parallel" || agentType === "sequential";
|
|
11168
|
+
const subAgentNames = this.config.subAgents?.map((a) => a.name) || [];
|
|
10840
11169
|
return {
|
|
10841
11170
|
__outputSchema: outputSchema,
|
|
10842
11171
|
async ask(message) {
|
|
10843
11172
|
const newMessage = typeof message === "string" ? { parts: [{ text: message }] } : typeof message === "object" && "contents" in message ? { parts: message.contents[message.contents.length - 1].parts } : message;
|
|
10844
|
-
let
|
|
11173
|
+
let combinedResponse = "";
|
|
11174
|
+
const perAgentBuffers = {};
|
|
11175
|
+
const authors = /* @__PURE__ */ new Set();
|
|
10845
11176
|
if (!sessionOptions?.userId) {
|
|
10846
11177
|
throw new Error("Session configuration is required");
|
|
10847
11178
|
}
|
|
@@ -10855,45 +11186,45 @@ var AgentBuilder = class _AgentBuilder {
|
|
|
10855
11186
|
(part) => (part && typeof part === "object" && "text" in part ? part.text : "") || ""
|
|
10856
11187
|
).join("");
|
|
10857
11188
|
if (content) {
|
|
10858
|
-
|
|
11189
|
+
combinedResponse += content;
|
|
11190
|
+
const author = event.author || "";
|
|
11191
|
+
if (author && author !== "user") {
|
|
11192
|
+
authors.add(author);
|
|
11193
|
+
perAgentBuffers[author] = (perAgentBuffers[author] || "") + content;
|
|
11194
|
+
}
|
|
10859
11195
|
}
|
|
10860
11196
|
}
|
|
10861
11197
|
}
|
|
11198
|
+
if (isMulti) {
|
|
11199
|
+
return subAgentNames.map((name) => ({
|
|
11200
|
+
agent: name,
|
|
11201
|
+
response: (perAgentBuffers[name] || "").trim()
|
|
11202
|
+
}));
|
|
11203
|
+
}
|
|
10862
11204
|
if (outputSchema) {
|
|
10863
11205
|
try {
|
|
10864
|
-
const parsed = JSON.parse(
|
|
11206
|
+
const parsed = JSON.parse(combinedResponse);
|
|
10865
11207
|
return outputSchema.parse(parsed);
|
|
10866
11208
|
} catch (parseError) {
|
|
10867
11209
|
try {
|
|
10868
|
-
return outputSchema.parse(
|
|
11210
|
+
return outputSchema.parse(combinedResponse);
|
|
10869
11211
|
} catch (validationError) {
|
|
10870
|
-
|
|
11212
|
+
throw new Error(
|
|
11213
|
+
`Failed to parse and validate LLM output against the schema.
|
|
11214
|
+
JSON parse error: ${parseError instanceof Error ? parseError.message : String(parseError)}
|
|
11215
|
+
Zod validation error: ${validationError instanceof Error ? validationError.message : String(validationError)}
|
|
11216
|
+
Raw output: "${combinedResponse}"`
|
|
11217
|
+
);
|
|
10871
11218
|
}
|
|
10872
11219
|
}
|
|
10873
11220
|
}
|
|
10874
|
-
return
|
|
11221
|
+
return combinedResponse.trim();
|
|
10875
11222
|
},
|
|
10876
11223
|
runAsync(params) {
|
|
10877
11224
|
return baseRunner.runAsync(params);
|
|
10878
11225
|
}
|
|
10879
11226
|
};
|
|
10880
11227
|
}
|
|
10881
|
-
/**
|
|
10882
|
-
* Warn (once per method) if the definition has been locked by withAgent().
|
|
10883
|
-
*/
|
|
10884
|
-
warnIfLocked(method) {
|
|
10885
|
-
if (!this.definitionLocked) return;
|
|
10886
|
-
if (this.warnedMethods.has(method)) return;
|
|
10887
|
-
this.warnedMethods.add(method);
|
|
10888
|
-
if (process.env.NODE_ENV !== "production") {
|
|
10889
|
-
const msg = `AgentBuilder: attempted to call ${method} after withAgent(); ignoring. (Wrap the agent first OR configure before withAgent).`;
|
|
10890
|
-
if (this.logger && typeof this.logger.warn === "function") {
|
|
10891
|
-
this.logger.warn(msg);
|
|
10892
|
-
} else {
|
|
10893
|
-
console.warn(msg);
|
|
10894
|
-
}
|
|
10895
|
-
}
|
|
10896
|
-
}
|
|
10897
11228
|
};
|
|
10898
11229
|
|
|
10899
11230
|
// src/memory/index.ts
|