@standardagents/builder 0.17.0-next.a4b7340 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -204,6 +204,16 @@ function getGoogleFallbackPricing(modelId) {
204
204
  if (prefixMatch) return { ...prefixMatch.pricing, source: "google-static" };
205
205
  return null;
206
206
  }
207
+ function getAnthropicFallbackPricing(modelId) {
208
+ const normalized = normalizeModelId(modelId);
209
+ let best = null;
210
+ for (const entry of ANTHROPIC_MODEL_PRICING_PREFIXES) {
211
+ if (normalized.startsWith(entry.prefix) && (!best || entry.prefix.length > best.prefix.length)) {
212
+ best = entry;
213
+ }
214
+ }
215
+ return best ? { ...best.pricing, source: "anthropic-static" } : null;
216
+ }
207
217
  function getGroqFallbackPricing(modelId) {
208
218
  const pricing = GROQ_MODEL_PRICING[normalizeModelId(modelId)];
209
219
  return pricing ? { ...pricing, source: "groq-static" } : null;
@@ -234,6 +244,9 @@ function resolveModelPricing(modelDef, providerName) {
234
244
  source: "model"
235
245
  };
236
246
  }
247
+ if (providerName === "anthropic") {
248
+ return getAnthropicFallbackPricing(modelDef.model);
249
+ }
237
250
  if (providerName === "cerebras") {
238
251
  return getCerebrasFallbackPricing(modelDef.model);
239
252
  }
@@ -269,10 +282,29 @@ function calculateUsageCost(usage, pricing) {
269
282
  costTotal: roundCost(costInput + costOutput)
270
283
  };
271
284
  }
272
- var TOKENS_PER_MILLION, CEREBRAS_MODEL_PRICING, GOOGLE_MODEL_PRICING, GOOGLE_MODEL_PRICING_PREFIXES, GROQ_MODEL_PRICING, XAI_MODEL_PRICING;
285
+ var TOKENS_PER_MILLION, ANTHROPIC_MODEL_PRICING_PREFIXES, CEREBRAS_MODEL_PRICING, GOOGLE_MODEL_PRICING, GOOGLE_MODEL_PRICING_PREFIXES, GROQ_MODEL_PRICING, XAI_MODEL_PRICING;
273
286
  var init_pricing = __esm({
274
287
  "src/agents/pricing.ts"() {
275
288
  TOKENS_PER_MILLION = 1e6;
289
+ ANTHROPIC_MODEL_PRICING_PREFIXES = [
290
+ { prefix: "claude-fable-5", pricing: { inputPrice: 10, outputPrice: 50, cachedPrice: 1 } },
291
+ { prefix: "claude-mythos", pricing: { inputPrice: 10, outputPrice: 50, cachedPrice: 1 } },
292
+ { prefix: "claude-opus-4-8", pricing: { inputPrice: 5, outputPrice: 25, cachedPrice: 0.5 } },
293
+ { prefix: "claude-opus-4-7", pricing: { inputPrice: 5, outputPrice: 25, cachedPrice: 0.5 } },
294
+ { prefix: "claude-opus-4-6", pricing: { inputPrice: 5, outputPrice: 25, cachedPrice: 0.5 } },
295
+ { prefix: "claude-opus-4-5", pricing: { inputPrice: 5, outputPrice: 25, cachedPrice: 0.5 } },
296
+ { prefix: "claude-opus-4-1", pricing: { inputPrice: 15, outputPrice: 75, cachedPrice: 1.5 } },
297
+ { prefix: "claude-opus-4", pricing: { inputPrice: 15, outputPrice: 75, cachedPrice: 1.5 } },
298
+ { prefix: "claude-sonnet-4-6", pricing: { inputPrice: 3, outputPrice: 15, cachedPrice: 0.3 } },
299
+ { prefix: "claude-sonnet-4-5", pricing: { inputPrice: 3, outputPrice: 15, cachedPrice: 0.3 } },
300
+ { prefix: "claude-sonnet-4", pricing: { inputPrice: 3, outputPrice: 15, cachedPrice: 0.3 } },
301
+ { prefix: "claude-haiku-4-5", pricing: { inputPrice: 1, outputPrice: 5, cachedPrice: 0.1 } },
302
+ { prefix: "claude-3-7-sonnet", pricing: { inputPrice: 3, outputPrice: 15, cachedPrice: 0.3 } },
303
+ { prefix: "claude-3-5-sonnet", pricing: { inputPrice: 3, outputPrice: 15, cachedPrice: 0.3 } },
304
+ { prefix: "claude-3-5-haiku", pricing: { inputPrice: 0.8, outputPrice: 4, cachedPrice: 0.08 } },
305
+ { prefix: "claude-3-opus", pricing: { inputPrice: 15, outputPrice: 75, cachedPrice: 1.5 } },
306
+ { prefix: "claude-3-haiku", pricing: { inputPrice: 0.25, outputPrice: 1.25, cachedPrice: 0.03 } }
307
+ ];
276
308
  CEREBRAS_MODEL_PRICING = {
277
309
  "zai-glm-4.7": {
278
310
  inputPrice: 2.25,
@@ -935,9 +967,9 @@ var init_ProviderRegistry = __esm({
935
967
  const fingerprint = this.getProviderFingerprint(providerName, modelDef);
936
968
  const cached = this.providerCache.get(modelName);
937
969
  if (cached?.fingerprint === fingerprint) {
938
- return this.buildResult(cached.provider, modelDef);
970
+ return this.buildResult(cached.provider, modelDef, false);
939
971
  }
940
- return this.cacheAndReturn(modelName, createTestProvider(), modelDef, fingerprint);
972
+ return this.cacheAndReturn(modelName, createTestProvider(), modelDef, fingerprint, false);
941
973
  }
942
974
  const apiKey = this.getApiKeyForProvider(providerName, env);
943
975
  if (apiKey) {
@@ -954,19 +986,19 @@ var init_ProviderRegistry = __esm({
954
986
  const fingerprint = this.getProviderFingerprint(providerName, modelDef, config);
955
987
  const cached = this.providerCache.get(modelName);
956
988
  if (cached?.fingerprint === fingerprint) {
957
- return this.buildResult(cached.provider, modelDef);
989
+ return this.buildResult(cached.provider, modelDef, false);
958
990
  }
959
- return this.cacheAndReturn(modelName, providerFactory(config), modelDef, fingerprint);
991
+ return this.cacheAndReturn(modelName, providerFactory(config), modelDef, fingerprint, false);
960
992
  }
961
993
  if (this.providerOverrideFn) {
962
994
  const overrideFingerprint = this.getProviderFingerprint(`override:${this.providerOverrideRevision}`, modelDef);
963
995
  const overrideCached = this.providerCache.get(modelName);
964
996
  if (overrideCached?.fingerprint === overrideFingerprint) {
965
- return this.buildResult(overrideCached.provider, modelDef);
997
+ return this.buildResult(overrideCached.provider, modelDef, true);
966
998
  }
967
999
  const overrideProvider = this.providerOverrideFn(modelName, modelDef, env);
968
1000
  if (overrideProvider) {
969
- return this.cacheAndReturn(modelName, overrideProvider, modelDef, overrideFingerprint);
1001
+ return this.cacheAndReturn(modelName, overrideProvider, modelDef, overrideFingerprint, true);
970
1002
  }
971
1003
  }
972
1004
  const routing = resolvePlatformRouting(providerName, env);
@@ -978,18 +1010,18 @@ var init_ProviderRegistry = __esm({
978
1010
  const fingerprint = this.getProviderFingerprint(`platform:${providerName}`, modelDef, config);
979
1011
  const cached = this.providerCache.get(modelName);
980
1012
  if (cached?.fingerprint === fingerprint) {
981
- return this.buildResult(cached.provider, modelDef);
1013
+ return this.buildResult(cached.provider, modelDef, true);
982
1014
  }
983
- return this.cacheAndReturn(modelName, providerFactory(config), modelDef, fingerprint);
1015
+ return this.cacheAndReturn(modelName, providerFactory(config), modelDef, fingerprint, true);
984
1016
  }
985
1017
  throw new Error(`No API key found for provider: ${providerName}. Set the provider key or STANDARD_AGENTS_API_KEY.`);
986
1018
  }
987
- buildResult(provider, modelDef) {
988
- return { provider, modelName: modelDef.model, modelDef };
1019
+ buildResult(provider, modelDef, viaPlatform) {
1020
+ return { provider, modelName: modelDef.model, modelDef, viaPlatform };
989
1021
  }
990
- cacheAndReturn(modelName, provider, modelDef, fingerprint) {
991
- this.providerCache.set(modelName, { provider, fingerprint });
992
- return this.buildResult(provider, modelDef);
1022
+ cacheAndReturn(modelName, provider, modelDef, fingerprint, viaPlatform) {
1023
+ this.providerCache.set(modelName, { provider, fingerprint, viaPlatform });
1024
+ return this.buildResult(provider, modelDef, viaPlatform);
993
1025
  }
994
1026
  getProviderFingerprint(providerName, modelDef, config) {
995
1027
  return JSON.stringify({
@@ -1422,6 +1454,23 @@ function convertUsage(usage) {
1422
1454
  provider: usage.provider
1423
1455
  };
1424
1456
  }
1457
+ function inferProviderFromModelId(model) {
1458
+ const trimmed = model?.trim();
1459
+ if (!trimmed) return null;
1460
+ const slashIndex = trimmed.indexOf("/");
1461
+ if (slashIndex <= 0) return null;
1462
+ return trimmed.slice(0, slashIndex);
1463
+ }
1464
+ function inferInitialActualProvider(providerName, modelDef) {
1465
+ if (providerName !== "openrouter") return null;
1466
+ return inferProviderFromModelId(modelDef.model);
1467
+ }
1468
+ function normalizeProviderMetadataValue(value) {
1469
+ if (typeof value !== "string") return void 0;
1470
+ const trimmed = value.trim();
1471
+ if (!trimmed || trimmed.toLowerCase() === "unknown") return void 0;
1472
+ return trimmed;
1473
+ }
1425
1474
  var NON_VISION_PLACEHOLDER_TEXT, LLMRequest;
1426
1475
  var init_LLMRequest = __esm({
1427
1476
  "src/agents/LLMRequest.ts"() {
@@ -1590,6 +1639,7 @@ var init_LLMRequest = __esm({
1590
1639
  console.error("Failed to get provider name:", err);
1591
1640
  }
1592
1641
  const { requestBody, visionFiltering } = buildRequestBody(context, modelDef);
1642
+ const initialActualProvider = inferInitialActualProvider(providerName, modelDef);
1593
1643
  const requestBodyForLog = {
1594
1644
  ...requestBody,
1595
1645
  messages: stripBase64FromMessages(
@@ -1608,6 +1658,7 @@ var init_LLMRequest = __esm({
1608
1658
  id,
1609
1659
  message_id: state.rootMessageId || crypto.randomUUID(),
1610
1660
  provider: providerName || this.getProviderFromModel(modelId),
1661
+ actual_provider: initialActualProvider ?? void 0,
1611
1662
  model: modelId,
1612
1663
  model_name: modelDef.model,
1613
1664
  endpoint: "chat.completions",
@@ -1628,14 +1679,15 @@ var init_LLMRequest = __esm({
1628
1679
  await state.storage.sql.exec(
1629
1680
  `
1630
1681
  INSERT INTO logs (
1631
- id, message_id, provider, model, model_name, endpoint,
1682
+ id, message_id, provider, actual_provider, model, model_name, endpoint,
1632
1683
  request_body, tools_available, message_history_length, prompt_name,
1633
1684
  parent_log_id, retry_of_log_id, tools_schema, system_prompt, is_complete, created_at
1634
- ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16)
1685
+ ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17)
1635
1686
  `,
1636
1687
  logData.id,
1637
1688
  logData.message_id,
1638
1689
  logData.provider,
1690
+ logData.actual_provider,
1639
1691
  logData.model,
1640
1692
  logData.model_name,
1641
1693
  logData.endpoint,
@@ -1670,7 +1722,7 @@ var init_LLMRequest = __esm({
1670
1722
  */
1671
1723
  static async callModel(modelId, context, state, logId) {
1672
1724
  const { ProviderRegistry: ProviderRegistry2 } = await Promise.resolve().then(() => (init_providers(), providers_exports));
1673
- const { provider, modelName, modelDef } = await ProviderRegistry2.getProvider(
1725
+ const { provider, modelName, modelDef, viaPlatform } = await ProviderRegistry2.getProvider(
1674
1726
  modelId,
1675
1727
  state.env,
1676
1728
  state.thread.instance
@@ -1804,6 +1856,7 @@ var init_LLMRequest = __esm({
1804
1856
  }
1805
1857
  };
1806
1858
  response._provider = provider;
1859
+ response._viaPlatform = viaPlatform;
1807
1860
  response._providerResponseId = providerResponseId;
1808
1861
  response._aggregate_response = {
1809
1862
  id: responseId,
@@ -1881,12 +1934,12 @@ var init_LLMRequest = __esm({
1881
1934
  try {
1882
1935
  const toolsCalled = response.tool_calls ? JSON.stringify(response.tool_calls.map((tc) => tc.function.name)) : null;
1883
1936
  const providerName = response._provider?.name;
1884
- const standardAgentsRouterUsed = providerName === "platform";
1937
+ const standardAgentsRouterUsed = response._viaPlatform === true || providerName === "platform";
1885
1938
  const resolvedPricing = resolveModelPricing(modelDef, providerName);
1886
1939
  const calculatedCost = calculateUsageCost(response.usage, resolvedPricing);
1887
1940
  const providerReportedCost = typeof response.usage.cost === "number" ? response.usage.cost : typeof response.usage.cost === "string" ? parseFloat(response.usage.cost) : null;
1888
1941
  const cost_total = providerReportedCost != null && !Number.isNaN(providerReportedCost) ? providerReportedCost : calculatedCost?.costTotal ?? null;
1889
- const actualProvider = response.usage.provider;
1942
+ const actualProvider = normalizeProviderMetadataValue(response.usage.provider) ?? null;
1890
1943
  const aggregateResponse = response._aggregate_response;
1891
1944
  const responseBody = aggregateResponse ? JSON.stringify(aggregateResponse) : JSON.stringify(response);
1892
1945
  const providerTools = [];
@@ -2314,8 +2367,13 @@ ${errorStack}` : ""}${errorDetails}`;
2314
2367
  }).catch((err) => {
2315
2368
  console.error("Async metadata fetch failed (non-fatal):", err);
2316
2369
  });
2317
- state.rootState.pendingMetadataPromises = state.rootState.pendingMetadataPromises || [];
2318
- state.rootState.pendingMetadataPromises.push(metadataPromise);
2370
+ const rootState = state.rootState || state;
2371
+ rootState.pendingMetadataPromises = rootState.pendingMetadataPromises || [];
2372
+ rootState.pendingMetadataPromises.push(metadataPromise);
2373
+ if (rootState !== state) {
2374
+ state.pendingMetadataPromises = state.pendingMetadataPromises || [];
2375
+ state.pendingMetadataPromises.push(metadataPromise);
2376
+ }
2319
2377
  }
2320
2378
  /**
2321
2379
  * Update log record with async metadata from provider.
@@ -2325,9 +2383,12 @@ ${errorStack}` : ""}${errorDetails}`;
2325
2383
  const updates = [];
2326
2384
  const values = [];
2327
2385
  let paramIndex = 1;
2328
- if (metadata.actual_provider !== void 0) {
2386
+ const actualProvider = normalizeProviderMetadataValue(
2387
+ metadata.actual_provider ?? metadata.actualProvider ?? metadata.providerName
2388
+ );
2389
+ if (actualProvider !== void 0) {
2329
2390
  updates.push(`actual_provider = ?${paramIndex++}`);
2330
- values.push(metadata.actual_provider);
2391
+ values.push(actualProvider);
2331
2392
  }
2332
2393
  if (metadata.generation_cost !== void 0) {
2333
2394
  updates.push(`cost_total = ?${paramIndex++}`);
@@ -2345,7 +2406,7 @@ ${errorStack}` : ""}${errorDetails}`;
2345
2406
  log_id: logId,
2346
2407
  data: {
2347
2408
  id: logId,
2348
- ...metadata.actual_provider !== void 0 && { actual_provider: metadata.actual_provider },
2409
+ ...actualProvider !== void 0 && { actual_provider: actualProvider },
2349
2410
  ...metadata.generation_cost !== void 0 && { cost_total: metadata.generation_cost }
2350
2411
  }
2351
2412
  });
@@ -3071,6 +3132,11 @@ var init_ToolExecutor = __esm({
3071
3132
  state.sequence.queue.push(...toolCalls);
3072
3133
  state.sequence.isHandling = true;
3073
3134
  while (state.sequence.queue.length > 0) {
3135
+ if (state.stopped) {
3136
+ state.sequence.queue = [];
3137
+ state.sequence.isHandling = false;
3138
+ break;
3139
+ }
3074
3140
  if (await state.thread.instance.shouldStop() || state.abortController?.signal.aborted) {
3075
3141
  state.sequence.queue = [];
3076
3142
  state.sequence.isHandling = false;
@@ -3099,7 +3165,17 @@ var init_ToolExecutor = __esm({
3099
3165
  });
3100
3166
  continue;
3101
3167
  }
3102
- const result = await this.executeToolCall(call, state, toolMessageId);
3168
+ const previousToolCall = state.currentToolCall;
3169
+ state.currentToolCall = {
3170
+ id: call.id,
3171
+ name: call.function.name
3172
+ };
3173
+ let result;
3174
+ try {
3175
+ result = await this.executeToolCall(call, state, toolMessageId);
3176
+ } finally {
3177
+ state.currentToolCall = previousToolCall;
3178
+ }
3103
3179
  if (result.status === "error") {
3104
3180
  const error = new Error(result.error || "Tool execution failed");
3105
3181
  if (result.stack) {
@@ -4968,6 +5044,11 @@ ${attachmentPaths}`;
4968
5044
  }
4969
5045
  }
4970
5046
  const toolStatus = processedResult.status === "success" ? "success" : "error";
5047
+ const parentNotifications = this.consumeParentNotificationsForToolCall(
5048
+ state,
5049
+ call
5050
+ );
5051
+ const notificationContent = parentNotifications[parentNotifications.length - 1]?.content;
4971
5052
  let message = {
4972
5053
  id: messageId,
4973
5054
  role: "tool",
@@ -4981,15 +5062,20 @@ ${attachmentPaths}`;
4981
5062
  parent_id: state.parentMessageId || null,
4982
5063
  depth: state.depth,
4983
5064
  attachments: attachmentRefs && attachmentRefs.length > 0 ? JSON.stringify(attachmentRefs) : null,
4984
- subagent_id: typeof processedResult.subagent_id === "string" && processedResult.subagent_id.trim().length > 0 ? processedResult.subagent_id.trim() : null
5065
+ subagent_id: typeof processedResult.subagent_id === "string" && processedResult.subagent_id.trim().length > 0 ? processedResult.subagent_id.trim() : null,
5066
+ metadata: parentNotifications.length > 0 ? {
5067
+ parent_notification: true,
5068
+ parent_notifications: parentNotifications,
5069
+ parent_notification_content: notificationContent
5070
+ } : void 0
4985
5071
  };
4986
5072
  message = await FlowEngine2.runBeforeCreateMessageHook(state, message);
4987
5073
  message.created_at = Date.now() * TIMESTAMP_MULTIPLIER;
4988
5074
  const currentPrompt = state.promptPath.length > 0 ? state.promptPath[state.promptPath.length - 1] : null;
4989
5075
  await state.storage.sql.exec(
4990
5076
  `
4991
- INSERT INTO messages (id, role, content, name, tool_call_id, created_at, tool_status, parent_id, depth, attachments, subagent_id, prompt)
4992
- VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)
5077
+ INSERT INTO messages (id, role, content, name, tool_call_id, created_at, tool_status, parent_id, depth, attachments, subagent_id, prompt, metadata)
5078
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)
4993
5079
  `,
4994
5080
  message.id,
4995
5081
  message.role,
@@ -5002,7 +5088,8 @@ ${attachmentPaths}`;
5002
5088
  message.depth,
5003
5089
  message.attachments,
5004
5090
  message.subagent_id ?? null,
5005
- currentPrompt
5091
+ currentPrompt,
5092
+ message.metadata ? JSON.stringify(message.metadata) : null
5006
5093
  );
5007
5094
  await FlowEngine2.runAfterCreateMessageHook(state, message);
5008
5095
  const parentLogId = state.currentLogId || null;
@@ -5067,6 +5154,23 @@ ${attachmentPaths}`;
5067
5154
  await this.logError(state, error, `storeToolResult:${call.function.name}`);
5068
5155
  }
5069
5156
  }
5157
+ static consumeParentNotificationsForToolCall(state, call) {
5158
+ const pending = state.parentNotifications ?? [];
5159
+ if (pending.length === 0) return [];
5160
+ const matched = [];
5161
+ const remaining = [];
5162
+ for (const notification of pending) {
5163
+ const matchesCallId = notification.toolCallId === call.id;
5164
+ const matchesToolName = !notification.toolCallId && notification.toolName === call.function.name;
5165
+ if (matchesCallId || matchesToolName) {
5166
+ matched.push(notification);
5167
+ } else {
5168
+ remaining.push(notification);
5169
+ }
5170
+ }
5171
+ state.parentNotifications = remaining;
5172
+ return matched;
5173
+ }
5070
5174
  static async createSilentGeneratedAssetPathMessagesFromToolResult(state, sourceToolMessage, refs, enabled) {
5071
5175
  if (!enabled || !refs || refs.length === 0) {
5072
5176
  return;
@@ -5528,6 +5632,8 @@ var init_FlowEngine = __esm({
5528
5632
  stoppedBy: state.stoppedBy,
5529
5633
  stopReason: state.stopReason,
5530
5634
  stopReasonCode: state.stopReasonCode,
5635
+ sessionStopped: state.sessionStopped,
5636
+ sessionStopResult: state.sessionStopResult,
5531
5637
  stepCount: state.stepCount,
5532
5638
  stream: state.stream.httpStream
5533
5639
  };
@@ -5727,6 +5833,8 @@ var init_FlowEngine = __esm({
5727
5833
  stoppedBy: stateInput.stoppedBy,
5728
5834
  stopReason: stateInput.stopReason,
5729
5835
  stopReasonCode: stateInput.stopReasonCode,
5836
+ sessionStopped: stateInput.sessionStopped,
5837
+ sessionStopResult: stateInput.sessionStopResult,
5730
5838
  messageHistory: [],
5731
5839
  sequence: stateInput.sequence || {
5732
5840
  queue: [],
@@ -5986,7 +6094,7 @@ var init_FlowEngine = __esm({
5986
6094
  max_session_turns: newAgentDef.maxSessionTurns ?? null,
5987
6095
  side_a_label: newAgentDef.sideA?.label ?? null,
5988
6096
  side_a_agent_prompt: newAgentDef.sideA?.prompt ?? null,
5989
- side_a_stop_on_response: newAgentDef.sideA?.stopOnResponse ?? false,
6097
+ side_a_stop_on_response: newAgentDef.sideA?.stopOnResponse ?? true,
5990
6098
  side_a_stop_tool: newAgentDef.sideA?.stopTool ?? null,
5991
6099
  side_a_stop_tool_response_property: newAgentDef.sideA?.stopToolResponseProperty ?? null,
5992
6100
  side_a_max_steps: newAgentDef.sideA?.maxSteps ?? null,
@@ -6001,7 +6109,7 @@ var init_FlowEngine = __esm({
6001
6109
  side_a_session_status_attachments_property: sideASession.status.attachmentsProperty,
6002
6110
  side_b_label: newAgentDef.sideB?.label ?? null,
6003
6111
  side_b_agent_prompt: newAgentDef.sideB?.prompt ?? null,
6004
- side_b_stop_on_response: newAgentDef.sideB?.stopOnResponse ?? false,
6112
+ side_b_stop_on_response: newAgentDef.sideB?.stopOnResponse ?? true,
6005
6113
  side_b_stop_tool: newAgentDef.sideB?.stopTool ?? null,
6006
6114
  side_b_stop_tool_response_property: newAgentDef.sideB?.stopToolResponseProperty ?? null,
6007
6115
  side_b_max_steps: newAgentDef.sideB?.maxSteps ?? null,
@@ -11696,34 +11804,79 @@ var init_ThreadStateImpl = __esm({
11696
11804
  this._metadata.tenvs = nextEnv;
11697
11805
  }
11698
11806
  async notifyParent(content) {
11699
- if (!content || !content.trim()) {
11807
+ const trimmedContent = content?.trim();
11808
+ if (!trimmedContent) {
11700
11809
  throw new Error("notifyParent requires non-empty content");
11701
11810
  }
11702
- const { parentThreadId, parentStub } = await this._getParentThreadStub();
11703
- if (typeof parentStub.queueMessage !== "function") {
11704
- throw new Error("notifyParent is not supported by this thread runtime");
11811
+ if (this._flowState) {
11812
+ const currentToolCall = this._flowState.currentToolCall;
11813
+ const notification = {
11814
+ content: trimmedContent,
11815
+ toolCallId: currentToolCall?.id ?? null,
11816
+ toolName: currentToolCall?.name ?? this._flowState.active?.tool ?? null,
11817
+ created_at: Date.now() * 1e3
11818
+ };
11819
+ this._flowState.parentNotifications = [
11820
+ ...this._flowState.parentNotifications ?? [],
11821
+ notification
11822
+ ];
11823
+ }
11824
+ const parentTarget = await this._getOptionalParentThreadStub();
11825
+ if (parentTarget && typeof parentTarget.parentStub.queueMessage === "function") {
11826
+ await parentTarget.parentStub.queueMessage(parentTarget.parentThreadId, {
11827
+ role: "user",
11828
+ content: trimmedContent,
11829
+ silent: true,
11830
+ metadata: { subagent_id: this.threadId }
11831
+ });
11705
11832
  }
11706
- await parentStub.queueMessage(parentThreadId, {
11707
- role: "user",
11708
- content: content.trim(),
11709
- silent: true,
11710
- metadata: { subagent_id: this.threadId }
11711
- });
11712
11833
  }
11713
11834
  async setStatus(status) {
11714
11835
  if (!status || !status.trim()) {
11715
11836
  throw new Error("setStatus requires non-empty status");
11716
11837
  }
11717
- const { parentThreadId, parentStub } = await this._getParentThreadStub();
11718
- if (typeof parentStub.updateChildRegistryStatus !== "function") {
11719
- throw new Error("setStatus is not supported by this thread runtime");
11838
+ const parentTarget = await this._getOptionalParentThreadStub();
11839
+ if (!parentTarget || typeof parentTarget.parentStub.updateChildRegistryStatus !== "function") {
11840
+ return;
11720
11841
  }
11721
- await parentStub.updateChildRegistryStatus(
11722
- parentThreadId,
11842
+ await parentTarget.parentStub.updateChildRegistryStatus(
11843
+ parentTarget.parentThreadId,
11723
11844
  this.threadId,
11724
11845
  status.trim()
11725
11846
  );
11726
11847
  }
11848
+ async stopSession(options = {}) {
11849
+ if (!this._flowState) {
11850
+ throw new Error("stopSession requires active execution");
11851
+ }
11852
+ const notifyParent = options.notifyParent?.trim();
11853
+ if (options.notifyParent !== void 0 && !notifyParent) {
11854
+ throw new Error("stopSession notifyParent requires non-empty content");
11855
+ }
11856
+ const status = options.status?.trim();
11857
+ if (options.status !== void 0 && !status) {
11858
+ throw new Error("stopSession status requires non-empty status");
11859
+ }
11860
+ if (notifyParent) {
11861
+ await this.notifyParent(notifyParent);
11862
+ }
11863
+ if (status) {
11864
+ await this.setStatus(status);
11865
+ }
11866
+ const result = options.result?.trim() || "Session stopped.";
11867
+ this._flowState.sessionStopped = true;
11868
+ this._flowState.sessionStopResult = result;
11869
+ this._flowState.stopped = true;
11870
+ this._flowState.stoppedBy = this._flowState.currentSide;
11871
+ this._flowState.stopReason = "Session stopped by state.stopSession()";
11872
+ this._flowState.stopReasonCode = "state_stop_session";
11873
+ this._flowState.emitTelemetry?.({
11874
+ type: "stopped",
11875
+ reason: this._flowState.stopReason,
11876
+ side: this._flowState.currentSide,
11877
+ timestamp: Date.now()
11878
+ });
11879
+ }
11727
11880
  async getChildThread(referenceId) {
11728
11881
  const agentBuilder = this._getAgentBuilderStub();
11729
11882
  const child = await agentBuilder.getThread(referenceId);
@@ -12136,19 +12289,47 @@ var init_ThreadStateImpl = __esm({
12136
12289
  return Object.keys(normalized).length > 0 ? normalized : null;
12137
12290
  }
12138
12291
  async _getParentThreadId() {
12292
+ const parent = await this._getOptionalParentThreadId();
12293
+ if (!parent) {
12294
+ throw new Error(`Thread ${this.threadId} has no parent thread`);
12295
+ }
12296
+ return parent;
12297
+ }
12298
+ async _getOptionalParentThreadId() {
12139
12299
  const metadataParent = typeof this._metadata.parent === "string" && this._metadata.parent.trim().length > 0 ? this._metadata.parent.trim() : null;
12140
12300
  if (metadataParent) {
12141
12301
  return metadataParent;
12142
12302
  }
12143
- const agentBuilder = this._getAgentBuilderStub();
12144
- const thread = await agentBuilder.getThread(this.threadId);
12303
+ let thread = null;
12304
+ try {
12305
+ const agentBuilder = this._getAgentBuilderStub();
12306
+ thread = await agentBuilder.getThread(this.threadId);
12307
+ } catch {
12308
+ return null;
12309
+ }
12145
12310
  const parent = thread && typeof thread.parent === "string" && thread.parent.trim().length > 0 ? thread.parent.trim() : null;
12146
- if (!parent) {
12147
- throw new Error(`Thread ${this.threadId} has no parent thread`);
12311
+ if (parent) {
12312
+ this._metadata.parent = parent;
12148
12313
  }
12149
- this._metadata.parent = parent;
12150
12314
  return parent;
12151
12315
  }
12316
+ async _getOptionalParentThreadStub() {
12317
+ const parentThreadId = await this._getOptionalParentThreadId();
12318
+ if (!parentThreadId) {
12319
+ return null;
12320
+ }
12321
+ try {
12322
+ const threadNamespace = this._threadInstance.env.AGENT_BUILDER_THREAD;
12323
+ if (!threadNamespace || typeof threadNamespace.idFromName !== "function" || typeof threadNamespace.get !== "function") {
12324
+ return null;
12325
+ }
12326
+ const durableId = threadNamespace.idFromName(parentThreadId);
12327
+ const parentStub = threadNamespace.get(durableId);
12328
+ return { parentThreadId, parentStub };
12329
+ } catch {
12330
+ return null;
12331
+ }
12332
+ }
12152
12333
  async _getParentThreadStub() {
12153
12334
  const parentThreadId = await this._getParentThreadId();
12154
12335
  const durableId = this._threadInstance.env.AGENT_BUILDER_THREAD.idFromName(parentThreadId);
@@ -13130,6 +13311,12 @@ function needsRegeneration(config) {
13130
13311
 
13131
13312
  // src/providers/catalog.ts
13132
13313
  var FIRST_PARTY_PROVIDERS = [
13314
+ {
13315
+ name: "anthropic",
13316
+ package: "@standardagents/anthropic",
13317
+ label: "Anthropic",
13318
+ envKeys: ["ANTHROPIC_API_KEY"]
13319
+ },
13133
13320
  {
13134
13321
  name: "cloudflare",
13135
13322
  package: "@standardagents/cloudflare",
@@ -18843,6 +19030,18 @@ function readRawRequestBody(req) {
18843
19030
  req.on("error", reject);
18844
19031
  });
18845
19032
  }
19033
+ function resolveContainedFile(baseDir, requestPath) {
19034
+ const resolvedBase = path8__default.resolve(baseDir);
19035
+ const resolved = path8__default.resolve(resolvedBase, `.${path8__default.sep}${requestPath.replace(/^\/+/, "")}`);
19036
+ if (resolved !== resolvedBase && !resolved.startsWith(resolvedBase + path8__default.sep)) {
19037
+ return null;
19038
+ }
19039
+ try {
19040
+ return fs8__default.existsSync(resolved) && fs8__default.statSync(resolved).isFile() ? resolved : null;
19041
+ } catch {
19042
+ return null;
19043
+ }
19044
+ }
18846
19045
  function injectUiConfigIntoHtml(htmlContent) {
18847
19046
  const configScript = `<script>window.__AGENTBUILDER_CONFIG__ = { devMode: true };</script>`;
18848
19047
  return htmlContent.replace(/\/agents\//g, "/").replace("</head>", `${configScript}</head>`);
@@ -18985,6 +19184,15 @@ function createDevMiddleware(server, context) {
18985
19184
  if (isStaticAsset) {
18986
19185
  const cleanUrl = clientPath.split("?")[0];
18987
19186
  filePath = path8__default.join(clientDir, cleanUrl);
19187
+ if (!fs8__default.existsSync(filePath)) {
19188
+ const projectPublicFile = resolveContainedFile(
19189
+ path8__default.resolve(server.config.root, "public"),
19190
+ cleanUrl
19191
+ );
19192
+ if (projectPublicFile) {
19193
+ filePath = projectPublicFile;
19194
+ }
19195
+ }
18988
19196
  } else {
18989
19197
  filePath = path8__default.join(clientDir, "index.html");
18990
19198
  }
@@ -19947,6 +20155,7 @@ var depsToInclude = [
19947
20155
  "zod/v4",
19948
20156
  "zod/v4/core",
19949
20157
  "openai",
20158
+ "@anthropic-ai/sdk",
19950
20159
  "magic-string",
19951
20160
  "@standardagents/spec"
19952
20161
  ];
@@ -20280,6 +20489,27 @@ export { CodeExecutionBridge, DurableAgentBuilder, DurableThread };
20280
20489
  }
20281
20490
  }
20282
20491
  copyRecursive(clientDir, mountDir);
20492
+ const projectPublicDir = path8__default.resolve(process.cwd(), "public");
20493
+ if (fs8__default.existsSync(projectPublicDir)) {
20494
+ let copyPublicRecursive2 = function(src, dest) {
20495
+ const entries = fs8__default.readdirSync(src, { withFileTypes: true });
20496
+ for (const entry of entries) {
20497
+ const srcPath = path8__default.join(src, entry.name);
20498
+ const destPath = path8__default.join(dest, entry.name);
20499
+ if (entry.isDirectory()) {
20500
+ fs8__default.mkdirSync(destPath, { recursive: true });
20501
+ copyPublicRecursive2(srcPath, destPath);
20502
+ } else if (fs8__default.existsSync(destPath)) {
20503
+ console.warn(
20504
+ `[agentbuilder] Skipping public/ file that collides with a built UI asset: ${destPath}`
20505
+ );
20506
+ } else {
20507
+ fs8__default.copyFileSync(srcPath, destPath);
20508
+ }
20509
+ }
20510
+ };
20511
+ copyPublicRecursive2(projectPublicDir, mountDir);
20512
+ }
20283
20513
  }
20284
20514
  };
20285
20515
  return [
@@ -22193,6 +22423,7 @@ function createEndpointThreadStateBridge(state) {
22193
22423
  setEnv: (propertyName, value, options) => state.setEnv(propertyName, value, options),
22194
22424
  notifyParent: (content) => state.notifyParent(content),
22195
22425
  setStatus: (status) => state.setStatus(status),
22426
+ stopSession: (options) => state.stopSession(options),
22196
22427
  queueTool: (toolName, args) => state.queueTool(toolName, args),
22197
22428
  invokeTool: (toolName, args) => state.invokeTool(toolName, args),
22198
22429
  scheduleEffect: (name, args, delay) => state.scheduleEffect(name, args, delay),
@@ -23412,6 +23643,15 @@ var DurableThread = class extends DurableObject {
23412
23643
  const terminalToolNames = await this.getTerminalSessionToolNames(agentId);
23413
23644
  const sessionFailToolNames = terminalToolNames.fail;
23414
23645
  const hasTerminalSessionTools = terminalToolNames.all.size > 0;
23646
+ if (flowResult.sessionStopped) {
23647
+ await emitParentHandoffStatus("result");
23648
+ return {
23649
+ status: "success",
23650
+ result: flowResult.sessionStopResult?.trim() || "Session stopped.",
23651
+ attachments: void 0,
23652
+ terminal: true
23653
+ };
23654
+ }
23415
23655
  const latestInRunCursor = await this.ctx.storage.sql.exec(
23416
23656
  `
23417
23657
  SELECT role, name, content, tool_status, attachments
@@ -23991,27 +24231,30 @@ ${paths.join("\n")}`;
23991
24231
  if (!parentThreadId || !flowResult.stopped) {
23992
24232
  return;
23993
24233
  }
24234
+ const sessionStopped = flowResult.sessionStopped === true;
23994
24235
  const terminalToolNames = await this.getTerminalSessionToolNames(agentName);
23995
24236
  const sessionFailToolNames = terminalToolNames.fail;
23996
24237
  const hasTerminalSessionTools = terminalToolNames.all.size > 0;
23997
- const latestTerminalMessage = hasTerminalSessionTools ? await this.getLatestTerminalSessionMessageAfter(
24238
+ const latestTerminalMessage = !sessionStopped && hasTerminalSessionTools ? await this.getLatestTerminalSessionMessageAfter(
23998
24239
  previousTopLevelMessageId,
23999
24240
  terminalToolNames.all
24000
24241
  ) : null;
24001
- const latest = latestTerminalMessage ?? await this.getLatestTopLevelMessage();
24002
- if (!latest && !hasTerminalSessionTools) {
24242
+ const latest = sessionStopped ? null : latestTerminalMessage ?? await this.getLatestTopLevelMessage();
24243
+ if (!sessionStopped && !latest && !hasTerminalSessionTools) {
24003
24244
  return;
24004
24245
  }
24005
- if (latest && latest.id === previousTopLevelMessageId && !hasTerminalSessionTools) {
24246
+ if (!sessionStopped && latest && latest.id === previousTopLevelMessageId && !hasTerminalSessionTools) {
24006
24247
  return;
24007
24248
  }
24008
24249
  const isTerminalSessionMessage = !!latest && latest.role === "tool" && !!latest.name && terminalToolNames.all.has(latest.name);
24009
24250
  const isFailSessionTerminal = isTerminalSessionMessage && !!latest.name && sessionFailToolNames.has(latest.name);
24010
24251
  const isSuccessfulTerminalSessionMessage = isTerminalSessionMessage && latest?.tool_status !== "error";
24011
- const isFailureWithoutTerminalMessage = hasTerminalSessionTools && !isSuccessfulTerminalSessionMessage;
24252
+ const isFailureWithoutTerminalMessage = !sessionStopped && hasTerminalSessionTools && !isSuccessfulTerminalSessionMessage;
24012
24253
  const isErrorTerminal = latest?.tool_status === "error" || isFailSessionTerminal || isFailureWithoutTerminalMessage;
24013
24254
  let refs = [];
24014
- if (hasTerminalSessionTools) {
24255
+ if (sessionStopped) {
24256
+ refs = [];
24257
+ } else if (hasTerminalSessionTools) {
24015
24258
  refs = this.parseAttachmentRefsJson(latestTerminalMessage?.attachments ?? null) ?? [];
24016
24259
  } else if (latest?.attachments) {
24017
24260
  refs = this.parseAttachmentRefsJson(latest.attachments) ?? [];
@@ -24029,7 +24272,7 @@ ${paths.join("\n")}`;
24029
24272
  parentStub,
24030
24273
  `from-subagent-${threadId}`
24031
24274
  );
24032
- const resultContent = isFailureWithoutTerminalMessage ? this.buildMissingTerminalSessionFailure(flowResult) : latest?.content || (isErrorTerminal ? "Subagent execution failed." : "Subagent completed.");
24275
+ const resultContent = sessionStopped ? flowResult.sessionStopResult?.trim() || "Session stopped." : isFailureWithoutTerminalMessage ? this.buildMissingTerminalSessionFailure(flowResult) : latest?.content || (isErrorTerminal ? "Subagent execution failed." : "Subagent completed.");
24033
24276
  const attachmentSummary = this.formatSubagentAttachmentPathSummary(copiedRefs);
24034
24277
  const messageContent = isErrorTerminal ? `Subagent (reference: ${threadId}) has reported a failure:
24035
24278
 
@@ -24045,7 +24288,7 @@ ${resultContent}${attachmentSummary}`;
24045
24288
  metadata: { subagent_id: threadId }
24046
24289
  });
24047
24290
  }
24048
- const terminalChildRun = hasTerminalSessionTools;
24291
+ const terminalChildRun = sessionStopped || hasTerminalSessionTools;
24049
24292
  await parentStub.updateChildRegistryStatus(
24050
24293
  parentThreadId,
24051
24294
  threadId,
@@ -25458,7 +25701,7 @@ ${resultContent}${attachmentSummary}`;
25458
25701
  max_session_turns: agentDef.maxSessionTurns,
25459
25702
  side_a_label: agentDef.sideA?.label,
25460
25703
  side_a_agent_prompt: qualifyPromptName(agentDef.sideA?.prompt),
25461
- side_a_stop_on_response: agentDef.sideA?.stopOnResponse ?? false,
25704
+ side_a_stop_on_response: agentDef.sideA?.stopOnResponse ?? true,
25462
25705
  side_a_stop_tool: agentDef.sideA?.stopTool,
25463
25706
  side_a_stop_tool_response_property: agentDef.sideA?.stopToolResponseProperty,
25464
25707
  side_a_max_steps: agentDef.sideA?.maxSteps,
@@ -25473,7 +25716,7 @@ ${resultContent}${attachmentSummary}`;
25473
25716
  side_a_session_status_attachments_property: sideASession.status.attachmentsProperty,
25474
25717
  side_b_label: agentDef.sideB?.label,
25475
25718
  side_b_agent_prompt: qualifyPromptName(agentDef.sideB?.prompt),
25476
- side_b_stop_on_response: agentDef.sideB?.stopOnResponse ?? false,
25719
+ side_b_stop_on_response: agentDef.sideB?.stopOnResponse ?? true,
25477
25720
  side_b_stop_tool: agentDef.sideB?.stopTool,
25478
25721
  side_b_stop_tool_response_property: agentDef.sideB?.stopToolResponseProperty,
25479
25722
  side_b_max_steps: agentDef.sideB?.maxSteps,
@@ -25651,7 +25894,7 @@ ${resultContent}${attachmentSummary}`;
25651
25894
  max_session_turns: agentDef.maxSessionTurns,
25652
25895
  side_a_label: agentDef.sideA?.label,
25653
25896
  side_a_agent_prompt: qualifyPromptName(agentDef.sideA?.prompt),
25654
- side_a_stop_on_response: agentDef.sideA?.stopOnResponse ?? false,
25897
+ side_a_stop_on_response: agentDef.sideA?.stopOnResponse ?? true,
25655
25898
  side_a_stop_tool: agentDef.sideA?.stopTool,
25656
25899
  side_a_stop_tool_response_property: agentDef.sideA?.stopToolResponseProperty,
25657
25900
  side_a_max_steps: agentDef.sideA?.maxSteps,
@@ -25666,7 +25909,7 @@ ${resultContent}${attachmentSummary}`;
25666
25909
  side_a_session_status_attachments_property: sideASession.status.attachmentsProperty,
25667
25910
  side_b_label: agentDef.sideB?.label,
25668
25911
  side_b_agent_prompt: qualifyPromptName(agentDef.sideB?.prompt),
25669
- side_b_stop_on_response: agentDef.sideB?.stopOnResponse ?? false,
25912
+ side_b_stop_on_response: agentDef.sideB?.stopOnResponse ?? true,
25670
25913
  side_b_stop_tool: agentDef.sideB?.stopTool,
25671
25914
  side_b_stop_tool_response_property: agentDef.sideB?.stopToolResponseProperty,
25672
25915
  side_b_max_steps: agentDef.sideB?.maxSteps,
@@ -25797,7 +26040,7 @@ ${resultContent}${attachmentSummary}`;
25797
26040
  max_session_turns: agentDef.maxSessionTurns,
25798
26041
  side_a_label: agentDef.sideA?.label,
25799
26042
  side_a_agent_prompt: qualifyPromptName(agentDef.sideA?.prompt),
25800
- side_a_stop_on_response: agentDef.sideA?.stopOnResponse ?? false,
26043
+ side_a_stop_on_response: agentDef.sideA?.stopOnResponse ?? true,
25801
26044
  side_a_stop_tool: agentDef.sideA?.stopTool,
25802
26045
  side_a_stop_tool_response_property: agentDef.sideA?.stopToolResponseProperty,
25803
26046
  side_a_max_steps: agentDef.sideA?.maxSteps,
@@ -25812,7 +26055,7 @@ ${resultContent}${attachmentSummary}`;
25812
26055
  side_a_session_status_attachments_property: sideASession.status.attachmentsProperty,
25813
26056
  side_b_label: agentDef.sideB?.label,
25814
26057
  side_b_agent_prompt: qualifyPromptName(agentDef.sideB?.prompt),
25815
- side_b_stop_on_response: agentDef.sideB?.stopOnResponse ?? false,
26058
+ side_b_stop_on_response: agentDef.sideB?.stopOnResponse ?? true,
25816
26059
  side_b_stop_tool: agentDef.sideB?.stopTool,
25817
26060
  side_b_stop_tool_response_property: agentDef.sideB?.stopToolResponseProperty,
25818
26061
  side_b_max_steps: agentDef.sideB?.maxSteps,