@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/runtime.js CHANGED
@@ -26,9 +26,10 @@ var __copyProps = (to, from, except, desc) => {
26
26
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
27
 
28
28
  // src/agents/types.ts
29
- var MAX_STEPS, MAX_RETRIES_PER_MODEL, TIMESTAMP_MULTIPLIER, STREAM_COOLDOWN, BACKOFF_BASE;
29
+ var SUBAGENT_INITIAL_ARGUMENTS_THREAD_PROPERTY, MAX_STEPS, MAX_RETRIES_PER_MODEL, TIMESTAMP_MULTIPLIER, STREAM_COOLDOWN, BACKOFF_BASE;
30
30
  var init_types = __esm({
31
31
  "src/agents/types.ts"() {
32
+ SUBAGENT_INITIAL_ARGUMENTS_THREAD_PROPERTY = "__agentbuilder_subagent_initial_arguments";
32
33
  MAX_STEPS = 250;
33
34
  MAX_RETRIES_PER_MODEL = 2;
34
35
  TIMESTAMP_MULTIPLIER = 1e3;
@@ -3613,9 +3614,8 @@ var init_ToolExecutor = __esm({
3613
3614
  // Pass through parent thread instance and metadata
3614
3615
  // Propagate namespace context to sub-flows for packed agent isolation
3615
3616
  namespaceContext: state.namespaceContext,
3617
+ arguments: args,
3616
3618
  context: {
3617
- ...args,
3618
- // Pass tool arguments for template interpolation
3619
3619
  // Pass parent tool config for response options
3620
3620
  __parentToolConfig: toolConfig,
3621
3621
  __parentToolName: call.function.name
@@ -3806,6 +3806,7 @@ ${errorLines.join("\n")}`);
3806
3806
  const targetAgentForCreate = createArgs?.agent;
3807
3807
  const builtinCreateMessage = createArgs?.message;
3808
3808
  const builtinCreateAttachmentValue = createArgs?.attachments;
3809
+ const builtinCreateInitialArguments = createArgs?.initialArguments ?? {};
3809
3810
  const registryAgentName = targetAgentForCreate || call.function.name;
3810
3811
  const packageId = getPackageId(state);
3811
3812
  let agentDef = null;
@@ -3904,6 +3905,20 @@ ${errorLines.join("\n")}`);
3904
3905
  args,
3905
3906
  initAttachmentsProperty
3906
3907
  );
3908
+ const initialArguments = builtinSubagentAction === "create" ? builtinCreateInitialArguments : args;
3909
+ const argumentValidationError = await this.validateSubagentArguments(
3910
+ state,
3911
+ agentDef,
3912
+ initialArguments,
3913
+ {
3914
+ agentName,
3915
+ receivesMessages,
3916
+ packageId
3917
+ }
3918
+ );
3919
+ if (argumentValidationError) {
3920
+ return argumentValidationError;
3921
+ }
3907
3922
  const existingChildren = await this.getChildrenRegistry(state);
3908
3923
  const activeInstances = existingChildren.filter(
3909
3924
  (entry) => entry.name === registryAgentName && entry.status !== "terminated"
@@ -3958,10 +3973,12 @@ ${errorLines.join("\n")}`);
3958
3973
  width: attachment.width,
3959
3974
  height: attachment.height
3960
3975
  })),
3976
+ initial_arguments: initialArguments,
3961
3977
  initial_agent_name: initialAgentName,
3962
3978
  agent_title: agentDef.title || registryAgentName,
3963
3979
  agent_description: agentDef.toolDescription || `Autonomous subagent ${agentDef.title || registryAgentName}`,
3964
- spawn_group_id: state.pendingMessageId ?? null
3980
+ spawn_group_id: state.pendingMessageId ?? null,
3981
+ arguments: initialArguments
3965
3982
  }
3966
3983
  });
3967
3984
  const requestId = pending && typeof pending.request_id === "string" ? pending.request_id : crypto.randomUUID();
@@ -3983,11 +4000,13 @@ ${errorLines.join("\n")}`);
3983
4000
  agent_name: agentName,
3984
4001
  parent: state.threadId,
3985
4002
  env: providedScopedEnv ?? void 0,
4003
+ properties: this.buildSubagentThreadProperties(initialArguments) ?? void 0,
3986
4004
  tags: initialAgentName ? [this.buildThreadNameTag(initialAgentName)] : void 0
3987
4005
  });
3988
4006
  const childThreadId = childThread.id;
3989
4007
  const durableId = state.env.AGENT_BUILDER_THREAD.idFromName(childThreadId);
3990
4008
  const stub = state.env.AGENT_BUILDER_THREAD.get(durableId);
4009
+ await this.persistSubagentArguments(stub, childThreadId, initialArguments);
3991
4010
  try {
3992
4011
  const { FlowEngine: FlowEngine2 } = await Promise.resolve().then(() => (init_FlowEngine(), FlowEngine_exports));
3993
4012
  const childState = ThreadStateImpl.fromThreadInstance(stub, {
@@ -4011,7 +4030,8 @@ ${errorLines.join("\n")}`);
4011
4030
  stub,
4012
4031
  initialMessageContent,
4013
4032
  receivesMessages,
4014
- initialMessageAttachments
4033
+ initialMessageAttachments,
4034
+ initialArguments
4015
4035
  );
4016
4036
  await this.upsertChildRegistry(state, {
4017
4037
  reference: childThreadId,
@@ -4022,6 +4042,7 @@ ${errorLines.join("\n")}`);
4022
4042
  blocking,
4023
4043
  ...resumable ? { parentCommunication } : {},
4024
4044
  status: "running",
4045
+ ...this.hasInitialArguments(initialArguments) ? { initialArguments } : {},
4025
4046
  ...initialAgentName ? { threadName: initialAgentName } : {},
4026
4047
  ...state.pendingMessageId ? { spawnGroupId: state.pendingMessageId } : {},
4027
4048
  createdAt: Date.now() * 1e3
@@ -4031,7 +4052,7 @@ ${errorLines.join("\n")}`);
4031
4052
  childThreadId,
4032
4053
  agentName,
4033
4054
  initialMessages,
4034
- {}
4055
+ initialArguments
4035
4056
  );
4036
4057
  const copiedAttachments = await this.copyAttachmentsBetweenThreads(
4037
4058
  stub,
@@ -4064,7 +4085,7 @@ ${errorLines.join("\n")}`);
4064
4085
  childThreadId,
4065
4086
  agentName,
4066
4087
  initialMessages,
4067
- {}
4088
+ initialArguments
4068
4089
  );
4069
4090
  const copiedAttachments = await this.copyAttachmentsBetweenThreads(
4070
4091
  stub,
@@ -4195,21 +4216,38 @@ ${errorLines.join("\n")}`);
4195
4216
  const message = typeof args.message === "string" ? args.message : "";
4196
4217
  const attachments = args.attachments;
4197
4218
  const name = typeof args.name === "string" ? args.name.trim() : "";
4219
+ const rawArguments = args.arguments;
4220
+ const initialArguments = this.isPlainRecord(rawArguments) ? rawArguments : {};
4198
4221
  if (!agent) {
4199
4222
  return {
4200
4223
  agent: "",
4201
4224
  message,
4202
4225
  attachments,
4203
4226
  name,
4227
+ initialArguments,
4228
+ arguments: initialArguments,
4204
4229
  error: `${SUBAGENT_CREATE_TOOL} requires agent.`
4205
4230
  };
4206
4231
  }
4232
+ if (rawArguments !== void 0 && (typeof rawArguments !== "object" || rawArguments === null || Array.isArray(rawArguments))) {
4233
+ return {
4234
+ agent,
4235
+ message,
4236
+ attachments,
4237
+ name,
4238
+ initialArguments,
4239
+ arguments: initialArguments,
4240
+ error: `${SUBAGENT_CREATE_TOOL} arguments must be an object when provided.`
4241
+ };
4242
+ }
4207
4243
  if (!message.trim()) {
4208
4244
  return {
4209
4245
  agent,
4210
4246
  message,
4211
4247
  attachments,
4212
4248
  name,
4249
+ initialArguments,
4250
+ arguments: initialArguments,
4213
4251
  error: `${SUBAGENT_CREATE_TOOL} requires message.`
4214
4252
  };
4215
4253
  }
@@ -4219,6 +4257,8 @@ ${errorLines.join("\n")}`);
4219
4257
  message,
4220
4258
  attachments,
4221
4259
  name,
4260
+ initialArguments,
4261
+ arguments: initialArguments,
4222
4262
  error: `${SUBAGENT_CREATE_TOOL} requires attachments (use [] when none).`
4223
4263
  };
4224
4264
  }
@@ -4228,6 +4268,8 @@ ${errorLines.join("\n")}`);
4228
4268
  message,
4229
4269
  attachments,
4230
4270
  name,
4271
+ initialArguments,
4272
+ arguments: initialArguments,
4231
4273
  error: `${SUBAGENT_CREATE_TOOL} name must be a string when provided.`
4232
4274
  };
4233
4275
  }
@@ -4237,10 +4279,141 @@ ${errorLines.join("\n")}`);
4237
4279
  message,
4238
4280
  attachments,
4239
4281
  name,
4282
+ initialArguments,
4283
+ arguments: initialArguments,
4240
4284
  error: `${SUBAGENT_CREATE_TOOL} requires name.`
4241
4285
  };
4242
4286
  }
4243
- return { agent, message, attachments, name };
4287
+ return {
4288
+ agent,
4289
+ message,
4290
+ attachments,
4291
+ name,
4292
+ initialArguments,
4293
+ arguments: initialArguments
4294
+ };
4295
+ }
4296
+ static hasInitialArguments(args) {
4297
+ return Object.keys(args).length > 0;
4298
+ }
4299
+ static isPlainRecord(value) {
4300
+ return !!value && typeof value === "object" && !Array.isArray(value);
4301
+ }
4302
+ static buildSubagentThreadProperties(initialArguments) {
4303
+ if (!this.hasInitialArguments(initialArguments)) {
4304
+ return null;
4305
+ }
4306
+ return {
4307
+ [SUBAGENT_INITIAL_ARGUMENTS_THREAD_PROPERTY]: initialArguments
4308
+ };
4309
+ }
4310
+ static qualifyPromptNameForAgent(promptName, agentName, packageId) {
4311
+ if (!promptName) {
4312
+ return null;
4313
+ }
4314
+ if (promptName.includes("/")) {
4315
+ return promptName;
4316
+ }
4317
+ const agentPackageId = agentName.includes("/") ? agentName.split("/")[0] : packageId;
4318
+ return agentPackageId ? `${agentPackageId}/${promptName}` : promptName;
4319
+ }
4320
+ static async validateSubagentInitialArguments(state, agentName, agentDef, receivesMessages, initialArguments, packageId) {
4321
+ return this.validateSubagentArguments(state, agentDef, initialArguments, {
4322
+ agentName,
4323
+ receivesMessages,
4324
+ packageId
4325
+ });
4326
+ }
4327
+ /**
4328
+ * Validate initial subagent arguments against the prompt schema on the child
4329
+ * side that receives parent messages.
4330
+ */
4331
+ static async validateSubagentArguments(state, agentDef, args, options = {}) {
4332
+ const receivesMessages = options.receivesMessages ?? "side_a";
4333
+ const promptName = receivesMessages === "side_b" ? agentDef.sideB?.prompt : agentDef.sideA?.prompt;
4334
+ const qualifiedPromptName = this.qualifyPromptNameForAgent(
4335
+ promptName,
4336
+ options.agentName ?? agentDef?.name ?? "",
4337
+ options.packageId
4338
+ );
4339
+ if (!qualifiedPromptName) {
4340
+ return null;
4341
+ }
4342
+ try {
4343
+ const promptDef = await state.thread.instance.loadPrompt(qualifiedPromptName);
4344
+ const schema = promptDef?.requiredSchema;
4345
+ if (!schema || typeof schema.safeParse !== "function") {
4346
+ return null;
4347
+ }
4348
+ const parsed = schema.safeParse(args);
4349
+ if (parsed.success) {
4350
+ return null;
4351
+ }
4352
+ const issues = Array.isArray(
4353
+ parsed.error?.issues
4354
+ ) ? parsed.error.issues : [];
4355
+ const missing = Array.from(
4356
+ new Set(
4357
+ issues.map(
4358
+ (issue) => Array.isArray(issue.path) ? issue.path.map(String).join(".") : String(issue.path ?? "")
4359
+ ).filter((path) => path.length > 0)
4360
+ )
4361
+ );
4362
+ const detail = issues.map((issue) => {
4363
+ const path = Array.isArray(issue.path) ? issue.path.map(String).join(".") : "";
4364
+ const message = typeof issue.message === "string" ? issue.message : "invalid value";
4365
+ return path ? `${path}: ${message}` : message;
4366
+ }).join("; ") || parsed.error.message || "invalid arguments";
4367
+ const agentLabel = agentDef.title || agentDef.name || options.agentName || qualifiedPromptName;
4368
+ return {
4369
+ status: "error",
4370
+ error: `${SUBAGENT_CREATE_TOOL} arguments for "${agentLabel}" failed validation: ${detail}.`,
4371
+ error_code: "subagent_arguments_required",
4372
+ error_data: {
4373
+ agent: agentLabel,
4374
+ required: missing
4375
+ }
4376
+ };
4377
+ } catch {
4378
+ return null;
4379
+ }
4380
+ }
4381
+ static buildSubagentInitialArgumentsMessage(initialArguments, createdAt) {
4382
+ if (!this.hasInitialArguments(initialArguments)) {
4383
+ return null;
4384
+ }
4385
+ return {
4386
+ id: crypto.randomUUID(),
4387
+ role: "system",
4388
+ content: [
4389
+ "Persistent initial arguments for this subagent thread.",
4390
+ "These values were supplied by the parent when the child was created and remain in effect for side_a and side_b.",
4391
+ "They are available as ThreadState.arguments and prompt variables by their top-level keys.",
4392
+ "",
4393
+ this.formatInitialArguments(initialArguments)
4394
+ ].join("\n"),
4395
+ silent: true,
4396
+ metadata: {
4397
+ subagentInitialArguments: true
4398
+ },
4399
+ created_at: createdAt
4400
+ };
4401
+ }
4402
+ static formatInitialArguments(initialArguments) {
4403
+ return JSON.stringify(initialArguments, null, 2);
4404
+ }
4405
+ static async persistSubagentArguments(stub, childThreadId, args) {
4406
+ if (!args || Object.keys(args).length === 0) {
4407
+ return;
4408
+ }
4409
+ if (typeof stub.setSubagentArguments !== "function") {
4410
+ return;
4411
+ }
4412
+ try {
4413
+ await stub.setSubagentArguments(childThreadId, args);
4414
+ } catch (error) {
4415
+ console.error("[ToolExecutor] Failed to persist subagent arguments:", error);
4416
+ }
4244
4417
  }
4245
4418
  static getSubpromptToolConfig(config) {
4246
4419
  if (!config || typeof config !== "object") {
@@ -4320,7 +4493,7 @@ ${errorLines.join("\n")}`);
4320
4493
  await childThread.terminateThread(reference);
4321
4494
  }
4322
4495
  }
4323
- static async buildChildInvocationMessages(state, childThread, content, receivesMessages, parentAttachments) {
4496
+ static async buildChildInvocationMessages(state, childThread, content, receivesMessages, parentAttachments, initialArguments) {
4324
4497
  const copiedAttachments = await this.copyAttachmentsBetweenThreads(
4325
4498
  state.thread.instance,
4326
4499
  childThread,
@@ -4330,6 +4503,14 @@ ${errorLines.join("\n")}`);
4330
4503
  const targetRole = receivesMessages === "side_a" ? "user" : "assistant";
4331
4504
  const baseTimestamp = Date.now() * 1e3;
4332
4505
  const messages = [];
4506
+ const initialArgumentsMessage = this.buildSubagentInitialArgumentsMessage(
4507
+ initialArguments,
4508
+ baseTimestamp
4509
+ );
4510
+ if (initialArgumentsMessage) {
4511
+ messages.push(initialArgumentsMessage);
4512
+ }
4513
+ const timestampOffset = messages.length;
4333
4514
  for (let i = 0; i < copiedAttachments.length; i++) {
4334
4515
  const attachment = copiedAttachments[i];
4335
4516
  messages.push({
@@ -4338,7 +4519,7 @@ ${errorLines.join("\n")}`);
4338
4519
  content: `Initial asset attachment path: ${attachment.path}`,
4339
4520
  attachments: JSON.stringify([attachment]),
4340
4521
  silent: true,
4341
- created_at: baseTimestamp + i
4522
+ created_at: baseTimestamp + timestampOffset + i
4342
4523
  });
4343
4524
  }
4344
4525
  messages.push({
@@ -4348,7 +4529,7 @@ ${errorLines.join("\n")}`);
4348
4529
  // Keep binary refs on the silent path messages only to avoid rendering
4349
4530
  // duplicate attachments on the visible init message.
4350
4531
  attachments: void 0,
4351
- created_at: baseTimestamp + copiedAttachments.length
4532
+ created_at: baseTimestamp + timestampOffset + copiedAttachments.length
4352
4533
  });
4353
4534
  return messages;
4354
4535
  }
@@ -5840,6 +6021,7 @@ var init_FlowEngine = __esm({
5840
6021
  },
5841
6022
  queue: stateInput.queue || [],
5842
6023
  stream,
6024
+ arguments: stateInput.arguments || {},
5843
6025
  context: stateInput.context || {},
5844
6026
  retryCount: stateInput.retryCount || 0,
5845
6027
  retryReason: stateInput.retryReason,
@@ -5876,8 +6058,44 @@ var init_FlowEngine = __esm({
5876
6058
  } else {
5877
6059
  state.rootState = state;
5878
6060
  }
6061
+ try {
6062
+ const persistedArgs = await this.loadSubagentArguments(state);
6063
+ if (persistedArgs && Object.keys(persistedArgs).length > 0) {
6064
+ state.context = { ...persistedArgs, ...state.context || {} };
6065
+ }
6066
+ } catch (error) {
6067
+ console.error(
6068
+ "[FlowEngine] Failed to hydrate persisted subagent arguments:",
6069
+ error
6070
+ );
6071
+ }
5879
6072
  return state;
5880
6073
  }
6074
+ static getPromptInterpolationContext(state) {
6075
+ return {
6076
+ ...state.context || {},
6077
+ ...state.arguments || {}
6078
+ };
6079
+ }
6080
+ /**
6081
+ * Read persisted subagent invocation arguments from execution_state.
6082
+ * Returns an empty object for top-level threads or when none were stored.
6083
+ */
6084
+ static async loadSubagentArguments(state) {
6085
+ try {
6086
+ const cursor = await state.storage.sql.exec(
6087
+ `SELECT value FROM execution_state WHERE key = 'subagent_arguments' LIMIT 1`
6088
+ );
6089
+ const raw = cursor.toArray()[0]?.value;
6090
+ if (!raw) {
6091
+ return {};
6092
+ }
6093
+ const parsed = JSON.parse(raw);
6094
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
6095
+ } catch {
6096
+ return {};
6097
+ }
6098
+ }
5881
6099
  /**
5882
6100
  * Execute a single step
5883
6101
  */
@@ -6974,6 +7192,16 @@ var init_FlowEngine = __esm({
6974
7192
  const normalized = value.replace(/\s+/g, " ").trim();
6975
7193
  return normalized.length > 0 ? normalized : null;
6976
7194
  }
7195
+ static getRegistryInitialArguments(entry) {
7196
+ const value = entry.initialArguments;
7197
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
7198
+ return null;
7199
+ }
7200
+ return Object.keys(value).length > 0 ? value : null;
7201
+ }
7202
+ static formatInitialArgumentsForPrompt(initialArguments) {
7203
+ return JSON.stringify(initialArguments, null, 2);
7204
+ }
6977
7205
  static extractSubagentIdFromMetadata(metadata) {
6978
7206
  if (!metadata) {
6979
7207
  return null;
@@ -7048,7 +7276,7 @@ var init_FlowEngine = __esm({
7048
7276
  const includePastTools = state.prompt.include_past_tools ?? true;
7049
7277
  const promptContent = await this.interpolatePrompt(
7050
7278
  state.prompt.prompt,
7051
- state.context || {},
7279
+ this.getPromptInterpolationContext(state),
7052
7280
  state
7053
7281
  );
7054
7282
  const systemPromptText = await this.runAfterSystemMessageHook(
@@ -7206,10 +7434,13 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
7206
7434
  const lines = subagentRegistry.map((entry) => {
7207
7435
  const threadName = this.getRegistryThreadName(entry) ?? fallbackNameMap.get(entry.reference) ?? null;
7208
7436
  const displayName = threadName ? `${entry.name} (${threadName})` : entry.name;
7437
+ const initialArguments = this.getRegistryInitialArguments(entry);
7438
+ const argumentsLine = initialArguments ? `
7439
+ Initial arguments: ${this.formatInitialArgumentsForPrompt(initialArguments)}` : "";
7209
7440
  return `- Reference: ${entry.reference}
7210
7441
  Name: ${displayName}
7211
7442
  Description: ${entry.description}
7212
- Status: ${entry.status}`;
7443
+ Status: ${entry.status}${argumentsLine}`;
7213
7444
  });
7214
7445
  messages.push({
7215
7446
  role: "system",
@@ -7661,13 +7892,21 @@ ${lines.join("\n\n")}`
7661
7892
  const subagentConfig = this.isSubagentToolConfig(configEntry) ? configEntry : void 0;
7662
7893
  const blocking = subagentConfig?.blocking ?? true;
7663
7894
  const resumable = !!subagentConfig?.resumable && typeof subagentConfig.resumable === "object";
7895
+ const receivesMessages = subagentConfig?.resumable && typeof subagentConfig.resumable === "object" ? subagentConfig.resumable.receives_messages : "side_a";
7896
+ const argumentSchema = await this.resolveSubagentArgumentSchema(
7897
+ state,
7898
+ agentDef,
7899
+ receivesMessages,
7900
+ packageId
7901
+ );
7664
7902
  descriptors.push({
7665
7903
  name: toolName,
7666
7904
  title: agentDef.title || toolName,
7667
7905
  description: agentDef.toolDescription || `Run ${agentDef.title || toolName} subagent`,
7668
7906
  blocking,
7669
7907
  resumable,
7670
- maxInstances: subagentConfig?.resumable && typeof subagentConfig.resumable === "object" ? subagentConfig.resumable.maxInstances : void 0
7908
+ maxInstances: subagentConfig?.resumable && typeof subagentConfig.resumable === "object" ? subagentConfig.resumable.maxInstances : void 0,
7909
+ argumentSchema
7671
7910
  });
7672
7911
  }
7673
7912
  return descriptors;
@@ -7689,18 +7928,86 @@ ${lines.join("\n\n")}`
7689
7928
  return null;
7690
7929
  }
7691
7930
  }
7931
+ static qualifyPromptNameForPackage(promptName, packageId) {
7932
+ if (!promptName) {
7933
+ return null;
7934
+ }
7935
+ if (promptName.includes("/") || !packageId) {
7936
+ return promptName;
7937
+ }
7938
+ return `${packageId}/${promptName}`;
7939
+ }
7940
+ static async resolveSubagentArgumentSchema(state, agentDef, receivesMessages, packageId) {
7941
+ const promptName = receivesMessages === "side_b" ? agentDef.sideB?.prompt : agentDef.sideA?.prompt;
7942
+ const qualifiedPromptName = this.qualifyPromptNameForPackage(promptName, packageId);
7943
+ if (!qualifiedPromptName) {
7944
+ return void 0;
7945
+ }
7946
+ try {
7947
+ const promptDef = await state.thread.instance.loadPrompt(qualifiedPromptName);
7948
+ if (!promptDef?.requiredSchema) {
7949
+ return void 0;
7950
+ }
7951
+ const schema = this.zodToJsonSchema(promptDef.requiredSchema);
7952
+ return schema && typeof schema === "object" && !Array.isArray(schema) ? schema : void 0;
7953
+ } catch {
7954
+ return void 0;
7955
+ }
7956
+ }
7692
7957
  static isSubagentToolConfig(configEntry) {
7693
7958
  if (typeof configEntry !== "object" || configEntry === null) {
7694
7959
  return false;
7695
7960
  }
7696
7961
  return "blocking" in configEntry || "resumable" in configEntry || "immediate" in configEntry || "optional" in configEntry || "initUserMessageProperty" in configEntry || "initAttachmentsProperty" in configEntry || "initAgentNameProperty" in configEntry;
7697
7962
  }
7963
+ static normalizeSubagentArgumentSchema(schema) {
7964
+ const normalized = schema && typeof schema === "object" && !Array.isArray(schema) ? { ...schema } : {};
7965
+ normalized.type = "object";
7966
+ if (!normalized.properties || typeof normalized.properties !== "object") {
7967
+ normalized.properties = {};
7968
+ }
7969
+ if (!("additionalProperties" in normalized)) {
7970
+ normalized.additionalProperties = false;
7971
+ }
7972
+ return normalized;
7973
+ }
7974
+ static describeSubagentArguments(schema) {
7975
+ const normalized = this.normalizeSubagentArgumentSchema(schema);
7976
+ const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? Object.keys(normalized.properties) : [];
7977
+ const required = Array.isArray(normalized.required) ? normalized.required.filter((item) => typeof item === "string") : [];
7978
+ const optional = properties.filter((name) => !required.includes(name));
7979
+ const parts = [];
7980
+ if (required.length > 0) {
7981
+ parts.push(`required arguments: ${required.join(", ")}`);
7982
+ }
7983
+ if (optional.length > 0) {
7984
+ parts.push(`optional arguments: ${optional.join(", ")}`);
7985
+ }
7986
+ return parts.length > 0 ? parts.join("; ") : "no extra initial arguments";
7987
+ }
7988
+ static buildSubagentArgumentsSchema(promptSubagents) {
7989
+ const variants = promptSubagents.map((entry) => ({
7990
+ ...this.normalizeSubagentArgumentSchema(entry.argumentSchema),
7991
+ title: `${entry.name} initial arguments`,
7992
+ description: `Initial arguments for ${entry.name}. These values persist for the child thread lifetime.`
7993
+ }));
7994
+ if (variants.length === 1) {
7995
+ return variants[0];
7996
+ }
7997
+ return {
7998
+ type: "object",
7999
+ description: "Agent-specific initial arguments for the selected subagent. Use the schema matching the selected agent.",
8000
+ additionalProperties: false,
8001
+ anyOf: variants
8002
+ };
8003
+ }
7698
8004
  static buildSubagentCreateTool(promptSubagents) {
7699
8005
  const agentNames = promptSubagents.map((entry) => entry.name);
7700
8006
  const descriptionLines = promptSubagents.map((entry) => {
7701
8007
  const mode = `${entry.blocking ? "blocking" : "non-blocking"}, ${entry.resumable ? "resumable" : "non-resumable"}`;
7702
8008
  const maxInstances = typeof entry.maxInstances === "number" && entry.maxInstances > 0 ? `, max instances: ${entry.maxInstances}` : "";
7703
- return `- ${entry.name}: ${entry.description} (mode: ${mode}${maxInstances})`;
8009
+ const argumentSummary = this.describeSubagentArguments(entry.argumentSchema);
8010
+ return `- ${entry.name}: ${entry.description} (mode: ${mode}${maxInstances}; ${argumentSummary})`;
7704
8011
  });
7705
8012
  return {
7706
8013
  type: "function",
@@ -7710,6 +8017,7 @@ ${lines.join("\n\n")}`
7710
8017
  "Create and run a configured resumable dual_ai subagent.",
7711
8018
  "Available resumable subagents:",
7712
8019
  ...descriptionLines,
8020
+ "Provide any required invocation arguments via `arguments`; they persist for the life of the subagent thread.",
7713
8021
  "Use subagent_message for follow-up communication with resumable instances."
7714
8022
  ].join("\n"),
7715
8023
  parameters: {
@@ -7734,8 +8042,10 @@ ${lines.join("\n\n")}`
7734
8042
  name: {
7735
8043
  type: "string",
7736
8044
  description: "Required human-readable instance name for the spawned subagent thread. Use a concise stable label that identifies this child instance."
7737
- }
8045
+ },
8046
+ arguments: this.buildSubagentArgumentsSchema(promptSubagents)
7738
8047
  },
8048
+ additionalProperties: false,
7739
8049
  required: ["agent", "message", "attachments", "name"]
7740
8050
  }
7741
8051
  }
@@ -11538,6 +11848,7 @@ function runCodeViaThreadRpc(threadInstance, threadId, source, options) {
11538
11848
  var ThreadStateImpl, ExecutionStateImpl;
11539
11849
  var init_ThreadStateImpl = __esm({
11540
11850
  "src/agents/ThreadStateImpl.ts"() {
11851
+ init_types();
11541
11852
  init_utilities();
11542
11853
  init_code_execution();
11543
11854
  ThreadStateImpl = class _ThreadStateImpl {
@@ -11585,6 +11896,19 @@ var init_ThreadStateImpl = __esm({
11585
11896
  get terminated() {
11586
11897
  return this._terminatedCache;
11587
11898
  }
11899
+ get arguments() {
11900
+ if (this._flowState) {
11901
+ return this._flowState.arguments ?? this.getMetadataArguments();
11902
+ }
11903
+ return this.getMetadataArguments();
11904
+ }
11905
+ getMetadataArguments() {
11906
+ const value = this._metadata.properties?.[SUBAGENT_INITIAL_ARGUMENTS_THREAD_PROPERTY];
11907
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
11908
+ return {};
11909
+ }
11910
+ return value;
11911
+ }
11588
11912
  /**
11589
11913
  * Get the agent configuration from the underlying FlowState.
11590
11914
  * This is for backward compatibility with hooks that access state.agentConfig.
@@ -15118,6 +15442,39 @@ var DurableThread = class extends DurableObject {
15118
15442
  await this.setChildrenRegistry(next);
15119
15443
  }
15120
15444
  }
15445
+ /**
15446
+ * Persist the invocation arguments supplied when this subagent thread was
15447
+ * created. These are hydrated into prompt-interpolation context on every
15448
+ * activation of either side, so they survive for the life of the thread.
15449
+ */
15450
+ async setSubagentArguments(_threadId, args) {
15451
+ await this.ensureMigrated();
15452
+ const payload = args && typeof args === "object" && !Array.isArray(args) ? args : {};
15453
+ await this.ctx.storage.sql.exec(
15454
+ `INSERT OR REPLACE INTO execution_state (key, value) VALUES ('subagent_arguments', ?)`,
15455
+ JSON.stringify(payload)
15456
+ );
15457
+ }
15458
+ /**
15459
+ * Read the persisted invocation arguments for this subagent thread.
15460
+ * Returns an empty object when none were stored.
15461
+ */
15462
+ async getSubagentArguments(_threadId) {
15463
+ await this.ensureMigrated();
15464
+ const cursor = await this.ctx.storage.sql.exec(
15465
+ `SELECT value FROM execution_state WHERE key = 'subagent_arguments' LIMIT 1`
15466
+ );
15467
+ const raw = cursor.toArray()[0]?.value;
15468
+ if (!raw) {
15469
+ return {};
15470
+ }
15471
+ try {
15472
+ const parsed = JSON.parse(raw);
15473
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
15474
+ } catch {
15475
+ return {};
15476
+ }
15477
+ }
15121
15478
  asOptionalString(value) {
15122
15479
  if (typeof value !== "string") {
15123
15480
  return null;
@@ -17665,6 +18022,23 @@ ${resultContent}${attachmentSummary}`;
17665
18022
  console.error("[DurableThread] Alarm handler failed:", error);
17666
18023
  }
17667
18024
  }
18025
+ normalizePlainRecord(value) {
18026
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
18027
+ return null;
18028
+ }
18029
+ return value;
18030
+ }
18031
+ buildExecutionArguments(data, properties) {
18032
+ const dataRecord = this.normalizePlainRecord(data) ?? {};
18033
+ const persistedInitialArguments = this.normalizePlainRecord(
18034
+ properties?.[SUBAGENT_INITIAL_ARGUMENTS_THREAD_PROPERTY]
18035
+ );
18036
+ const initialArguments = persistedInitialArguments ?? dataRecord;
18037
+ if (!initialArguments || Object.keys(initialArguments).length === 0) {
18038
+ return {};
18039
+ }
18040
+ return initialArguments;
18041
+ }
17668
18042
  /**
17669
18043
  * Internal method: Execute a flow (called by alarm queue)
17670
18044
  * This is the actual execution logic, separate from the public execute() RPC method
@@ -17794,6 +18168,7 @@ ${resultContent}${attachmentSummary}`;
17794
18168
  emitMessageChunk: (messageId, chunk, depth) => this.broadcastMessageChunk(messageId, chunk, depth),
17795
18169
  emitTelemetry: (event) => this.broadcastTelemetry(event),
17796
18170
  emitEvent: (type, data2) => this.broadcastEvent(type, data2),
18171
+ arguments: this.buildExecutionArguments(data, thread.properties),
17797
18172
  rootMessageId,
17798
18173
  abortController: this.currentAbortController
17799
18174
  }, awaitCompletion);
@@ -19063,6 +19438,7 @@ async function decryptEnvs(encrypted, encryptionKey) {
19063
19438
  }
19064
19439
 
19065
19440
  // src/durable-objects/DurableAgentBuilder.ts
19441
+ init_types();
19066
19442
  var ENV_TYPES_PROPERTY = "__agentbuilder_env_types";
19067
19443
  var DurableAgentBuilder = class extends DurableObject {
19068
19444
  migratedToVersion = null;
@@ -19088,6 +19464,45 @@ var DurableAgentBuilder = class extends DurableObject {
19088
19464
  }
19089
19465
  return Object.keys(result).length > 0 ? result : null;
19090
19466
  }
19467
+ normalizePlainObject(input) {
19468
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
19469
+ return void 0;
19470
+ }
19471
+ const result = { ...input };
19472
+ return Object.keys(result).length > 0 ? result : void 0;
19473
+ }
19474
+ hasInitialArguments(args) {
19475
+ return Object.keys(args).length > 0;
19476
+ }
19477
+ buildSubagentThreadProperties(initialArguments) {
19478
+ if (!this.hasInitialArguments(initialArguments)) {
19479
+ return void 0;
19480
+ }
19481
+ return {
19482
+ [SUBAGENT_INITIAL_ARGUMENTS_THREAD_PROPERTY]: initialArguments
19483
+ };
19484
+ }
19485
+ buildSubagentInitialArgumentsMessage(initialArguments, createdAt) {
19486
+ if (!this.hasInitialArguments(initialArguments)) {
19487
+ return null;
19488
+ }
19489
+ return {
19490
+ id: crypto.randomUUID(),
19491
+ role: "system",
19492
+ content: [
19493
+ "Persistent initial arguments for this subagent thread.",
19494
+ "These values were supplied by the parent when the child was created and remain in effect for side_a and side_b.",
19495
+ "They are available as ThreadState.arguments and prompt variables by their top-level keys.",
19496
+ "",
19497
+ JSON.stringify(initialArguments, null, 2)
19498
+ ].join("\n"),
19499
+ silent: true,
19500
+ metadata: {
19501
+ subagentInitialArguments: true
19502
+ },
19503
+ created_at: createdAt
19504
+ };
19505
+ }
19091
19506
  normalizeEnvTypeRecord(input, env) {
19092
19507
  if (!input || typeof input !== "object" || !env) {
19093
19508
  return null;
@@ -20153,10 +20568,12 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
20153
20568
  initial_message_attachments: this.normalizePendingAttachments(
20154
20569
  params.payload.initial_message_attachments
20155
20570
  ),
20571
+ initial_arguments: this.normalizePlainObject(params.payload.initial_arguments),
20156
20572
  initial_agent_name: typeof params.payload.initial_agent_name === "string" ? params.payload.initial_agent_name : null,
20157
20573
  agent_title: typeof params.payload.agent_title === "string" ? params.payload.agent_title : null,
20158
20574
  agent_description: typeof params.payload.agent_description === "string" ? params.payload.agent_description : null,
20159
- spawn_group_id: typeof params.payload.spawn_group_id === "string" ? params.payload.spawn_group_id : null
20575
+ spawn_group_id: typeof params.payload.spawn_group_id === "string" ? params.payload.spawn_group_id : null,
20576
+ arguments: params.payload.arguments && typeof params.payload.arguments === "object" && !Array.isArray(params.payload.arguments) ? params.payload.arguments : {}
20160
20577
  };
20161
20578
  await this.ctx.storage.sql.exec(
20162
20579
  `INSERT INTO pending_subagent_env_requests (
@@ -20218,7 +20635,8 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
20218
20635
  initial_agent_name: typeof payloadObject.initial_agent_name === "string" ? payloadObject.initial_agent_name : null,
20219
20636
  agent_title: typeof payloadObject.agent_title === "string" ? payloadObject.agent_title : null,
20220
20637
  agent_description: typeof payloadObject.agent_description === "string" ? payloadObject.agent_description : null,
20221
- spawn_group_id: typeof payloadObject.spawn_group_id === "string" ? payloadObject.spawn_group_id : null
20638
+ spawn_group_id: typeof payloadObject.spawn_group_id === "string" ? payloadObject.spawn_group_id : null,
20639
+ arguments: payloadObject.arguments && typeof payloadObject.arguments === "object" && !Array.isArray(payloadObject.arguments) ? payloadObject.arguments : {}
20222
20640
  };
20223
20641
  let requiredRaw = [];
20224
20642
  let missingRaw = [];
@@ -20271,16 +20689,26 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
20271
20689
  );
20272
20690
  }
20273
20691
  const initialAgentName = typeof pending.payload.initial_agent_name === "string" ? pending.payload.initial_agent_name.replace(/\s+/g, " ").trim() : "";
20692
+ const initialArguments = this.normalizePlainObject(pending.payload.initial_arguments) ?? {};
20274
20693
  const childThread = await this.createThread({
20275
20694
  agent_name: pending.agent_name,
20276
20695
  parent: params.parent_thread_id,
20277
20696
  env: providedEnv,
20697
+ properties: this.buildSubagentThreadProperties(initialArguments),
20278
20698
  tags: initialAgentName ? [this.buildThreadNameTag(initialAgentName)] : void 0
20279
20699
  });
20280
20700
  const parentId = this.env.AGENT_BUILDER_THREAD.idFromName(params.parent_thread_id);
20281
20701
  const childId = this.env.AGENT_BUILDER_THREAD.idFromName(childThread.id);
20282
20702
  const parentThread = this.env.AGENT_BUILDER_THREAD.get(parentId);
20283
20703
  const childThreadStub = this.env.AGENT_BUILDER_THREAD.get(childId);
20704
+ const pendingArguments = pending.payload.arguments;
20705
+ if (pendingArguments && typeof pendingArguments === "object" && !Array.isArray(pendingArguments) && Object.keys(pendingArguments).length > 0 && typeof childThreadStub.setSubagentArguments === "function") {
20706
+ try {
20707
+ await childThreadStub.setSubagentArguments(childThread.id, pendingArguments);
20708
+ } catch (error) {
20709
+ console.error("[DurableAgentBuilder] Failed to persist subagent arguments:", error);
20710
+ }
20711
+ }
20284
20712
  const canCopyInitialAttachments = typeof parentThread.readFile === "function" && typeof parentThread.statFile === "function" && typeof childThreadStub.writeFile === "function";
20285
20713
  const initialAttachments = canCopyInitialAttachments ? await this.copyPendingAttachmentsBetweenThreads(
20286
20714
  {
@@ -20295,6 +20723,14 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
20295
20723
  const targetRole = pending.payload.receives_messages === "side_b" ? "assistant" : "user";
20296
20724
  const baseTimestamp = Date.now() * 1e3;
20297
20725
  const initialMessages = [];
20726
+ const initialArgumentsMessage = this.buildSubagentInitialArgumentsMessage(
20727
+ initialArguments,
20728
+ baseTimestamp
20729
+ );
20730
+ if (initialArgumentsMessage) {
20731
+ initialMessages.push(initialArgumentsMessage);
20732
+ }
20733
+ const timestampOffset = initialMessages.length;
20298
20734
  for (let i = 0; i < initialAttachments.length; i++) {
20299
20735
  const attachment = initialAttachments[i];
20300
20736
  initialMessages.push({
@@ -20303,7 +20739,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
20303
20739
  content: `Initial asset attachment path: ${attachment.path}`,
20304
20740
  attachments: JSON.stringify([attachment]),
20305
20741
  silent: true,
20306
- created_at: baseTimestamp + i
20742
+ created_at: baseTimestamp + timestampOffset + i
20307
20743
  });
20308
20744
  }
20309
20745
  initialMessages.push({
@@ -20311,7 +20747,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
20311
20747
  role: targetRole,
20312
20748
  content: pending.payload.initial_message_content,
20313
20749
  attachments: void 0,
20314
- created_at: baseTimestamp + initialAttachments.length
20750
+ created_at: baseTimestamp + timestampOffset + initialAttachments.length
20315
20751
  });
20316
20752
  if (typeof parentThread.upsertChildRegistry === "function") {
20317
20753
  await parentThread.upsertChildRegistry(params.parent_thread_id, {
@@ -20322,6 +20758,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
20322
20758
  resumable: pending.payload.resumable,
20323
20759
  blocking: pending.payload.blocking,
20324
20760
  status: "running",
20761
+ ...this.hasInitialArguments(initialArguments) ? { initialArguments } : {},
20325
20762
  ...initialAgentName ? { threadName: initialAgentName } : {},
20326
20763
  ...pending.payload.spawn_group_id ? { spawnGroupId: pending.payload.spawn_group_id } : {},
20327
20764
  createdAt: Date.now() * 1e3
@@ -20336,7 +20773,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
20336
20773
  childThread.id,
20337
20774
  pending.agent_name,
20338
20775
  initialMessages,
20339
- {}
20776
+ initialArguments
20340
20777
  );
20341
20778
  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(
20342
20779
  {