@standardagents/builder 0.11.0-next.0fa8695 → 0.11.0-next.14455ae

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/plugin.d.ts CHANGED
@@ -9,6 +9,12 @@ interface AgentPluginOptions {
9
9
  promptsDir?: string;
10
10
  agentsDir?: string;
11
11
  effectsDir?: string;
12
+ /**
13
+ * Additional provider packages to expose in the UI.
14
+ * First-party providers (@standardagents/openai, @standardagents/openrouter) are always included.
15
+ * @example ['my-custom-provider', '@company/custom-openai']
16
+ */
17
+ providers?: string[];
12
18
  }
13
19
  declare function agentbuilder(options?: AgentPluginOptions): Plugin;
14
20
 
package/dist/plugin.js CHANGED
@@ -397,6 +397,9 @@ declare module 'virtual:@standardagents/builder' {
397
397
  listThreads(params?: {
398
398
  agent_name?: string;
399
399
  user_id?: string;
400
+ search?: string;
401
+ startDate?: number;
402
+ endDate?: number;
400
403
  limit?: number;
401
404
  offset?: number;
402
405
  }): Promise<{ threads: ThreadRegistryEntry[]; total: number }>;
@@ -578,14 +581,91 @@ function needsRegeneration(config) {
578
581
  return false;
579
582
  }
580
583
 
584
+ // src/utils/model-parser.ts
585
+ function getName(content) {
586
+ return content.match(/name:\s*['"]([^'"]+)['"]/)?.[1];
587
+ }
588
+ function getProvider(content) {
589
+ const stringMatch = content.match(/provider:\s*['"]([^'"]+)['"]/)?.[1];
590
+ if (stringMatch) return stringMatch;
591
+ const refMatch = content.match(/provider:\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*[,\n}]/)?.[1];
592
+ return refMatch || void 0;
593
+ }
594
+ function getModel(content) {
595
+ return content.match(/model:\s*['"]([^'"]+)['"]/)?.[1];
596
+ }
597
+ function getInputPrice(content) {
598
+ const match = content.match(/inputPrice:\s*([\d.]+)/);
599
+ return match ? parseFloat(match[1]) : void 0;
600
+ }
601
+ function getOutputPrice(content) {
602
+ const match = content.match(/outputPrice:\s*([\d.]+)/);
603
+ return match ? parseFloat(match[1]) : void 0;
604
+ }
605
+ function getCachedPrice(content) {
606
+ const match = content.match(/cachedPrice:\s*([\d.]+)/);
607
+ return match ? parseFloat(match[1]) : void 0;
608
+ }
609
+ function getIncludedProviders(content) {
610
+ const match = content.match(/includedProviders:\s*\[([^\]]*)\]/);
611
+ if (!match) return void 0;
612
+ const items = match[1].match(/['"]([^'"]+)['"]/g);
613
+ return items ? items.map((s) => s.replace(/['"]/g, "")) : [];
614
+ }
615
+ function getFallbacks(content) {
616
+ const match = content.match(/fallbacks:\s*\[([^\]]*)\]/);
617
+ if (!match) return [];
618
+ const items = match[1].match(/['"]([^'"]+)['"]/g);
619
+ return items ? items.map((s) => s.replace(/['"]/g, "")) : [];
620
+ }
621
+ function getProviderTools(content) {
622
+ const match = content.match(/providerTools:\s*\[([^\]]*)\]/);
623
+ if (!match) return [];
624
+ const items = match[1].match(/['"]([^'"]+)['"]/g);
625
+ return items ? items.map((s) => s.replace(/['"]/g, "")) : [];
626
+ }
627
+ function getCapabilities(content) {
628
+ const match = content.match(/capabilities:\s*\{([^}]*)\}/s);
629
+ if (!match) return void 0;
630
+ const inner = match[1];
631
+ const caps = {};
632
+ const boolMatches = inner.matchAll(/(\w+):\s*(true|false)/g);
633
+ for (const m of boolMatches) {
634
+ caps[m[1]] = m[2] === "true";
635
+ }
636
+ const numMatches = inner.matchAll(/(\w+):\s*(\d+)/g);
637
+ for (const m of numMatches) {
638
+ caps[m[1]] = parseInt(m[2], 10);
639
+ }
640
+ return Object.keys(caps).length > 0 ? caps : void 0;
641
+ }
642
+ function parseModelFile(content) {
643
+ const name = getName(content);
644
+ if (!name) return null;
645
+ return {
646
+ name,
647
+ provider: getProvider(content),
648
+ model: getModel(content),
649
+ inputPrice: getInputPrice(content),
650
+ outputPrice: getOutputPrice(content),
651
+ cachedPrice: getCachedPrice(content),
652
+ includedProviders: getIncludedProviders(content),
653
+ fallbacks: getFallbacks(content),
654
+ providerTools: getProviderTools(content),
655
+ capabilities: getCapabilities(content)
656
+ };
657
+ }
658
+
581
659
  // src/sdk/generators/generateModelFile.ts
582
- function generateModelFile(data) {
660
+ function generateModelFile(data, options) {
661
+ const { providerName, providerPackage } = options;
583
662
  const lines = [
584
663
  `import { defineModel } from '@standardagents/builder';`,
664
+ `import { ${providerName} } from '${providerPackage}';`,
585
665
  "",
586
666
  `export default defineModel({`,
587
667
  ` name: '${escapeString(data.name)}',`,
588
- ` provider: '${escapeString(data.provider)}',`,
668
+ ` provider: ${providerName},`,
589
669
  ` model: '${escapeString(data.model)}',`
590
670
  ];
591
671
  if (data.includedProviders && data.includedProviders.length > 0) {
@@ -594,6 +674,9 @@ function generateModelFile(data) {
594
674
  if (data.fallbacks && data.fallbacks.length > 0) {
595
675
  lines.push(` fallbacks: ${JSON.stringify(data.fallbacks)},`);
596
676
  }
677
+ if (data.providerTools && data.providerTools.length > 0) {
678
+ lines.push(` providerTools: ${JSON.stringify(data.providerTools)},`);
679
+ }
597
680
  if (data.inputPrice !== void 0) {
598
681
  lines.push(` inputPrice: ${data.inputPrice},`);
599
682
  }
@@ -603,6 +686,36 @@ function generateModelFile(data) {
603
686
  if (data.cachedPrice !== void 0) {
604
687
  lines.push(` cachedPrice: ${data.cachedPrice},`);
605
688
  }
689
+ if (data.capabilities && Object.keys(data.capabilities).length > 0) {
690
+ const caps = data.capabilities;
691
+ const capLines = [];
692
+ if (caps.supportsImages !== void 0) {
693
+ capLines.push(` supportsImages: ${caps.supportsImages},`);
694
+ }
695
+ if (caps.supportsToolCalls !== void 0) {
696
+ capLines.push(` supportsToolCalls: ${caps.supportsToolCalls},`);
697
+ }
698
+ if (caps.supportsStreaming !== void 0) {
699
+ capLines.push(` supportsStreaming: ${caps.supportsStreaming},`);
700
+ }
701
+ if (caps.supportsJsonMode !== void 0) {
702
+ capLines.push(` supportsJsonMode: ${caps.supportsJsonMode},`);
703
+ }
704
+ if (caps.maxContextTokens !== void 0) {
705
+ capLines.push(` maxContextTokens: ${caps.maxContextTokens},`);
706
+ }
707
+ if (caps.maxOutputTokens !== void 0) {
708
+ capLines.push(` maxOutputTokens: ${caps.maxOutputTokens},`);
709
+ }
710
+ if (caps.reasoningLevels !== void 0) {
711
+ capLines.push(` reasoningLevels: ${JSON.stringify(caps.reasoningLevels)},`);
712
+ }
713
+ if (capLines.length > 0) {
714
+ lines.push(` capabilities: {`);
715
+ lines.push(...capLines);
716
+ lines.push(` },`);
717
+ }
718
+ }
606
719
  lines.push(`});`);
607
720
  lines.push("");
608
721
  return lines.join("\n");
@@ -857,6 +970,12 @@ function formatToolConfig(config) {
857
970
  if (config.init_user_message_property !== void 0 && config.init_user_message_property !== null) {
858
971
  parts.push(`initUserMessageProperty: '${escapeString2(config.init_user_message_property)}'`);
859
972
  }
973
+ if (config.init_attachments_property !== void 0 && config.init_attachments_property !== null) {
974
+ parts.push(`initAttachmentsProperty: '${escapeString2(config.init_attachments_property)}'`);
975
+ }
976
+ if (config.tenvs && Object.keys(config.tenvs).length > 0) {
977
+ parts.push(`tenvs: ${JSON.stringify(config.tenvs)}`);
978
+ }
860
979
  return `{ ${parts.join(", ")} }`;
861
980
  }
862
981
  function formatReasoningConfig(reasoning) {
@@ -989,6 +1108,9 @@ function generateAgentFile(data) {
989
1108
  if (data.toolDescription) {
990
1109
  lines.push(` toolDescription: '${escapeString3(data.toolDescription)}',`);
991
1110
  }
1111
+ if (data.tenvs && Object.keys(data.tenvs).length > 0) {
1112
+ lines.push(` tenvs: ${JSON.stringify(data.tenvs)},`);
1113
+ }
992
1114
  lines.push(`});`);
993
1115
  lines.push("");
994
1116
  return lines.join("\n");
@@ -1025,8 +1147,15 @@ function escapeString3(str) {
1025
1147
  }
1026
1148
 
1027
1149
  // src/sdk/persistence/index.ts
1150
+ var PROVIDER_PACKAGE_MAP = {
1151
+ openai: { name: "openai", package: "@standardagents/openai" },
1152
+ openrouter: { name: "openrouter", package: "@standardagents/openrouter" },
1153
+ anthropic: { name: "anthropic", package: "@standardagents/anthropic" },
1154
+ google: { name: "google", package: "@standardagents/google" },
1155
+ test: { name: "test", package: "@standardagents/builder/test" }
1156
+ };
1028
1157
  function nameToFilename(name) {
1029
- return name.replace(/[/\\]/g, "__").replace(/[:*?"<>|]/g, "_").replace(/-/g, "_");
1158
+ return name.replace(/[/\\]/g, "__").replace(/[:*?"<>|.]/g, "_").replace(/-/g, "_");
1030
1159
  }
1031
1160
  function getModelFilePath(modelsDir, name) {
1032
1161
  const filename = nameToFilename(name);
@@ -1048,7 +1177,17 @@ async function saveModel(modelsDir, data, overwrite = false) {
1048
1177
  error: `Model file already exists: ${filePath}. Use update to modify existing models.`
1049
1178
  };
1050
1179
  }
1051
- const content = generateModelFile(data);
1180
+ const providerInfo = PROVIDER_PACKAGE_MAP[data.provider];
1181
+ if (!providerInfo) {
1182
+ return {
1183
+ success: false,
1184
+ error: `Unknown provider '${data.provider}'. Must be one of: ${Object.keys(PROVIDER_PACKAGE_MAP).join(", ")}`
1185
+ };
1186
+ }
1187
+ const content = generateModelFile(data, {
1188
+ providerName: providerInfo.name,
1189
+ providerPackage: providerInfo.package
1190
+ });
1052
1191
  await fs2.promises.writeFile(filePath, content, "utf-8");
1053
1192
  return {
1054
1193
  success: true,
@@ -1112,7 +1251,7 @@ function validateModelData(data) {
1112
1251
  if (!data.provider || typeof data.provider !== "string") {
1113
1252
  return "Model provider is required and must be a string";
1114
1253
  }
1115
- const validProviders = ["openai", "openrouter", "anthropic", "google", "test"];
1254
+ const validProviders = Object.keys(PROVIDER_PACKAGE_MAP);
1116
1255
  if (!validProviders.includes(data.provider)) {
1117
1256
  return `Invalid provider '${data.provider}'. Must be one of: ${validProviders.join(", ")}`;
1118
1257
  }
@@ -1636,6 +1775,8 @@ var VIRTUAL_AGENTS_ID = "virtual:@standardagents-agents";
1636
1775
  var RESOLVED_VIRTUAL_AGENTS_ID = "\0" + VIRTUAL_AGENTS_ID;
1637
1776
  var VIRTUAL_EFFECTS_ID = "virtual:@standardagents-effects";
1638
1777
  var RESOLVED_VIRTUAL_EFFECTS_ID = "\0" + VIRTUAL_EFFECTS_ID;
1778
+ var VIRTUAL_PROVIDERS_ID = "virtual:@standardagents-providers";
1779
+ var RESOLVED_VIRTUAL_PROVIDERS_ID = "\0" + VIRTUAL_PROVIDERS_ID;
1639
1780
  var VIRTUAL_BUILDER_ID = "virtual:@standardagents/builder";
1640
1781
  var RESOLVED_VIRTUAL_BUILDER_ID = "\0" + VIRTUAL_BUILDER_ID;
1641
1782
  function scanApiDirectory(dir, baseRoute = "") {
@@ -2112,6 +2253,9 @@ function agentbuilder(options = {}) {
2112
2253
  ];
2113
2254
  const depsToInclude = [
2114
2255
  "zod",
2256
+ "zod/v3",
2257
+ "zod/v4",
2258
+ "zod/v4/core",
2115
2259
  "openai"
2116
2260
  ];
2117
2261
  config.optimizeDeps = config.optimizeDeps || {};
@@ -2152,6 +2296,9 @@ function agentbuilder(options = {}) {
2152
2296
  if (id === VIRTUAL_EFFECTS_ID) {
2153
2297
  return RESOLVED_VIRTUAL_EFFECTS_ID;
2154
2298
  }
2299
+ if (id === VIRTUAL_PROVIDERS_ID) {
2300
+ return RESOLVED_VIRTUAL_PROVIDERS_ID;
2301
+ }
2155
2302
  if (id === VIRTUAL_BUILDER_ID) {
2156
2303
  return RESOLVED_VIRTUAL_BUILDER_ID;
2157
2304
  }
@@ -2227,9 +2374,56 @@ function isPublicRoute(routePath) {
2227
2374
  return true;
2228
2375
  }
2229
2376
 
2377
+ // Provider icon routes are public (used by <img src>)
2378
+ if (routePath.startsWith('/api/providers/') && routePath.includes('/icon')) {
2379
+ return true;
2380
+ }
2381
+
2230
2382
  return false;
2231
2383
  }
2232
2384
 
2385
+ // CORS headers for API responses
2386
+ const CORS_HEADERS = {
2387
+ "Access-Control-Allow-Origin": "*",
2388
+ "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
2389
+ "Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With",
2390
+ "Access-Control-Max-Age": "86400",
2391
+ };
2392
+
2393
+ // Helper to create headers with CORS
2394
+ function corsHeaders(contentType) {
2395
+ return {
2396
+ "Content-Type": contentType,
2397
+ ...CORS_HEADERS,
2398
+ };
2399
+ }
2400
+
2401
+ // Helper to add CORS headers to any Response without touching the body
2402
+ function addCorsHeaders(response) {
2403
+ // Skip WebSocket upgrade responses - they can't be wrapped
2404
+ if (response.status === 101) {
2405
+ return response;
2406
+ }
2407
+
2408
+ // Skip if already has CORS headers
2409
+ if (response.headers.has("Access-Control-Allow-Origin")) {
2410
+ return response;
2411
+ }
2412
+
2413
+ // Create new headers with CORS added
2414
+ const newHeaders = new Headers(response.headers);
2415
+ for (const [key, value] of Object.entries(CORS_HEADERS)) {
2416
+ newHeaders.set(key, value);
2417
+ }
2418
+
2419
+ // Return new Response with same body stream (not cloned, just transferred)
2420
+ return new Response(response.body, {
2421
+ status: response.status,
2422
+ statusText: response.statusText,
2423
+ headers: newHeaders,
2424
+ });
2425
+ }
2426
+
2233
2427
  export async function router(request, env) {
2234
2428
  const url = new URL(request.url);
2235
2429
  const pathname = url.pathname;
@@ -2239,6 +2433,14 @@ export async function router(request, env) {
2239
2433
  return null;
2240
2434
  }
2241
2435
 
2436
+ // Handle CORS preflight requests
2437
+ if (request.method === "OPTIONS") {
2438
+ return new Response(null, {
2439
+ status: 204,
2440
+ headers: CORS_HEADERS,
2441
+ });
2442
+ }
2443
+
2242
2444
  // Strip mount point prefix for route matching, ensuring we keep the leading slash
2243
2445
  let routePath = pathname.slice(MOUNT_POINT.length) || "/";
2244
2446
  if (!routePath.startsWith('/')) {
@@ -2273,7 +2475,7 @@ ${threadRouteCode}
2273
2475
 
2274
2476
  // If requireAuth returns a Response, it's an error (401)
2275
2477
  if (authResult instanceof Response) {
2276
- return authResult;
2478
+ return addCorsHeaders(authResult);
2277
2479
  }
2278
2480
 
2279
2481
  authContext = authResult;
@@ -2292,16 +2494,17 @@ ${threadRouteCode}
2292
2494
  const result = await controller(context);
2293
2495
 
2294
2496
  if (result instanceof Response) {
2295
- return result;
2497
+ return addCorsHeaders(result);
2296
2498
  }
2297
2499
  if (typeof result === "string") {
2298
2500
  return new Response(result, {
2299
- headers: {
2300
- "Content-Type": "text/plain",
2301
- },
2501
+ headers: corsHeaders("text/plain"),
2302
2502
  });
2303
2503
  }
2304
- return Response.json(result);
2504
+ // JSON responses get CORS headers
2505
+ return new Response(JSON.stringify(result), {
2506
+ headers: corsHeaders("application/json"),
2507
+ });
2305
2508
  }
2306
2509
 
2307
2510
  // Serve UI for all other routes (SPA fallback)
@@ -2496,6 +2699,30 @@ ${effectsCode}
2496
2699
  };
2497
2700
 
2498
2701
  export const effectNames = ${JSON.stringify(effects.filter((e) => !e.error).map((e) => e.name))};
2702
+ `;
2703
+ }
2704
+ if (id === RESOLVED_VIRTUAL_PROVIDERS_ID) {
2705
+ const firstPartyProviders = [
2706
+ { name: "openai", package: "@standardagents/openai", label: "OpenAI", envKey: "OPENAI_API_KEY" },
2707
+ { name: "openrouter", package: "@standardagents/openrouter", label: "OpenRouter", envKey: "OPENROUTER_API_KEY" }
2708
+ ];
2709
+ const customProviders = (options.providers || []).map((pkg) => ({
2710
+ name: pkg.split("/").pop() || pkg,
2711
+ package: pkg,
2712
+ label: pkg.split("/").pop() || pkg,
2713
+ envKey: `${(pkg.split("/").pop() || pkg).toUpperCase().replace(/-/g, "_")}_API_KEY`,
2714
+ isCustom: true
2715
+ }));
2716
+ const allProviders = [...firstPartyProviders, ...customProviders];
2717
+ return `// Virtual providers module - lists available LLM provider packages
2718
+ export const providers = ${JSON.stringify(allProviders, null, 2)};
2719
+
2720
+ export const providerNames = ${JSON.stringify(allProviders.map((p) => p.name))};
2721
+
2722
+ // Provider factories - dynamic imports for code splitting
2723
+ export const providerFactories = {
2724
+ ${allProviders.map((p) => ` "${p.name}": async () => (await import("${p.package}")).${p.name},`).join("\n")}
2725
+ };
2499
2726
  `;
2500
2727
  }
2501
2728
  if (id === RESOLVED_VIRTUAL_BUILDER_ID) {
@@ -2609,7 +2836,8 @@ import { DurableAgentBuilder as _BaseDurableAgentBuilder } from '@standardagents
2609
2836
 
2610
2837
  // Import sip WASM module and initializer
2611
2838
  // Static import allows workerd to pre-compile the WASM at bundle time
2612
- import _sipWasm from '@standardagents/sip/dist/sip.wasm';
2839
+ // WASM is bundled in builder's dist to avoid transitive dependency resolution issues
2840
+ import _sipWasm from '@standardagents/builder/dist/sip.wasm';
2613
2841
  import { initWithWasmModule as _initSipWasm } from '@standardagents/sip';
2614
2842
 
2615
2843
  // Re-export router from virtual:@standardagents-routes
@@ -2748,51 +2976,26 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
2748
2976
  try {
2749
2977
  const filePath = path3.join(modelsDir, file);
2750
2978
  const content = fs4.readFileSync(filePath, "utf-8");
2751
- const getName = (c) => c.match(/name:\s*['"]([^'"]+)['"]/)?.[1];
2752
- const getProvider = (c) => c.match(/provider:\s*['"]([^'"]+)['"]/)?.[1];
2753
- const getModel = (c) => c.match(/model:\s*['"]([^'"]+)['"]/)?.[1];
2754
- const getInputPrice = (c) => {
2755
- const match = c.match(/inputPrice:\s*([\d.]+)/);
2756
- return match ? parseFloat(match[1]) : void 0;
2757
- };
2758
- const getOutputPrice = (c) => {
2759
- const match = c.match(/outputPrice:\s*([\d.]+)/);
2760
- return match ? parseFloat(match[1]) : void 0;
2761
- };
2762
- const getCachedPrice = (c) => {
2763
- const match = c.match(/cachedPrice:\s*([\d.]+)/);
2764
- return match ? parseFloat(match[1]) : void 0;
2765
- };
2766
- const getIncludedProviders = (c) => {
2767
- const match = c.match(/includedProviders:\s*\[([^\]]*)\]/);
2768
- if (!match) return void 0;
2769
- const items = match[1].match(/['"]([^'"]+)['"]/g);
2770
- return items ? items.map((s) => s.replace(/['"]/g, "")) : [];
2771
- };
2772
- const getFallbacks = (c) => {
2773
- const match = c.match(/fallbacks:\s*\[([^\]]*)\]/);
2774
- if (!match) return [];
2775
- const items = match[1].match(/['"]([^'"]+)['"]/g);
2776
- return items ? items.map((s) => s.replace(/['"]/g, "")) : [];
2777
- };
2778
- const name = getName(content);
2779
- if (!name) return null;
2780
- const fallbacks = getFallbacks(content);
2781
- const fallbackObjects = fallbacks.map((fallbackName, index) => ({
2979
+ const parsed = parseModelFile(content);
2980
+ if (!parsed || !parsed.name) return null;
2981
+ const fallbackObjects = parsed.fallbacks.map((fallbackName, index) => ({
2782
2982
  id: fallbackName,
2783
2983
  name: fallbackName,
2784
2984
  order: index
2785
2985
  }));
2786
2986
  return {
2787
- id: name,
2788
- name,
2789
- provider: getProvider(content),
2790
- model: getModel(content),
2791
- input_price: getInputPrice(content),
2792
- output_price: getOutputPrice(content),
2793
- cached_price: getCachedPrice(content),
2794
- included_providers: getIncludedProviders(content),
2987
+ id: parsed.name,
2988
+ name: parsed.name,
2989
+ provider: parsed.provider,
2990
+ provider_id: parsed.provider,
2991
+ model: parsed.model,
2992
+ input_price: parsed.inputPrice,
2993
+ output_price: parsed.outputPrice,
2994
+ cached_price: parsed.cachedPrice,
2995
+ included_providers: parsed.includedProviders,
2795
2996
  fallbacks: fallbackObjects,
2997
+ providerTools: parsed.providerTools,
2998
+ capabilities: parsed.capabilities,
2796
2999
  created_at: Math.floor(Date.now() / 1e3)
2797
3000
  };
2798
3001
  } catch (error) {
@@ -2958,9 +3161,9 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
2958
3161
  try {
2959
3162
  const filePath = path3.join(promptsDir, file);
2960
3163
  const content = fs4.readFileSync(filePath, "utf-8");
2961
- const getName = (c) => c.match(/name:\s*['"]([^'"]+)['"]/)?.[1];
3164
+ const getName2 = (c) => c.match(/name:\s*['"]([^'"]+)['"]/)?.[1];
2962
3165
  const getToolDescription = (c) => c.match(/toolDescription:\s*['"]([^'"]+)['"]/)?.[1];
2963
- const getModel = (c) => c.match(/model:\s*['"]([^'"]+)['"]/)?.[1];
3166
+ const getModel2 = (c) => c.match(/model:\s*['"]([^'"]+)['"]/)?.[1];
2964
3167
  const getIncludeChat = (c) => c.match(/includeChat:\s*(true|false)/)?.[1] === "true";
2965
3168
  const getIncludePastTools = (c) => c.match(/includePastTools:\s*(true|false)/)?.[1] === "true";
2966
3169
  const getParallelToolCalls = (c) => c.match(/parallelToolCalls:\s*(true|false)/)?.[1] === "true";
@@ -2980,9 +3183,9 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
2980
3183
  if (arrayMatch) return arrayMatch[1];
2981
3184
  return "";
2982
3185
  };
2983
- const name = getName(content);
3186
+ const name = getName2(content);
2984
3187
  if (!name) return null;
2985
- const modelId = getModel(content);
3188
+ const modelId = getModel2(content);
2986
3189
  const modelDef = modelId ? modelMap[modelId] : null;
2987
3190
  return {
2988
3191
  id: name,
@@ -3153,7 +3356,7 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
3153
3356
  try {
3154
3357
  const filePath = path3.join(agentsDir, file);
3155
3358
  const content = fs4.readFileSync(filePath, "utf-8");
3156
- const getName = (c) => c.match(/name:\s*['"]([^'"]+)['"]/)?.[1];
3359
+ const getName2 = (c) => c.match(/name:\s*['"]([^'"]+)['"]/)?.[1];
3157
3360
  const getTitle = (c) => c.match(/title:\s*['"]([^'"]+)['"]/)?.[1];
3158
3361
  const getType = (c) => c.match(/type:\s*['"]([^'"]+)['"]/)?.[1];
3159
3362
  const getDefaultPrompt = (c) => c.match(/defaultPrompt:\s*['"]([^'"]+)['"]/)?.[1];
@@ -3164,7 +3367,14 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
3164
3367
  const items = match[1].match(/['"]([^'"]+)['"]/g);
3165
3368
  return items ? items.map((s) => s.replace(/['"]/g, "")) : [];
3166
3369
  };
3167
- const name = getName(content);
3370
+ const getSidePrompt = (c, side) => {
3371
+ const sideRegex = new RegExp(`${side}:\\s*\\{([^}]+)\\}`, "s");
3372
+ const sideMatch = c.match(sideRegex);
3373
+ if (!sideMatch) return null;
3374
+ const promptMatch = sideMatch[1].match(/prompt:\s*['"]([^'"]+)['"]/);
3375
+ return promptMatch ? promptMatch[1] : null;
3376
+ };
3377
+ const name = getName2(content);
3168
3378
  if (!name) return null;
3169
3379
  return {
3170
3380
  id: name,
@@ -3174,6 +3384,8 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
3174
3384
  default_prompt: getDefaultPrompt(content) || "",
3175
3385
  default_model: getDefaultModel(content) || "",
3176
3386
  tools: getTools(content),
3387
+ side_a_agent_prompt: getSidePrompt(content, "sideA"),
3388
+ side_b_agent_prompt: getSidePrompt(content, "sideB"),
3177
3389
  created_at: Math.floor(Date.now() / 1e3)
3178
3390
  };
3179
3391
  } catch (error) {