@standardagents/builder 0.19.3 → 0.20.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/dist/index.js CHANGED
@@ -35,9 +35,10 @@ var __copyProps = (to, from, except, desc) => {
35
35
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
36
36
 
37
37
  // src/agents/types.ts
38
- var MAX_STEPS, MAX_RETRIES_PER_MODEL, TIMESTAMP_MULTIPLIER, STREAM_COOLDOWN, BACKOFF_BASE;
38
+ var SUBAGENT_INITIAL_ARGUMENTS_THREAD_PROPERTY, MAX_STEPS, MAX_RETRIES_PER_MODEL, TIMESTAMP_MULTIPLIER, STREAM_COOLDOWN, BACKOFF_BASE;
39
39
  var init_types = __esm({
40
40
  "src/agents/types.ts"() {
41
+ SUBAGENT_INITIAL_ARGUMENTS_THREAD_PROPERTY = "__agentbuilder_subagent_initial_arguments";
41
42
  MAX_STEPS = 250;
42
43
  MAX_RETRIES_PER_MODEL = 2;
43
44
  TIMESTAMP_MULTIPLIER = 1e3;
@@ -3622,9 +3623,8 @@ var init_ToolExecutor = __esm({
3622
3623
  // Pass through parent thread instance and metadata
3623
3624
  // Propagate namespace context to sub-flows for packed agent isolation
3624
3625
  namespaceContext: state.namespaceContext,
3626
+ arguments: args,
3625
3627
  context: {
3626
- ...args,
3627
- // Pass tool arguments for template interpolation
3628
3628
  // Pass parent tool config for response options
3629
3629
  __parentToolConfig: toolConfig,
3630
3630
  __parentToolName: call.function.name
@@ -3815,6 +3815,7 @@ ${errorLines.join("\n")}`);
3815
3815
  const targetAgentForCreate = createArgs?.agent;
3816
3816
  const builtinCreateMessage = createArgs?.message;
3817
3817
  const builtinCreateAttachmentValue = createArgs?.attachments;
3818
+ const builtinCreateInitialArguments = createArgs?.initialArguments ?? {};
3818
3819
  const registryAgentName = targetAgentForCreate || call.function.name;
3819
3820
  const packageId = getPackageId(state);
3820
3821
  let agentDef = null;
@@ -3913,6 +3914,20 @@ ${errorLines.join("\n")}`);
3913
3914
  args,
3914
3915
  initAttachmentsProperty
3915
3916
  );
3917
+ const initialArguments = builtinSubagentAction === "create" ? builtinCreateInitialArguments : args;
3918
+ const argumentValidationError = await this.validateSubagentArguments(
3919
+ state,
3920
+ agentDef,
3921
+ initialArguments,
3922
+ {
3923
+ agentName,
3924
+ receivesMessages,
3925
+ packageId
3926
+ }
3927
+ );
3928
+ if (argumentValidationError) {
3929
+ return argumentValidationError;
3930
+ }
3916
3931
  const existingChildren = await this.getChildrenRegistry(state);
3917
3932
  const activeInstances = existingChildren.filter(
3918
3933
  (entry) => entry.name === registryAgentName && entry.status !== "terminated"
@@ -3967,10 +3982,12 @@ ${errorLines.join("\n")}`);
3967
3982
  width: attachment.width,
3968
3983
  height: attachment.height
3969
3984
  })),
3985
+ initial_arguments: initialArguments,
3970
3986
  initial_agent_name: initialAgentName,
3971
3987
  agent_title: agentDef.title || registryAgentName,
3972
3988
  agent_description: agentDef.toolDescription || `Autonomous subagent ${agentDef.title || registryAgentName}`,
3973
- spawn_group_id: state.pendingMessageId ?? null
3989
+ spawn_group_id: state.pendingMessageId ?? null,
3990
+ arguments: initialArguments
3974
3991
  }
3975
3992
  });
3976
3993
  const requestId = pending && typeof pending.request_id === "string" ? pending.request_id : crypto.randomUUID();
@@ -3992,11 +4009,13 @@ ${errorLines.join("\n")}`);
3992
4009
  agent_name: agentName,
3993
4010
  parent: state.threadId,
3994
4011
  env: providedScopedEnv ?? void 0,
4012
+ properties: this.buildSubagentThreadProperties(initialArguments) ?? void 0,
3995
4013
  tags: initialAgentName ? [this.buildThreadNameTag(initialAgentName)] : void 0
3996
4014
  });
3997
4015
  const childThreadId = childThread.id;
3998
4016
  const durableId = state.env.AGENT_BUILDER_THREAD.idFromName(childThreadId);
3999
4017
  const stub = state.env.AGENT_BUILDER_THREAD.get(durableId);
4018
+ await this.persistSubagentArguments(stub, childThreadId, initialArguments);
4000
4019
  try {
4001
4020
  const { FlowEngine: FlowEngine2 } = await Promise.resolve().then(() => (init_FlowEngine(), FlowEngine_exports));
4002
4021
  const childState = ThreadStateImpl.fromThreadInstance(stub, {
@@ -4020,7 +4039,8 @@ ${errorLines.join("\n")}`);
4020
4039
  stub,
4021
4040
  initialMessageContent,
4022
4041
  receivesMessages,
4023
- initialMessageAttachments
4042
+ initialMessageAttachments,
4043
+ initialArguments
4024
4044
  );
4025
4045
  await this.upsertChildRegistry(state, {
4026
4046
  reference: childThreadId,
@@ -4031,6 +4051,7 @@ ${errorLines.join("\n")}`);
4031
4051
  blocking,
4032
4052
  ...resumable ? { parentCommunication } : {},
4033
4053
  status: "running",
4054
+ ...this.hasInitialArguments(initialArguments) ? { initialArguments } : {},
4034
4055
  ...initialAgentName ? { threadName: initialAgentName } : {},
4035
4056
  ...state.pendingMessageId ? { spawnGroupId: state.pendingMessageId } : {},
4036
4057
  createdAt: Date.now() * 1e3
@@ -4040,7 +4061,7 @@ ${errorLines.join("\n")}`);
4040
4061
  childThreadId,
4041
4062
  agentName,
4042
4063
  initialMessages,
4043
- {}
4064
+ initialArguments
4044
4065
  );
4045
4066
  const copiedAttachments = await this.copyAttachmentsBetweenThreads(
4046
4067
  stub,
@@ -4073,7 +4094,7 @@ ${errorLines.join("\n")}`);
4073
4094
  childThreadId,
4074
4095
  agentName,
4075
4096
  initialMessages,
4076
- {}
4097
+ initialArguments
4077
4098
  );
4078
4099
  const copiedAttachments = await this.copyAttachmentsBetweenThreads(
4079
4100
  stub,
@@ -4204,21 +4225,38 @@ ${errorLines.join("\n")}`);
4204
4225
  const message = typeof args.message === "string" ? args.message : "";
4205
4226
  const attachments = args.attachments;
4206
4227
  const name = typeof args.name === "string" ? args.name.trim() : "";
4228
+ const rawArguments = args.arguments;
4229
+ const initialArguments = this.isPlainRecord(rawArguments) ? rawArguments : {};
4207
4230
  if (!agent) {
4208
4231
  return {
4209
4232
  agent: "",
4210
4233
  message,
4211
4234
  attachments,
4212
4235
  name,
4236
+ initialArguments,
4237
+ arguments: initialArguments,
4213
4238
  error: `${SUBAGENT_CREATE_TOOL} requires agent.`
4214
4239
  };
4215
4240
  }
4241
+ if (rawArguments !== void 0 && (typeof rawArguments !== "object" || rawArguments === null || Array.isArray(rawArguments))) {
4242
+ return {
4243
+ agent,
4244
+ message,
4245
+ attachments,
4246
+ name,
4247
+ initialArguments,
4248
+ arguments: initialArguments,
4249
+ error: `${SUBAGENT_CREATE_TOOL} arguments must be an object when provided.`
4250
+ };
4251
+ }
4216
4252
  if (!message.trim()) {
4217
4253
  return {
4218
4254
  agent,
4219
4255
  message,
4220
4256
  attachments,
4221
4257
  name,
4258
+ initialArguments,
4259
+ arguments: initialArguments,
4222
4260
  error: `${SUBAGENT_CREATE_TOOL} requires message.`
4223
4261
  };
4224
4262
  }
@@ -4228,6 +4266,8 @@ ${errorLines.join("\n")}`);
4228
4266
  message,
4229
4267
  attachments,
4230
4268
  name,
4269
+ initialArguments,
4270
+ arguments: initialArguments,
4231
4271
  error: `${SUBAGENT_CREATE_TOOL} requires attachments (use [] when none).`
4232
4272
  };
4233
4273
  }
@@ -4237,6 +4277,8 @@ ${errorLines.join("\n")}`);
4237
4277
  message,
4238
4278
  attachments,
4239
4279
  name,
4280
+ initialArguments,
4281
+ arguments: initialArguments,
4240
4282
  error: `${SUBAGENT_CREATE_TOOL} name must be a string when provided.`
4241
4283
  };
4242
4284
  }
@@ -4246,10 +4288,141 @@ ${errorLines.join("\n")}`);
4246
4288
  message,
4247
4289
  attachments,
4248
4290
  name,
4291
+ initialArguments,
4292
+ arguments: initialArguments,
4249
4293
  error: `${SUBAGENT_CREATE_TOOL} requires name.`
4250
4294
  };
4251
4295
  }
4252
- return { agent, message, attachments, name };
4296
+ return {
4297
+ agent,
4298
+ message,
4299
+ attachments,
4300
+ name,
4301
+ initialArguments,
4302
+ arguments: initialArguments
4303
+ };
4304
+ }
4305
+ static hasInitialArguments(args) {
4306
+ return Object.keys(args).length > 0;
4307
+ }
4308
+ static isPlainRecord(value) {
4309
+ return !!value && typeof value === "object" && !Array.isArray(value);
4310
+ }
4311
+ static buildSubagentThreadProperties(initialArguments) {
4312
+ if (!this.hasInitialArguments(initialArguments)) {
4313
+ return null;
4314
+ }
4315
+ return {
4316
+ [SUBAGENT_INITIAL_ARGUMENTS_THREAD_PROPERTY]: initialArguments
4317
+ };
4318
+ }
4319
+ static qualifyPromptNameForAgent(promptName, agentName, packageId) {
4320
+ if (!promptName) {
4321
+ return null;
4322
+ }
4323
+ if (promptName.includes("/")) {
4324
+ return promptName;
4325
+ }
4326
+ const agentPackageId = agentName.includes("/") ? agentName.split("/")[0] : packageId;
4327
+ return agentPackageId ? `${agentPackageId}/${promptName}` : promptName;
4328
+ }
4329
+ static async validateSubagentInitialArguments(state, agentName, agentDef, receivesMessages, initialArguments, packageId) {
4330
+ return this.validateSubagentArguments(state, agentDef, initialArguments, {
4331
+ agentName,
4332
+ receivesMessages,
4333
+ packageId
4334
+ });
4335
+ }
4336
+ /**
4337
+ * Validate initial subagent arguments against the prompt schema on the child
4338
+ * side that receives parent messages.
4339
+ */
4340
+ static async validateSubagentArguments(state, agentDef, args, options = {}) {
4341
+ const receivesMessages = options.receivesMessages ?? "side_a";
4342
+ const promptName = receivesMessages === "side_b" ? agentDef.sideB?.prompt : agentDef.sideA?.prompt;
4343
+ const qualifiedPromptName = this.qualifyPromptNameForAgent(
4344
+ promptName,
4345
+ options.agentName ?? agentDef?.name ?? "",
4346
+ options.packageId
4347
+ );
4348
+ if (!qualifiedPromptName) {
4349
+ return null;
4350
+ }
4351
+ try {
4352
+ const promptDef = await state.thread.instance.loadPrompt(qualifiedPromptName);
4353
+ const schema = promptDef?.requiredSchema;
4354
+ if (!schema || typeof schema.safeParse !== "function") {
4355
+ return null;
4356
+ }
4357
+ const parsed = schema.safeParse(args);
4358
+ if (parsed.success) {
4359
+ return null;
4360
+ }
4361
+ const issues = Array.isArray(
4362
+ parsed.error?.issues
4363
+ ) ? parsed.error.issues : [];
4364
+ const missing = Array.from(
4365
+ new Set(
4366
+ issues.map(
4367
+ (issue) => Array.isArray(issue.path) ? issue.path.map(String).join(".") : String(issue.path ?? "")
4368
+ ).filter((path20) => path20.length > 0)
4369
+ )
4370
+ );
4371
+ const detail = issues.map((issue) => {
4372
+ const path20 = Array.isArray(issue.path) ? issue.path.map(String).join(".") : "";
4373
+ const message = typeof issue.message === "string" ? issue.message : "invalid value";
4374
+ return path20 ? `${path20}: ${message}` : message;
4375
+ }).join("; ") || parsed.error.message || "invalid arguments";
4376
+ const agentLabel = agentDef.title || agentDef.name || options.agentName || qualifiedPromptName;
4377
+ return {
4378
+ status: "error",
4379
+ error: `${SUBAGENT_CREATE_TOOL} arguments for "${agentLabel}" failed validation: ${detail}.`,
4380
+ error_code: "subagent_arguments_required",
4381
+ error_data: {
4382
+ agent: agentLabel,
4383
+ required: missing
4384
+ }
4385
+ };
4386
+ } catch {
4387
+ return null;
4388
+ }
4389
+ }
4390
+ static buildSubagentInitialArgumentsMessage(initialArguments, createdAt) {
4391
+ if (!this.hasInitialArguments(initialArguments)) {
4392
+ return null;
4393
+ }
4394
+ return {
4395
+ id: crypto.randomUUID(),
4396
+ role: "system",
4397
+ content: [
4398
+ "Persistent initial arguments for this subagent thread.",
4399
+ "These values were supplied by the parent when the child was created and remain in effect for side_a and side_b.",
4400
+ "They are available as ThreadState.arguments and prompt variables by their top-level keys.",
4401
+ "",
4402
+ this.formatInitialArguments(initialArguments)
4403
+ ].join("\n"),
4404
+ silent: true,
4405
+ metadata: {
4406
+ subagentInitialArguments: true
4407
+ },
4408
+ created_at: createdAt
4409
+ };
4410
+ }
4411
+ static formatInitialArguments(initialArguments) {
4412
+ return JSON.stringify(initialArguments, null, 2);
4413
+ }
4414
+ static async persistSubagentArguments(stub, childThreadId, args) {
4415
+ if (!args || Object.keys(args).length === 0) {
4416
+ return;
4417
+ }
4418
+ if (typeof stub.setSubagentArguments !== "function") {
4419
+ return;
4420
+ }
4421
+ try {
4422
+ await stub.setSubagentArguments(childThreadId, args);
4423
+ } catch (error) {
4424
+ console.error("[ToolExecutor] Failed to persist subagent arguments:", error);
4425
+ }
4253
4426
  }
4254
4427
  static getSubpromptToolConfig(config) {
4255
4428
  if (!config || typeof config !== "object") {
@@ -4329,7 +4502,7 @@ ${errorLines.join("\n")}`);
4329
4502
  await childThread.terminateThread(reference);
4330
4503
  }
4331
4504
  }
4332
- static async buildChildInvocationMessages(state, childThread, content, receivesMessages, parentAttachments) {
4505
+ static async buildChildInvocationMessages(state, childThread, content, receivesMessages, parentAttachments, initialArguments) {
4333
4506
  const copiedAttachments = await this.copyAttachmentsBetweenThreads(
4334
4507
  state.thread.instance,
4335
4508
  childThread,
@@ -4339,6 +4512,14 @@ ${errorLines.join("\n")}`);
4339
4512
  const targetRole = receivesMessages === "side_a" ? "user" : "assistant";
4340
4513
  const baseTimestamp = Date.now() * 1e3;
4341
4514
  const messages = [];
4515
+ const initialArgumentsMessage = this.buildSubagentInitialArgumentsMessage(
4516
+ initialArguments,
4517
+ baseTimestamp
4518
+ );
4519
+ if (initialArgumentsMessage) {
4520
+ messages.push(initialArgumentsMessage);
4521
+ }
4522
+ const timestampOffset = messages.length;
4342
4523
  for (let i = 0; i < copiedAttachments.length; i++) {
4343
4524
  const attachment = copiedAttachments[i];
4344
4525
  messages.push({
@@ -4347,7 +4528,7 @@ ${errorLines.join("\n")}`);
4347
4528
  content: `Initial asset attachment path: ${attachment.path}`,
4348
4529
  attachments: JSON.stringify([attachment]),
4349
4530
  silent: true,
4350
- created_at: baseTimestamp + i
4531
+ created_at: baseTimestamp + timestampOffset + i
4351
4532
  });
4352
4533
  }
4353
4534
  messages.push({
@@ -4357,7 +4538,7 @@ ${errorLines.join("\n")}`);
4357
4538
  // Keep binary refs on the silent path messages only to avoid rendering
4358
4539
  // duplicate attachments on the visible init message.
4359
4540
  attachments: void 0,
4360
- created_at: baseTimestamp + copiedAttachments.length
4541
+ created_at: baseTimestamp + timestampOffset + copiedAttachments.length
4361
4542
  });
4362
4543
  return messages;
4363
4544
  }
@@ -5849,6 +6030,7 @@ var init_FlowEngine = __esm({
5849
6030
  },
5850
6031
  queue: stateInput.queue || [],
5851
6032
  stream,
6033
+ arguments: stateInput.arguments || {},
5852
6034
  context: stateInput.context || {},
5853
6035
  retryCount: stateInput.retryCount || 0,
5854
6036
  retryReason: stateInput.retryReason,
@@ -5885,8 +6067,44 @@ var init_FlowEngine = __esm({
5885
6067
  } else {
5886
6068
  state.rootState = state;
5887
6069
  }
6070
+ try {
6071
+ const persistedArgs = await this.loadSubagentArguments(state);
6072
+ if (persistedArgs && Object.keys(persistedArgs).length > 0) {
6073
+ state.context = { ...persistedArgs, ...state.context || {} };
6074
+ }
6075
+ } catch (error) {
6076
+ console.error(
6077
+ "[FlowEngine] Failed to hydrate persisted subagent arguments:",
6078
+ error
6079
+ );
6080
+ }
5888
6081
  return state;
5889
6082
  }
6083
+ static getPromptInterpolationContext(state) {
6084
+ return {
6085
+ ...state.context || {},
6086
+ ...state.arguments || {}
6087
+ };
6088
+ }
6089
+ /**
6090
+ * Read persisted subagent invocation arguments from execution_state.
6091
+ * Returns an empty object for top-level threads or when none were stored.
6092
+ */
6093
+ static async loadSubagentArguments(state) {
6094
+ try {
6095
+ const cursor = await state.storage.sql.exec(
6096
+ `SELECT value FROM execution_state WHERE key = 'subagent_arguments' LIMIT 1`
6097
+ );
6098
+ const raw = cursor.toArray()[0]?.value;
6099
+ if (!raw) {
6100
+ return {};
6101
+ }
6102
+ const parsed = JSON.parse(raw);
6103
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
6104
+ } catch {
6105
+ return {};
6106
+ }
6107
+ }
5890
6108
  /**
5891
6109
  * Execute a single step
5892
6110
  */
@@ -6983,6 +7201,16 @@ var init_FlowEngine = __esm({
6983
7201
  const normalized = value.replace(/\s+/g, " ").trim();
6984
7202
  return normalized.length > 0 ? normalized : null;
6985
7203
  }
7204
+ static getRegistryInitialArguments(entry) {
7205
+ const value = entry.initialArguments;
7206
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
7207
+ return null;
7208
+ }
7209
+ return Object.keys(value).length > 0 ? value : null;
7210
+ }
7211
+ static formatInitialArgumentsForPrompt(initialArguments) {
7212
+ return JSON.stringify(initialArguments, null, 2);
7213
+ }
6986
7214
  static extractSubagentIdFromMetadata(metadata) {
6987
7215
  if (!metadata) {
6988
7216
  return null;
@@ -7057,7 +7285,7 @@ var init_FlowEngine = __esm({
7057
7285
  const includePastTools = state.prompt.include_past_tools ?? true;
7058
7286
  const promptContent = await this.interpolatePrompt(
7059
7287
  state.prompt.prompt,
7060
- state.context || {},
7288
+ this.getPromptInterpolationContext(state),
7061
7289
  state
7062
7290
  );
7063
7291
  const systemPromptText = await this.runAfterSystemMessageHook(
@@ -7215,10 +7443,13 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
7215
7443
  const lines = subagentRegistry.map((entry) => {
7216
7444
  const threadName = this.getRegistryThreadName(entry) ?? fallbackNameMap.get(entry.reference) ?? null;
7217
7445
  const displayName = threadName ? `${entry.name} (${threadName})` : entry.name;
7446
+ const initialArguments = this.getRegistryInitialArguments(entry);
7447
+ const argumentsLine = initialArguments ? `
7448
+ Initial arguments: ${this.formatInitialArgumentsForPrompt(initialArguments)}` : "";
7218
7449
  return `- Reference: ${entry.reference}
7219
7450
  Name: ${displayName}
7220
7451
  Description: ${entry.description}
7221
- Status: ${entry.status}`;
7452
+ Status: ${entry.status}${argumentsLine}`;
7222
7453
  });
7223
7454
  messages.push({
7224
7455
  role: "system",
@@ -7670,13 +7901,21 @@ ${lines.join("\n\n")}`
7670
7901
  const subagentConfig = this.isSubagentToolConfig(configEntry) ? configEntry : void 0;
7671
7902
  const blocking = subagentConfig?.blocking ?? true;
7672
7903
  const resumable = !!subagentConfig?.resumable && typeof subagentConfig.resumable === "object";
7904
+ const receivesMessages = subagentConfig?.resumable && typeof subagentConfig.resumable === "object" ? subagentConfig.resumable.receives_messages : "side_a";
7905
+ const argumentSchema = await this.resolveSubagentArgumentSchema(
7906
+ state,
7907
+ agentDef,
7908
+ receivesMessages,
7909
+ packageId
7910
+ );
7673
7911
  descriptors.push({
7674
7912
  name: toolName,
7675
7913
  title: agentDef.title || toolName,
7676
7914
  description: agentDef.toolDescription || `Run ${agentDef.title || toolName} subagent`,
7677
7915
  blocking,
7678
7916
  resumable,
7679
- maxInstances: subagentConfig?.resumable && typeof subagentConfig.resumable === "object" ? subagentConfig.resumable.maxInstances : void 0
7917
+ maxInstances: subagentConfig?.resumable && typeof subagentConfig.resumable === "object" ? subagentConfig.resumable.maxInstances : void 0,
7918
+ argumentSchema
7680
7919
  });
7681
7920
  }
7682
7921
  return descriptors;
@@ -7698,18 +7937,86 @@ ${lines.join("\n\n")}`
7698
7937
  return null;
7699
7938
  }
7700
7939
  }
7940
+ static qualifyPromptNameForPackage(promptName, packageId) {
7941
+ if (!promptName) {
7942
+ return null;
7943
+ }
7944
+ if (promptName.includes("/") || !packageId) {
7945
+ return promptName;
7946
+ }
7947
+ return `${packageId}/${promptName}`;
7948
+ }
7949
+ static async resolveSubagentArgumentSchema(state, agentDef, receivesMessages, packageId) {
7950
+ const promptName = receivesMessages === "side_b" ? agentDef.sideB?.prompt : agentDef.sideA?.prompt;
7951
+ const qualifiedPromptName = this.qualifyPromptNameForPackage(promptName, packageId);
7952
+ if (!qualifiedPromptName) {
7953
+ return void 0;
7954
+ }
7955
+ try {
7956
+ const promptDef = await state.thread.instance.loadPrompt(qualifiedPromptName);
7957
+ if (!promptDef?.requiredSchema) {
7958
+ return void 0;
7959
+ }
7960
+ const schema = this.zodToJsonSchema(promptDef.requiredSchema);
7961
+ return schema && typeof schema === "object" && !Array.isArray(schema) ? schema : void 0;
7962
+ } catch {
7963
+ return void 0;
7964
+ }
7965
+ }
7701
7966
  static isSubagentToolConfig(configEntry) {
7702
7967
  if (typeof configEntry !== "object" || configEntry === null) {
7703
7968
  return false;
7704
7969
  }
7705
7970
  return "blocking" in configEntry || "resumable" in configEntry || "immediate" in configEntry || "optional" in configEntry || "initUserMessageProperty" in configEntry || "initAttachmentsProperty" in configEntry || "initAgentNameProperty" in configEntry;
7706
7971
  }
7972
+ static normalizeSubagentArgumentSchema(schema) {
7973
+ const normalized = schema && typeof schema === "object" && !Array.isArray(schema) ? { ...schema } : {};
7974
+ normalized.type = "object";
7975
+ if (!normalized.properties || typeof normalized.properties !== "object") {
7976
+ normalized.properties = {};
7977
+ }
7978
+ if (!("additionalProperties" in normalized)) {
7979
+ normalized.additionalProperties = false;
7980
+ }
7981
+ return normalized;
7982
+ }
7983
+ static describeSubagentArguments(schema) {
7984
+ const normalized = this.normalizeSubagentArgumentSchema(schema);
7985
+ const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? Object.keys(normalized.properties) : [];
7986
+ const required = Array.isArray(normalized.required) ? normalized.required.filter((item) => typeof item === "string") : [];
7987
+ const optional = properties.filter((name) => !required.includes(name));
7988
+ const parts = [];
7989
+ if (required.length > 0) {
7990
+ parts.push(`required arguments: ${required.join(", ")}`);
7991
+ }
7992
+ if (optional.length > 0) {
7993
+ parts.push(`optional arguments: ${optional.join(", ")}`);
7994
+ }
7995
+ return parts.length > 0 ? parts.join("; ") : "no extra initial arguments";
7996
+ }
7997
+ static buildSubagentArgumentsSchema(promptSubagents) {
7998
+ const variants = promptSubagents.map((entry) => ({
7999
+ ...this.normalizeSubagentArgumentSchema(entry.argumentSchema),
8000
+ title: `${entry.name} initial arguments`,
8001
+ description: `Initial arguments for ${entry.name}. These values persist for the child thread lifetime.`
8002
+ }));
8003
+ if (variants.length === 1) {
8004
+ return variants[0];
8005
+ }
8006
+ return {
8007
+ type: "object",
8008
+ description: "Agent-specific initial arguments for the selected subagent. Use the schema matching the selected agent.",
8009
+ additionalProperties: false,
8010
+ anyOf: variants
8011
+ };
8012
+ }
7707
8013
  static buildSubagentCreateTool(promptSubagents) {
7708
8014
  const agentNames = promptSubagents.map((entry) => entry.name);
7709
8015
  const descriptionLines = promptSubagents.map((entry) => {
7710
8016
  const mode = `${entry.blocking ? "blocking" : "non-blocking"}, ${entry.resumable ? "resumable" : "non-resumable"}`;
7711
8017
  const maxInstances = typeof entry.maxInstances === "number" && entry.maxInstances > 0 ? `, max instances: ${entry.maxInstances}` : "";
7712
- return `- ${entry.name}: ${entry.description} (mode: ${mode}${maxInstances})`;
8018
+ const argumentSummary = this.describeSubagentArguments(entry.argumentSchema);
8019
+ return `- ${entry.name}: ${entry.description} (mode: ${mode}${maxInstances}; ${argumentSummary})`;
7713
8020
  });
7714
8021
  return {
7715
8022
  type: "function",
@@ -7719,6 +8026,7 @@ ${lines.join("\n\n")}`
7719
8026
  "Create and run a configured resumable dual_ai subagent.",
7720
8027
  "Available resumable subagents:",
7721
8028
  ...descriptionLines,
8029
+ "Provide any required invocation arguments via `arguments`; they persist for the life of the subagent thread.",
7722
8030
  "Use subagent_message for follow-up communication with resumable instances."
7723
8031
  ].join("\n"),
7724
8032
  parameters: {
@@ -7743,8 +8051,10 @@ ${lines.join("\n\n")}`
7743
8051
  name: {
7744
8052
  type: "string",
7745
8053
  description: "Required human-readable instance name for the spawned subagent thread. Use a concise stable label that identifies this child instance."
7746
- }
8054
+ },
8055
+ arguments: this.buildSubagentArgumentsSchema(promptSubagents)
7747
8056
  },
8057
+ additionalProperties: false,
7748
8058
  required: ["agent", "message", "attachments", "name"]
7749
8059
  }
7750
8060
  }
@@ -11547,6 +11857,7 @@ function runCodeViaThreadRpc(threadInstance, threadId, source, options) {
11547
11857
  var ThreadStateImpl, ExecutionStateImpl;
11548
11858
  var init_ThreadStateImpl = __esm({
11549
11859
  "src/agents/ThreadStateImpl.ts"() {
11860
+ init_types();
11550
11861
  init_utilities();
11551
11862
  init_code_execution();
11552
11863
  ThreadStateImpl = class _ThreadStateImpl {
@@ -11594,6 +11905,19 @@ var init_ThreadStateImpl = __esm({
11594
11905
  get terminated() {
11595
11906
  return this._terminatedCache;
11596
11907
  }
11908
+ get arguments() {
11909
+ if (this._flowState) {
11910
+ return this._flowState.arguments ?? this.getMetadataArguments();
11911
+ }
11912
+ return this.getMetadataArguments();
11913
+ }
11914
+ getMetadataArguments() {
11915
+ const value = this._metadata.properties?.[SUBAGENT_INITIAL_ARGUMENTS_THREAD_PROPERTY];
11916
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
11917
+ return {};
11918
+ }
11919
+ return value;
11920
+ }
11597
11921
  /**
11598
11922
  * Get the agent configuration from the underlying FlowState.
11599
11923
  * This is for backward compatibility with hooks that access state.agentConfig.
@@ -23258,6 +23582,39 @@ var DurableThread = class extends DurableObject {
23258
23582
  await this.setChildrenRegistry(next);
23259
23583
  }
23260
23584
  }
23585
+ /**
23586
+ * Persist the invocation arguments supplied when this subagent thread was
23587
+ * created. These are hydrated into prompt-interpolation context on every
23588
+ * activation of either side, so they survive for the life of the thread.
23589
+ */
23590
+ async setSubagentArguments(_threadId, args) {
23591
+ await this.ensureMigrated();
23592
+ const payload = args && typeof args === "object" && !Array.isArray(args) ? args : {};
23593
+ await this.ctx.storage.sql.exec(
23594
+ `INSERT OR REPLACE INTO execution_state (key, value) VALUES ('subagent_arguments', ?)`,
23595
+ JSON.stringify(payload)
23596
+ );
23597
+ }
23598
+ /**
23599
+ * Read the persisted invocation arguments for this subagent thread.
23600
+ * Returns an empty object when none were stored.
23601
+ */
23602
+ async getSubagentArguments(_threadId) {
23603
+ await this.ensureMigrated();
23604
+ const cursor = await this.ctx.storage.sql.exec(
23605
+ `SELECT value FROM execution_state WHERE key = 'subagent_arguments' LIMIT 1`
23606
+ );
23607
+ const raw = cursor.toArray()[0]?.value;
23608
+ if (!raw) {
23609
+ return {};
23610
+ }
23611
+ try {
23612
+ const parsed = JSON.parse(raw);
23613
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
23614
+ } catch {
23615
+ return {};
23616
+ }
23617
+ }
23261
23618
  asOptionalString(value) {
23262
23619
  if (typeof value !== "string") {
23263
23620
  return null;
@@ -25805,6 +26162,23 @@ ${resultContent}${attachmentSummary}`;
25805
26162
  console.error("[DurableThread] Alarm handler failed:", error);
25806
26163
  }
25807
26164
  }
26165
+ normalizePlainRecord(value) {
26166
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
26167
+ return null;
26168
+ }
26169
+ return value;
26170
+ }
26171
+ buildExecutionArguments(data, properties) {
26172
+ const dataRecord = this.normalizePlainRecord(data) ?? {};
26173
+ const persistedInitialArguments = this.normalizePlainRecord(
26174
+ properties?.[SUBAGENT_INITIAL_ARGUMENTS_THREAD_PROPERTY]
26175
+ );
26176
+ const initialArguments = persistedInitialArguments ?? dataRecord;
26177
+ if (!initialArguments || Object.keys(initialArguments).length === 0) {
26178
+ return {};
26179
+ }
26180
+ return initialArguments;
26181
+ }
25808
26182
  /**
25809
26183
  * Internal method: Execute a flow (called by alarm queue)
25810
26184
  * This is the actual execution logic, separate from the public execute() RPC method
@@ -25934,6 +26308,7 @@ ${resultContent}${attachmentSummary}`;
25934
26308
  emitMessageChunk: (messageId, chunk, depth) => this.broadcastMessageChunk(messageId, chunk, depth),
25935
26309
  emitTelemetry: (event) => this.broadcastTelemetry(event),
25936
26310
  emitEvent: (type, data2) => this.broadcastEvent(type, data2),
26311
+ arguments: this.buildExecutionArguments(data, thread.properties),
25937
26312
  rootMessageId,
25938
26313
  abortController: this.currentAbortController
25939
26314
  }, awaitCompletion);
@@ -27203,6 +27578,7 @@ async function decryptEnvs(encrypted, encryptionKey) {
27203
27578
  }
27204
27579
 
27205
27580
  // src/durable-objects/DurableAgentBuilder.ts
27581
+ init_types();
27206
27582
  var ENV_TYPES_PROPERTY = "__agentbuilder_env_types";
27207
27583
  var DurableAgentBuilder = class extends DurableObject {
27208
27584
  migratedToVersion = null;
@@ -27228,6 +27604,45 @@ var DurableAgentBuilder = class extends DurableObject {
27228
27604
  }
27229
27605
  return Object.keys(result).length > 0 ? result : null;
27230
27606
  }
27607
+ normalizePlainObject(input) {
27608
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
27609
+ return void 0;
27610
+ }
27611
+ const result = { ...input };
27612
+ return Object.keys(result).length > 0 ? result : void 0;
27613
+ }
27614
+ hasInitialArguments(args) {
27615
+ return Object.keys(args).length > 0;
27616
+ }
27617
+ buildSubagentThreadProperties(initialArguments) {
27618
+ if (!this.hasInitialArguments(initialArguments)) {
27619
+ return void 0;
27620
+ }
27621
+ return {
27622
+ [SUBAGENT_INITIAL_ARGUMENTS_THREAD_PROPERTY]: initialArguments
27623
+ };
27624
+ }
27625
+ buildSubagentInitialArgumentsMessage(initialArguments, createdAt) {
27626
+ if (!this.hasInitialArguments(initialArguments)) {
27627
+ return null;
27628
+ }
27629
+ return {
27630
+ id: crypto.randomUUID(),
27631
+ role: "system",
27632
+ content: [
27633
+ "Persistent initial arguments for this subagent thread.",
27634
+ "These values were supplied by the parent when the child was created and remain in effect for side_a and side_b.",
27635
+ "They are available as ThreadState.arguments and prompt variables by their top-level keys.",
27636
+ "",
27637
+ JSON.stringify(initialArguments, null, 2)
27638
+ ].join("\n"),
27639
+ silent: true,
27640
+ metadata: {
27641
+ subagentInitialArguments: true
27642
+ },
27643
+ created_at: createdAt
27644
+ };
27645
+ }
27231
27646
  normalizeEnvTypeRecord(input, env) {
27232
27647
  if (!input || typeof input !== "object" || !env) {
27233
27648
  return null;
@@ -28293,10 +28708,12 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
28293
28708
  initial_message_attachments: this.normalizePendingAttachments(
28294
28709
  params.payload.initial_message_attachments
28295
28710
  ),
28711
+ initial_arguments: this.normalizePlainObject(params.payload.initial_arguments),
28296
28712
  initial_agent_name: typeof params.payload.initial_agent_name === "string" ? params.payload.initial_agent_name : null,
28297
28713
  agent_title: typeof params.payload.agent_title === "string" ? params.payload.agent_title : null,
28298
28714
  agent_description: typeof params.payload.agent_description === "string" ? params.payload.agent_description : null,
28299
- spawn_group_id: typeof params.payload.spawn_group_id === "string" ? params.payload.spawn_group_id : null
28715
+ spawn_group_id: typeof params.payload.spawn_group_id === "string" ? params.payload.spawn_group_id : null,
28716
+ arguments: params.payload.arguments && typeof params.payload.arguments === "object" && !Array.isArray(params.payload.arguments) ? params.payload.arguments : {}
28300
28717
  };
28301
28718
  await this.ctx.storage.sql.exec(
28302
28719
  `INSERT INTO pending_subagent_env_requests (
@@ -28358,7 +28775,8 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
28358
28775
  initial_agent_name: typeof payloadObject.initial_agent_name === "string" ? payloadObject.initial_agent_name : null,
28359
28776
  agent_title: typeof payloadObject.agent_title === "string" ? payloadObject.agent_title : null,
28360
28777
  agent_description: typeof payloadObject.agent_description === "string" ? payloadObject.agent_description : null,
28361
- spawn_group_id: typeof payloadObject.spawn_group_id === "string" ? payloadObject.spawn_group_id : null
28778
+ spawn_group_id: typeof payloadObject.spawn_group_id === "string" ? payloadObject.spawn_group_id : null,
28779
+ arguments: payloadObject.arguments && typeof payloadObject.arguments === "object" && !Array.isArray(payloadObject.arguments) ? payloadObject.arguments : {}
28362
28780
  };
28363
28781
  let requiredRaw = [];
28364
28782
  let missingRaw = [];
@@ -28411,16 +28829,26 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
28411
28829
  );
28412
28830
  }
28413
28831
  const initialAgentName = typeof pending.payload.initial_agent_name === "string" ? pending.payload.initial_agent_name.replace(/\s+/g, " ").trim() : "";
28832
+ const initialArguments = this.normalizePlainObject(pending.payload.initial_arguments) ?? {};
28414
28833
  const childThread = await this.createThread({
28415
28834
  agent_name: pending.agent_name,
28416
28835
  parent: params.parent_thread_id,
28417
28836
  env: providedEnv,
28837
+ properties: this.buildSubagentThreadProperties(initialArguments),
28418
28838
  tags: initialAgentName ? [this.buildThreadNameTag(initialAgentName)] : void 0
28419
28839
  });
28420
28840
  const parentId = this.env.AGENT_BUILDER_THREAD.idFromName(params.parent_thread_id);
28421
28841
  const childId = this.env.AGENT_BUILDER_THREAD.idFromName(childThread.id);
28422
28842
  const parentThread = this.env.AGENT_BUILDER_THREAD.get(parentId);
28423
28843
  const childThreadStub = this.env.AGENT_BUILDER_THREAD.get(childId);
28844
+ const pendingArguments = pending.payload.arguments;
28845
+ if (pendingArguments && typeof pendingArguments === "object" && !Array.isArray(pendingArguments) && Object.keys(pendingArguments).length > 0 && typeof childThreadStub.setSubagentArguments === "function") {
28846
+ try {
28847
+ await childThreadStub.setSubagentArguments(childThread.id, pendingArguments);
28848
+ } catch (error) {
28849
+ console.error("[DurableAgentBuilder] Failed to persist subagent arguments:", error);
28850
+ }
28851
+ }
28424
28852
  const canCopyInitialAttachments = typeof parentThread.readFile === "function" && typeof parentThread.statFile === "function" && typeof childThreadStub.writeFile === "function";
28425
28853
  const initialAttachments = canCopyInitialAttachments ? await this.copyPendingAttachmentsBetweenThreads(
28426
28854
  {
@@ -28435,6 +28863,14 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
28435
28863
  const targetRole = pending.payload.receives_messages === "side_b" ? "assistant" : "user";
28436
28864
  const baseTimestamp = Date.now() * 1e3;
28437
28865
  const initialMessages = [];
28866
+ const initialArgumentsMessage = this.buildSubagentInitialArgumentsMessage(
28867
+ initialArguments,
28868
+ baseTimestamp
28869
+ );
28870
+ if (initialArgumentsMessage) {
28871
+ initialMessages.push(initialArgumentsMessage);
28872
+ }
28873
+ const timestampOffset = initialMessages.length;
28438
28874
  for (let i = 0; i < initialAttachments.length; i++) {
28439
28875
  const attachment = initialAttachments[i];
28440
28876
  initialMessages.push({
@@ -28443,7 +28879,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
28443
28879
  content: `Initial asset attachment path: ${attachment.path}`,
28444
28880
  attachments: JSON.stringify([attachment]),
28445
28881
  silent: true,
28446
- created_at: baseTimestamp + i
28882
+ created_at: baseTimestamp + timestampOffset + i
28447
28883
  });
28448
28884
  }
28449
28885
  initialMessages.push({
@@ -28451,7 +28887,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
28451
28887
  role: targetRole,
28452
28888
  content: pending.payload.initial_message_content,
28453
28889
  attachments: void 0,
28454
- created_at: baseTimestamp + initialAttachments.length
28890
+ created_at: baseTimestamp + timestampOffset + initialAttachments.length
28455
28891
  });
28456
28892
  if (typeof parentThread.upsertChildRegistry === "function") {
28457
28893
  await parentThread.upsertChildRegistry(params.parent_thread_id, {
@@ -28462,6 +28898,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
28462
28898
  resumable: pending.payload.resumable,
28463
28899
  blocking: pending.payload.blocking,
28464
28900
  status: "running",
28901
+ ...this.hasInitialArguments(initialArguments) ? { initialArguments } : {},
28465
28902
  ...initialAgentName ? { threadName: initialAgentName } : {},
28466
28903
  ...pending.payload.spawn_group_id ? { spawnGroupId: pending.payload.spawn_group_id } : {},
28467
28904
  createdAt: Date.now() * 1e3
@@ -28476,7 +28913,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
28476
28913
  childThread.id,
28477
28914
  pending.agent_name,
28478
28915
  initialMessages,
28479
- {}
28916
+ initialArguments
28480
28917
  );
28481
28918
  const resultAttachments = Array.isArray(childResult.attachments) && childResult.attachments.length > 0 && typeof childThreadStub.readFile === "function" && typeof childThreadStub.statFile === "function" && typeof parentThread.writeFile === "function" ? await this.copyPendingAttachmentsBetweenThreads(
28482
28919
  {