@aigne/agent-library 1.23.0-beta.6 → 1.23.0-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,28 @@
7
7
  * @aigne/core bumped to 1.22.0
8
8
  * @aigne/openai bumped to 0.3.4
9
9
 
10
+ ## [1.23.0-beta.8](https://github.com/AIGNE-io/aigne-framework/compare/agent-library-v1.23.0-beta.7...agent-library-v1.23.0-beta.8) (2025-12-12)
11
+
12
+
13
+ ### Features
14
+
15
+ * **agent-library:** add BashAgent with sandbox support ([#816](https://github.com/AIGNE-io/aigne-framework/issues/816)) ([0d4feee](https://github.com/AIGNE-io/aigne-framework/commit/0d4feeeac2b71df1c4d725adeee76c9318ce8e02))
16
+
17
+ ## [1.23.0-beta.7](https://github.com/AIGNE-io/aigne-framework/compare/agent-library-v1.23.0-beta.6...agent-library-v1.23.0-beta.7) (2025-12-11)
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * **orchestrator:** support custom input schema for planner/worker/completer ([#823](https://github.com/AIGNE-io/aigne-framework/issues/823)) ([3d26f8b](https://github.com/AIGNE-io/aigne-framework/commit/3d26f8bac8b679010f25d9e4eb59fc6e80afda4c))
23
+
24
+
25
+ ### Dependencies
26
+
27
+ * The following workspace dependencies were updated
28
+ * dependencies
29
+ * @aigne/core bumped to 1.71.0-beta.6
30
+ * @aigne/openai bumped to 0.16.15-beta.6
31
+
10
32
  ## [1.23.0-beta.6](https://github.com/AIGNE-io/aigne-framework/compare/agent-library-v1.23.0-beta.5...agent-library-v1.23.0-beta.6) (2025-12-11)
11
33
 
12
34
 
package/README.md CHANGED
@@ -29,6 +29,7 @@ Collection of agent libraries for [AIGNE Framework](https://github.com/AIGNE-io/
29
29
  ## Features
30
30
 
31
31
  * **Orchestrator Agent**: Provides OrchestratorAgent implementation for coordinating workflows between multiple agents
32
+ * **Bash Agent**: Secure execution of bash scripts with sandboxed environment and comprehensive output handling
32
33
  * **Task Concurrency**: Supports parallel execution of multiple tasks to improve processing efficiency
33
34
  * **Planning & Execution**: Automatically generates execution plans and executes them step by step
34
35
  * **Result Synthesis**: Intelligently synthesizes results from multiple steps and tasks
@@ -62,6 +63,8 @@ The library provides the following components:
62
63
 
63
64
  * **[Orchestrator Agent](src/orchestrator/README.md)**: A sophisticated agent pattern that enables autonomous task planning and execution through a three-phase architecture: Planner → Worker → Completer. It breaks down complex objectives into manageable tasks, executes them iteratively, and synthesizes the final results. Perfect for coordinating complex workflows and multi-step tasks.
64
65
 
66
+ * **[Bash Agent](src/bash/README.md)**: Enables secure execution of bash scripts within a sandboxed environment. Provides controlled access to system commands, network resources, and the filesystem while returning comprehensive execution results including stdout, stderr, and exit codes. Ideal for running system commands, interacting with CLI tools, and executing shell scripts safely.
67
+
65
68
  ## License
66
69
 
67
70
  Elastic-2.0
@@ -0,0 +1,124 @@
1
+ import { type SpawnOptions } from "node:child_process";
2
+ import { Agent, type AgentInvokeOptions, type AgentOptions, type AgentResponseStream, type Message } from "@aigne/core";
3
+ import { type NestAgentSchema } from "@aigne/core/loader/agent-yaml.js";
4
+ import { type LoadOptions } from "@aigne/core/loader/index.js";
5
+ import { type SandboxRuntimeConfig } from "@anthropic-ai/sandbox-runtime";
6
+ export interface BashAgentOptions extends AgentOptions<BashAgentInput, BashAgentOutput> {
7
+ sandbox?: Partial<{
8
+ [K in keyof SandboxRuntimeConfig]: Partial<SandboxRuntimeConfig[K]>;
9
+ }> | boolean;
10
+ inputKey?: string;
11
+ /**
12
+ * Optional timeout for script execution in milliseconds
13
+ * @default 60000 (60 seconds)
14
+ */
15
+ timeout?: number;
16
+ /**
17
+ * Optional permissions configuration for command execution control
18
+ * Inspired by Claude Code's permission system
19
+ */
20
+ permissions?: {
21
+ /**
22
+ * Whitelist: Commands that are allowed to execute without approval
23
+ * Supports exact match or prefix match with ':*' wildcard
24
+ * Examples: ['npm run test:*', 'git status', 'ls:*']
25
+ */
26
+ allow?: string[];
27
+ /**
28
+ * Blacklist: Commands that are completely forbidden
29
+ * Takes highest priority over allow and defaultMode
30
+ * Examples: ['rm:*', 'sudo:*', 'curl:*']
31
+ */
32
+ deny?: string[];
33
+ /**
34
+ * Default permission mode when command doesn't match allow/deny lists
35
+ * @default 'allow'
36
+ */
37
+ defaultMode?: "allow" | "ask" | "deny";
38
+ /**
39
+ * Callback function invoked when a command requires user approval (ask mode)
40
+ * Return true to approve, false to reject
41
+ * @param script - The script that requires approval
42
+ * @returns Promise resolving to approval decision
43
+ */
44
+ guard?: BashAgent["guard"];
45
+ };
46
+ }
47
+ export interface LoadBashAgentOptions extends Omit<BashAgentOptions, "permissions"> {
48
+ permissions?: Omit<NonNullable<BashAgentOptions["permissions"]>, "guard"> & {
49
+ guard?: NestAgentSchema;
50
+ };
51
+ }
52
+ export interface BashAgentInput extends Message {
53
+ script?: string;
54
+ }
55
+ export interface BashAgentOutput extends Message {
56
+ stdout?: string;
57
+ stderr?: string;
58
+ exitCode?: number;
59
+ }
60
+ export declare class BashAgent extends Agent<BashAgentInput, BashAgentOutput> {
61
+ options: BashAgentOptions;
62
+ static load(options: {
63
+ filepath: string;
64
+ parsed: LoadBashAgentOptions;
65
+ options?: LoadOptions;
66
+ }): Promise<Agent<any, any>>;
67
+ constructor(options: BashAgentOptions);
68
+ inputKey?: string;
69
+ guard?: Agent<{
70
+ script?: string;
71
+ }, {
72
+ approved: boolean;
73
+ reason?: string;
74
+ }>;
75
+ process(input: BashAgentInput, options: AgentInvokeOptions): Promise<AgentResponseStream<BashAgentOutput>>;
76
+ spawn(command: string, args?: string[], options?: SpawnOptions): Promise<AgentResponseStream<BashAgentOutput>>;
77
+ runInSandbox<T>(config: Exclude<BashAgentOptions["sandbox"], boolean>, script: string, task: (script: string) => Promise<T>): Promise<T>;
78
+ /**
79
+ * Check permission for executing a script
80
+ * Permission priority: deny > allow > defaultMode
81
+ *
82
+ * For complex commands (with pipes, chaining, etc.), each sub-command
83
+ * is validated separately. All sub-commands must pass permission checks.
84
+ *
85
+ * @param script - The script to check permission for
86
+ * @returns Permission decision: 'allow', 'ask', or 'deny'
87
+ */
88
+ checkPermission(script: string): Promise<"allow" | "ask" | "deny">;
89
+ /**
90
+ * Split a script into individual commands by pipes, command chaining, etc.
91
+ * Separators: | (pipe), && (AND), || (OR), & (background), ; (sequential), \n (newline)
92
+ *
93
+ * Note: Redirection operators (>, >>, <, <<, &>, 2>, etc.) are treated as part of
94
+ * the command, not as separators.
95
+ *
96
+ * @param script - The script to split
97
+ * @returns Array of individual commands
98
+ */
99
+ private splitCommands;
100
+ /**
101
+ * Check permission for a single command
102
+ * @param command - The command to check
103
+ * @param permissions - Permission configuration
104
+ * @returns Permission decision for this command
105
+ */
106
+ private checkSingleCommandPermission;
107
+ /**
108
+ * Match a single command against a permission pattern
109
+ * Supports exact match and prefix match with ':*' wildcard
110
+ *
111
+ * Note: This method is called for individual commands after splitting,
112
+ * so it doesn't need to handle complex command chaining.
113
+ *
114
+ * Examples:
115
+ * - "ls:*" matches "ls", "ls -la", "ls:option"
116
+ * - "npm run test:*" matches "npm run test", "npm run test:unit", "npm run test arg"
117
+ *
118
+ * @param command - The command to match (should be a single command)
119
+ * @param pattern - The pattern to match against
120
+ * @returns true if command matches pattern
121
+ */
122
+ private matchPattern;
123
+ }
124
+ export default BashAgent;
@@ -0,0 +1,359 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.BashAgent = void 0;
37
+ const node_child_process_1 = require("node:child_process");
38
+ const core_1 = require("@aigne/core");
39
+ const agent_yaml_js_1 = require("@aigne/core/loader/agent-yaml.js");
40
+ const index_js_1 = require("@aigne/core/loader/index.js");
41
+ const schema_js_1 = require("@aigne/core/loader/schema.js");
42
+ const sandbox_runtime_1 = require("@anthropic-ai/sandbox-runtime");
43
+ const ripgrep_1 = require("@vscode/ripgrep");
44
+ const zod_1 = __importStar(require("zod"));
45
+ const mutex_js_1 = require("../utils/mutex.js");
46
+ const DEFAULT_TIMEOUT = 60e3; // 60 seconds
47
+ let sandboxInitialization;
48
+ const mutex = new mutex_js_1.Mutex();
49
+ class BashAgent extends core_1.Agent {
50
+ options;
51
+ static async load(options) {
52
+ const schema = getBashAgentSchema({ filepath: options.filepath });
53
+ const parsed = await schema.parseAsync(options.parsed);
54
+ return new BashAgent({
55
+ ...parsed,
56
+ permissions: {
57
+ ...parsed.permissions,
58
+ guard: parsed.permissions?.guard
59
+ ? await (0, index_js_1.loadNestAgent)(options.filepath, parsed.permissions.guard, options.options ?? {}, {
60
+ outputSchema: zod_1.default.object({
61
+ approved: zod_1.default.boolean().describe("Whether the command is approved by the user."),
62
+ reason: zod_1.default.string().describe("Optional reason for rejection.").optional(),
63
+ }),
64
+ })
65
+ : undefined,
66
+ },
67
+ });
68
+ }
69
+ constructor(options) {
70
+ super({
71
+ name: "Bash",
72
+ description: `\
73
+ Execute bash scripts and return stdout and stderr output.
74
+
75
+ When to use:
76
+ - Running system commands or bash scripts
77
+ - Interacting with command-line tools
78
+ `,
79
+ ...options,
80
+ inputSchema: zod_1.default.object({
81
+ [options.inputKey || "script"]: zod_1.default.string().describe("The bash script to execute."),
82
+ }),
83
+ outputSchema: zod_1.default.object({
84
+ stdout: zod_1.default.string().describe("The standard output from the bash script.").optional(),
85
+ stderr: zod_1.default.string().describe("The standard error output from the bash script.").optional(),
86
+ exitCode: zod_1.default.number().describe("The exit code of the bash script execution.").optional(),
87
+ }),
88
+ });
89
+ this.options = options;
90
+ this.guard = this.options.permissions?.guard;
91
+ this.inputKey = this.options.inputKey;
92
+ }
93
+ inputKey;
94
+ guard;
95
+ async process(input, options) {
96
+ const script = input[this.inputKey || "script"];
97
+ if (typeof script !== "string")
98
+ throw new Error(`Invalid or missing script input: ${this.inputKey || "script"}`);
99
+ // Permission check
100
+ const permission = await this.checkPermission(script);
101
+ if (permission === "deny") {
102
+ throw new Error(`Command blocked by permissions: ${script}`);
103
+ }
104
+ if (permission === "ask") {
105
+ if (!this.guard) {
106
+ throw new Error(`No guard agent configured for permission 'ask'`);
107
+ }
108
+ const { approved, reason } = await this.invokeChildAgent(this.guard, input, {
109
+ ...options,
110
+ streaming: false,
111
+ });
112
+ if (!approved) {
113
+ throw new Error(`Command rejected by guard agent (${this.guard.name}): ${script}, reason: ${reason || "no reason provided"}`);
114
+ }
115
+ }
116
+ const platform = {
117
+ win32: "windows",
118
+ darwin: "macos",
119
+ linux: "linux",
120
+ }[globalThis.process.platform] || "unknown";
121
+ if (this.options.sandbox === false) {
122
+ return this.spawn("bash", ["-c", script]);
123
+ }
124
+ else {
125
+ if (!sandbox_runtime_1.SandboxManager.isSupportedPlatform(platform)) {
126
+ throw new Error(`Sandboxed execution is not supported on this platform ${platform}`);
127
+ }
128
+ return await this.runInSandbox(typeof this.options.sandbox === "boolean" ? {} : this.options.sandbox, script, async (sandboxedCommand) => {
129
+ return this.spawn(sandboxedCommand, undefined, {
130
+ shell: true,
131
+ });
132
+ });
133
+ }
134
+ }
135
+ async spawn(command, args, options) {
136
+ return new ReadableStream({
137
+ start: (controller) => {
138
+ try {
139
+ const timeout = this.options.timeout ?? DEFAULT_TIMEOUT;
140
+ const child = (0, node_child_process_1.spawn)(command, args, {
141
+ ...options,
142
+ stdio: "pipe",
143
+ timeout,
144
+ });
145
+ let stderr = "";
146
+ child.stdout.on("data", (chunk) => {
147
+ controller.enqueue({ delta: { text: { stdout: chunk.toString() } } });
148
+ });
149
+ child.stderr.on("data", (chunk) => {
150
+ controller.enqueue({ delta: { text: { stderr: chunk.toString() } } });
151
+ stderr += chunk.toString();
152
+ });
153
+ child.on("error", (error) => {
154
+ controller.error(error);
155
+ });
156
+ child.on("close", (code, signal) => {
157
+ // Handle timeout or killed by signal
158
+ if (signal) {
159
+ const timeoutHint = signal === "SIGTERM" ? ` (likely timeout ${timeout})` : "";
160
+ controller.error(new Error(`Bash script killed by signal ${signal}${timeoutHint}: ${stderr}`));
161
+ return;
162
+ }
163
+ // Handle normal exit
164
+ if (typeof code === "number") {
165
+ if (code === 0) {
166
+ controller.enqueue({ delta: { json: { exitCode: code } } });
167
+ controller.close();
168
+ }
169
+ else {
170
+ controller.error(new Error(`Bash script exited with code ${code}: ${stderr}`));
171
+ }
172
+ }
173
+ else {
174
+ // Unexpected case: no code and no signal
175
+ controller.error(new Error(`Bash script closed unexpectedly: ${stderr}`));
176
+ }
177
+ });
178
+ }
179
+ catch (error) {
180
+ controller.error(error);
181
+ }
182
+ },
183
+ });
184
+ }
185
+ async runInSandbox(config, script, task) {
186
+ return await mutex.runExclusive(async () => {
187
+ sandboxInitialization ??= sandbox_runtime_1.SandboxManager.initialize({
188
+ network: {
189
+ allowedDomains: [],
190
+ deniedDomains: [],
191
+ },
192
+ filesystem: {
193
+ denyRead: [],
194
+ denyWrite: [],
195
+ allowWrite: [],
196
+ },
197
+ ripgrep: {
198
+ command: ripgrep_1.rgPath,
199
+ },
200
+ });
201
+ await sandboxInitialization;
202
+ sandbox_runtime_1.SandboxManager.updateConfig({
203
+ ...config,
204
+ network: {
205
+ ...config?.network,
206
+ allowedDomains: config?.network?.allowedDomains || [],
207
+ deniedDomains: config?.network?.deniedDomains || [],
208
+ },
209
+ filesystem: {
210
+ ...config?.filesystem,
211
+ denyRead: config?.filesystem?.denyRead || [],
212
+ denyWrite: config?.filesystem?.denyWrite || [],
213
+ allowWrite: config?.filesystem?.allowWrite || [],
214
+ },
215
+ ripgrep: {
216
+ command: ripgrep_1.rgPath,
217
+ },
218
+ });
219
+ const sandboxedCommand = await sandbox_runtime_1.SandboxManager.wrapWithSandbox(script);
220
+ return await task(sandboxedCommand);
221
+ });
222
+ }
223
+ /**
224
+ * Check permission for executing a script
225
+ * Permission priority: deny > allow > defaultMode
226
+ *
227
+ * For complex commands (with pipes, chaining, etc.), each sub-command
228
+ * is validated separately. All sub-commands must pass permission checks.
229
+ *
230
+ * @param script - The script to check permission for
231
+ * @returns Permission decision: 'allow', 'ask', or 'deny'
232
+ */
233
+ async checkPermission(script) {
234
+ const { permissions } = this.options;
235
+ if (!permissions) {
236
+ return "allow"; // No permissions configured, default to allow
237
+ }
238
+ // Split complex commands into individual commands
239
+ const commands = this.splitCommands(script);
240
+ // Check permission for each command
241
+ for (const command of commands) {
242
+ const commandPermission = this.checkSingleCommandPermission(command, permissions);
243
+ // If any command is denied, deny the whole script
244
+ if (commandPermission === "deny") {
245
+ return "deny";
246
+ }
247
+ // If any command requires asking, the whole script requires asking
248
+ if (commandPermission === "ask") {
249
+ return "ask";
250
+ }
251
+ }
252
+ // All commands are allowed
253
+ return "allow";
254
+ }
255
+ /**
256
+ * Split a script into individual commands by pipes, command chaining, etc.
257
+ * Separators: | (pipe), && (AND), || (OR), & (background), ; (sequential), \n (newline)
258
+ *
259
+ * Note: Redirection operators (>, >>, <, <<, &>, 2>, etc.) are treated as part of
260
+ * the command, not as separators.
261
+ *
262
+ * @param script - The script to split
263
+ * @returns Array of individual commands
264
+ */
265
+ splitCommands(script) {
266
+ // Split by pipes, &&, ||, &, ;, and newlines
267
+ // IMPORTANT: Match longer patterns first to avoid incorrect splitting:
268
+ // - && and || before single & and |
269
+ // - Must use negative lookbehind/lookahead to avoid matching &> (redirect)
270
+ // Pattern explanation: (?<!&) means "not preceded by &", (?!>) means "not followed by >"
271
+ const parts = script.split(/(\||&&|\|\||(?<!&)&(?!>)|;|\n)/);
272
+ const commands = [];
273
+ for (let i = 0; i < parts.length; i++) {
274
+ const part = parts[i];
275
+ if (!part)
276
+ continue;
277
+ const trimmedPart = part.trim();
278
+ // Skip empty parts and separator tokens
279
+ if (trimmedPart && !["|", "&&", "||", "&", ";"].includes(trimmedPart)) {
280
+ commands.push(trimmedPart);
281
+ }
282
+ }
283
+ return commands.length > 0 ? commands : [script];
284
+ }
285
+ /**
286
+ * Check permission for a single command
287
+ * @param command - The command to check
288
+ * @param permissions - Permission configuration
289
+ * @returns Permission decision for this command
290
+ */
291
+ checkSingleCommandPermission(command, permissions) {
292
+ // Priority 1: Check deny list (highest priority)
293
+ if (permissions.deny?.some((pattern) => this.matchPattern(command, pattern))) {
294
+ return "deny";
295
+ }
296
+ // Priority 2: Check allow list
297
+ if (permissions.allow?.some((pattern) => this.matchPattern(command, pattern))) {
298
+ return "allow";
299
+ }
300
+ // Priority 3: Apply default mode
301
+ return permissions.defaultMode || "allow";
302
+ }
303
+ /**
304
+ * Match a single command against a permission pattern
305
+ * Supports exact match and prefix match with ':*' wildcard
306
+ *
307
+ * Note: This method is called for individual commands after splitting,
308
+ * so it doesn't need to handle complex command chaining.
309
+ *
310
+ * Examples:
311
+ * - "ls:*" matches "ls", "ls -la", "ls:option"
312
+ * - "npm run test:*" matches "npm run test", "npm run test:unit", "npm run test arg"
313
+ *
314
+ * @param command - The command to match (should be a single command)
315
+ * @param pattern - The pattern to match against
316
+ * @returns true if command matches pattern
317
+ */
318
+ matchPattern(command, pattern) {
319
+ // Trim whitespace
320
+ command = command.trim();
321
+ pattern = pattern.trim();
322
+ // Exact match
323
+ if (pattern === command) {
324
+ return true;
325
+ }
326
+ // Prefix match with ':*' wildcard
327
+ if (pattern.endsWith(":*")) {
328
+ const prefix = pattern.slice(0, -2).trim();
329
+ // Match if command equals prefix or starts with prefix followed by space or colon
330
+ return command === prefix || command.startsWith(prefix) || command.startsWith(`${prefix}:`);
331
+ }
332
+ return false;
333
+ }
334
+ }
335
+ exports.BashAgent = BashAgent;
336
+ exports.default = BashAgent;
337
+ function getBashAgentSchema({ filepath }) {
338
+ const nestAgentSchema = (0, agent_yaml_js_1.getNestAgentSchema)({ filepath });
339
+ return (0, schema_js_1.camelizeSchema)(zod_1.default.object({
340
+ sandbox: (0, schema_js_1.optionalize)(zod_1.default.union([makeShapePropertiesOptions(sandbox_runtime_1.SandboxRuntimeConfigSchema, 2), zod_1.default.boolean()])),
341
+ inputKey: (0, schema_js_1.optionalize)(zod_1.default.string().describe("The input key for the bash script.")),
342
+ timeout: (0, schema_js_1.optionalize)(zod_1.default.number().describe("Timeout for script execution in milliseconds.")),
343
+ permissions: (0, schema_js_1.optionalize)((0, schema_js_1.camelizeSchema)(zod_1.default.object({
344
+ allow: (0, schema_js_1.optionalize)(zod_1.default.array(zod_1.default.string())),
345
+ deny: (0, schema_js_1.optionalize)(zod_1.default.array(zod_1.default.string())),
346
+ defaultMode: (0, schema_js_1.optionalize)(zod_1.default.enum(["allow", "ask", "deny"])),
347
+ guard: (0, schema_js_1.optionalize)(nestAgentSchema),
348
+ }))),
349
+ }));
350
+ }
351
+ function makeShapePropertiesOptions(schema, depth = 1) {
352
+ return zod_1.default.object(Object.fromEntries(Object.entries(schema.shape).map(([key, value]) => {
353
+ const isObject = value instanceof zod_1.ZodObject;
354
+ if (isObject && depth > 1) {
355
+ return [key, (0, schema_js_1.optionalize)(makeShapePropertiesOptions(value, depth - 1))];
356
+ }
357
+ return [key, (0, schema_js_1.optionalize)(value)];
358
+ })));
359
+ }
@@ -6,7 +6,7 @@ import { type StateManagementOptions } from "./type.js";
6
6
  * Configuration options for the Orchestrator Agent
7
7
  */
8
8
  export interface OrchestratorAgentOptions<I extends Message = Message, O extends Message = Message> extends Omit<AIAgentOptions<I, O>, "instructions"> {
9
- objective: PromptBuilder;
9
+ objective?: PromptBuilder;
10
10
  planner?: OrchestratorAgent<I, O>["planner"];
11
11
  worker?: OrchestratorAgent<I, O>["worker"];
12
12
  completer?: OrchestratorAgent<I, O>["completer"];
@@ -17,7 +17,7 @@ export interface OrchestratorAgentOptions<I extends Message = Message, O extends
17
17
  stateManagement?: StateManagementOptions;
18
18
  }
19
19
  export interface LoadOrchestratorAgentOptions<I extends Message = Message, O extends Message = Message> extends Omit<AIAgentOptions<I, O>, "instructions"> {
20
- objective: string | PromptBuilder | Instructions;
20
+ objective?: string | PromptBuilder | Instructions;
21
21
  planner?: NestAgentSchema | {
22
22
  instructions?: string | PromptBuilder | Instructions;
23
23
  };
@@ -62,7 +62,7 @@ export declare class OrchestratorAgent<I extends Message = Message, O extends Me
62
62
  * @param options - Configuration options for the Orchestrator Agent
63
63
  */
64
64
  constructor(options: OrchestratorAgentOptions<I, O>);
65
- private objective;
65
+ private objective?;
66
66
  private planner;
67
67
  private worker;
68
68
  private completer;
@@ -60,7 +60,7 @@ class OrchestratorAgent extends core_1.AIAgent {
60
60
  const valid = await schema.parseAsync(parsed);
61
61
  return new OrchestratorAgent({
62
62
  ...parsed,
63
- objective: (0, index_js_1.instructionsToPromptBuilder)(valid.objective),
63
+ objective: valid.objective && (0, index_js_1.instructionsToPromptBuilder)(valid.objective),
64
64
  planner: valid.planner
65
65
  ? (await (0, index_js_1.loadNestAgent)(filepath, valid.planner, options, {
66
66
  ...defaultPlannerOptions,
@@ -170,10 +170,10 @@ class OrchestratorAgent extends core_1.AIAgent {
170
170
  const model = this.model || options.model || options.context.model;
171
171
  if (!model)
172
172
  throw new Error("model is required to run OrchestratorAgent");
173
- const { prompt: objective } = await this.objective.buildPrompt({
173
+ const objective = (await this.objective?.buildPrompt({
174
174
  input,
175
175
  context: options.context,
176
- });
176
+ }))?.prompt;
177
177
  const executionState = { tasks: [] };
178
178
  let iterationCount = 0;
179
179
  const maxIterations = this.stateManagement?.maxIterations ?? type_js_1.DEFAULT_MAX_ITERATIONS;
@@ -193,13 +193,22 @@ class OrchestratorAgent extends core_1.AIAgent {
193
193
  iterationCount++;
194
194
  // Compress state for planner input if needed
195
195
  const compressedState = this.compressState(executionState);
196
- const plan = await this.invokeChildAgent(this.planner, { objective, executionState: compressedState }, { ...options, model, streaming: false });
196
+ const plan = await this.invokeChildAgent(this.planner, {
197
+ objective,
198
+ executionState: compressedState,
199
+ ...(0, type_utils_js_1.pick)(input, this.planner.inputKeys),
200
+ }, { ...options, model, streaming: false });
197
201
  if (plan.finished || !plan.nextTask) {
198
202
  break;
199
203
  }
200
204
  const task = plan.nextTask;
201
205
  const createdAt = Date.now();
202
- const taskResult = await this.invokeChildAgent(this.worker, { objective, executionState: compressedState, task }, { ...options, model, streaming: false })
206
+ const taskResult = await this.invokeChildAgent(this.worker, {
207
+ objective,
208
+ executionState: compressedState,
209
+ task,
210
+ ...(0, type_utils_js_1.pick)(input, this.worker.inputKeys),
211
+ }, { ...options, model, streaming: false })
203
212
  .then((res) => {
204
213
  if (res.error || res.success === false) {
205
214
  return { status: "failed", result: res.result, error: res.error };
@@ -219,7 +228,11 @@ class OrchestratorAgent extends core_1.AIAgent {
219
228
  }
220
229
  // Compress state for completer input if needed
221
230
  const compressedState = this.compressState(executionState);
222
- yield* await this.invokeChildAgent(this.completer, { objective, executionState: compressedState }, { ...options, model, streaming: true });
231
+ yield* await this.invokeChildAgent(this.completer, {
232
+ objective,
233
+ executionState: compressedState,
234
+ ...(0, type_utils_js_1.pick)(input, this.completer.inputKeys),
235
+ }, { ...options, model, streaming: true });
223
236
  }
224
237
  }
225
238
  exports.OrchestratorAgent = OrchestratorAgent;
@@ -228,7 +241,7 @@ function getOrchestratorAgentSchema({ filepath }) {
228
241
  const nestAgentSchema = (0, agent_yaml_js_1.getNestAgentSchema)({ filepath });
229
242
  const instructionsSchema = (0, agent_yaml_js_1.getInstructionsSchema)({ filepath });
230
243
  return (0, schema_js_1.camelizeSchema)(zod_1.z.object({
231
- objective: instructionsSchema,
244
+ objective: (0, schema_js_1.optionalize)(instructionsSchema),
232
245
  planner: (0, schema_js_1.optionalize)(nestAgentSchema),
233
246
  worker: (0, schema_js_1.optionalize)(nestAgentSchema),
234
247
  completer: (0, schema_js_1.optionalize)(nestAgentSchema),