@standardagents/builder 0.10.1-dev.d2d335e → 0.10.1-next.9e1860c

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
@@ -8,6 +8,7 @@ interface AgentPluginOptions {
8
8
  modelsDir?: string;
9
9
  promptsDir?: string;
10
10
  agentsDir?: string;
11
+ effectsDir?: string;
11
12
  }
12
13
  declare function agentbuilder(options?: AgentPluginOptions): Plugin;
13
14
 
package/dist/plugin.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import fs2 from 'fs';
2
2
  import path3 from 'path';
3
3
  import { fileURLToPath } from 'url';
4
- import { createRequire } from 'module';
5
4
 
6
5
  // src/plugin.ts
7
6
  var TSCONFIG_CONTENT = `{
@@ -398,6 +397,9 @@ declare module 'virtual:@standardagents/builder' {
398
397
  listThreads(params?: {
399
398
  agent_name?: string;
400
399
  user_id?: string;
400
+ search?: string;
401
+ startDate?: number;
402
+ endDate?: number;
401
403
  limit?: number;
402
404
  offset?: number;
403
405
  }): Promise<{ threads: ThreadRegistryEntry[]; total: number }>;
@@ -813,16 +815,6 @@ function generatePromptFile(data) {
813
815
  const toolsCode = formatToolsArray(data.tools);
814
816
  lines.push(` tools: ${toolsCode},`);
815
817
  }
816
- if (data.handoffAgents && data.handoffAgents.length > 0) {
817
- const agentsStr = data.handoffAgents.map((a) => `'${escapeString2(a)}'`).join(", ");
818
- lines.push(` handoffAgents: [${agentsStr}],`);
819
- }
820
- if (data.beforeTool) {
821
- lines.push(` beforeTool: '${escapeString2(data.beforeTool)}',`);
822
- }
823
- if (data.afterTool) {
824
- lines.push(` afterTool: '${escapeString2(data.afterTool)}',`);
825
- }
826
818
  if (data.reasoning && hasNonNullProperties(data.reasoning)) {
827
819
  const reasoningCode = formatReasoningConfig(data.reasoning);
828
820
  lines.push(` reasoning: ${reasoningCode},`);
@@ -1000,9 +992,6 @@ function generateAgentFile(data) {
1000
992
  if (data.toolDescription) {
1001
993
  lines.push(` toolDescription: '${escapeString3(data.toolDescription)}',`);
1002
994
  }
1003
- if (data.tags && data.tags.length > 0) {
1004
- lines.push(` tags: ${JSON.stringify(data.tags)},`);
1005
- }
1006
995
  lines.push(`});`);
1007
996
  lines.push("");
1008
997
  return lines.join("\n");
@@ -1022,11 +1011,11 @@ function formatSideConfig(config) {
1022
1011
  if (config.stopToolResponseProperty) {
1023
1012
  parts.push(` stopToolResponseProperty: '${escapeString3(config.stopToolResponseProperty)}',`);
1024
1013
  }
1025
- if (config.maxTurns !== void 0) {
1026
- parts.push(` maxTurns: ${config.maxTurns},`);
1014
+ if (config.maxSteps !== void 0) {
1015
+ parts.push(` maxSteps: ${config.maxSteps},`);
1027
1016
  }
1028
- if (config.endConversationTool) {
1029
- parts.push(` endConversationTool: '${escapeString3(config.endConversationTool)}',`);
1017
+ if (config.endSessionTool) {
1018
+ parts.push(` endSessionTool: '${escapeString3(config.endSessionTool)}',`);
1030
1019
  }
1031
1020
  if (config.manualStopCondition !== void 0) {
1032
1021
  parts.push(` manualStopCondition: ${config.manualStopCondition},`);
@@ -1126,7 +1115,7 @@ function validateModelData(data) {
1126
1115
  if (!data.provider || typeof data.provider !== "string") {
1127
1116
  return "Model provider is required and must be a string";
1128
1117
  }
1129
- const validProviders = ["openai", "openrouter", "anthropic", "google"];
1118
+ const validProviders = ["openai", "openrouter", "anthropic", "google", "test"];
1130
1119
  if (!validProviders.includes(data.provider)) {
1131
1120
  return `Invalid provider '${data.provider}'. Must be one of: ${validProviders.join(", ")}`;
1132
1121
  }
@@ -1173,11 +1162,8 @@ function transformPromptData(data) {
1173
1162
  required_schema: "requiredSchema",
1174
1163
  include_chat: "includeChat",
1175
1164
  include_past_tools: "includePastTools",
1176
- before_tool: "beforeTool",
1177
- after_tool: "afterTool",
1178
1165
  parallel_tool_calls: "parallelToolCalls",
1179
1166
  tool_choice: "toolChoice",
1180
- handoff_agents: "handoffAgents",
1181
1167
  reasoning_effort: "reasoningEffort",
1182
1168
  reasoning_max_tokens: "reasoningMaxTokens",
1183
1169
  reasoning_exclude: "reasoningExclude",
@@ -1328,9 +1314,6 @@ function validatePromptData(data) {
1328
1314
  if (data.tools !== void 0 && !Array.isArray(data.tools)) {
1329
1315
  return "tools must be an array";
1330
1316
  }
1331
- if (data.handoffAgents !== void 0 && !Array.isArray(data.handoffAgents)) {
1332
- return "handoffAgents must be an array";
1333
- }
1334
1317
  if (data.reasoning !== void 0) {
1335
1318
  if (typeof data.reasoning !== "object") {
1336
1319
  return "reasoning must be an object";
@@ -1375,11 +1358,11 @@ function transformAgentData(data) {
1375
1358
  if (data.side_a_stop_tool_response_property) {
1376
1359
  transformed.sideA.stopToolResponseProperty = data.side_a_stop_tool_response_property;
1377
1360
  }
1378
- if (data.side_a_max_turns !== void 0) {
1379
- transformed.sideA.maxTurns = data.side_a_max_turns;
1361
+ if (data.side_a_max_steps !== void 0) {
1362
+ transformed.sideA.maxSteps = data.side_a_max_steps;
1380
1363
  }
1381
- if (data.side_a_end_conversation_tool) {
1382
- transformed.sideA.endConversationTool = data.side_a_end_conversation_tool;
1364
+ if (data.side_a_end_session_tool) {
1365
+ transformed.sideA.endSessionTool = data.side_a_end_session_tool;
1383
1366
  }
1384
1367
  if (data.side_a_manual_stop_condition !== void 0) {
1385
1368
  transformed.sideA.manualStopCondition = data.side_a_manual_stop_condition;
@@ -1400,11 +1383,11 @@ function transformAgentData(data) {
1400
1383
  if (data.side_b_stop_tool_response_property) {
1401
1384
  transformed.sideB.stopToolResponseProperty = data.side_b_stop_tool_response_property;
1402
1385
  }
1403
- if (data.side_b_max_turns !== void 0) {
1404
- transformed.sideB.maxTurns = data.side_b_max_turns;
1386
+ if (data.side_b_max_steps !== void 0) {
1387
+ transformed.sideB.maxSteps = data.side_b_max_steps;
1405
1388
  }
1406
- if (data.side_b_end_conversation_tool) {
1407
- transformed.sideB.endConversationTool = data.side_b_end_conversation_tool;
1389
+ if (data.side_b_end_session_tool) {
1390
+ transformed.sideB.endSessionTool = data.side_b_end_session_tool;
1408
1391
  }
1409
1392
  if (data.side_b_manual_stop_condition !== void 0) {
1410
1393
  transformed.sideB.manualStopCondition = data.side_b_manual_stop_condition;
@@ -1416,9 +1399,6 @@ function transformAgentData(data) {
1416
1399
  if (data.tool_description) {
1417
1400
  transformed.toolDescription = data.tool_description;
1418
1401
  }
1419
- if (data.tags) {
1420
- transformed.tags = data.tags;
1421
- }
1422
1402
  return transformed;
1423
1403
  }
1424
1404
  function getAgentFilePath(agentsDir, name) {
@@ -1606,9 +1586,9 @@ function validateAgentData(data) {
1606
1586
  if (data.sideA.stopTool && !data.sideA.stopToolResponseProperty) {
1607
1587
  return "sideA.stopToolResponseProperty is required when sideA.stopTool is set";
1608
1588
  }
1609
- if (data.sideA.maxTurns !== void 0) {
1610
- if (typeof data.sideA.maxTurns !== "number" || data.sideA.maxTurns <= 0) {
1611
- return "sideA.maxTurns must be a positive number";
1589
+ if (data.sideA.maxSteps !== void 0) {
1590
+ if (typeof data.sideA.maxSteps !== "number" || data.sideA.maxSteps <= 0) {
1591
+ return "sideA.maxSteps must be a positive number";
1612
1592
  }
1613
1593
  }
1614
1594
  if (data.type === "dual_ai") {
@@ -1621,9 +1601,9 @@ function validateAgentData(data) {
1621
1601
  if (data.sideB.stopTool && !data.sideB.stopToolResponseProperty) {
1622
1602
  return "sideB.stopToolResponseProperty is required when sideB.stopTool is set";
1623
1603
  }
1624
- if (data.sideB.maxTurns !== void 0) {
1625
- if (typeof data.sideB.maxTurns !== "number" || data.sideB.maxTurns <= 0) {
1626
- return "sideB.maxTurns must be a positive number";
1604
+ if (data.sideB.maxSteps !== void 0) {
1605
+ if (typeof data.sideB.maxSteps !== "number" || data.sideB.maxSteps <= 0) {
1606
+ return "sideB.maxSteps must be a positive number";
1627
1607
  }
1628
1608
  }
1629
1609
  }
@@ -1635,21 +1615,10 @@ function validateAgentData(data) {
1635
1615
  return "maxSessionTurns must be a positive number";
1636
1616
  }
1637
1617
  }
1638
- if (data.tags !== void 0) {
1639
- if (!Array.isArray(data.tags)) {
1640
- return "tags must be an array";
1641
- }
1642
- for (const tag of data.tags) {
1643
- if (typeof tag !== "string") {
1644
- return "Each tag must be a string";
1645
- }
1646
- }
1647
- }
1648
1618
  return null;
1649
1619
  }
1650
1620
 
1651
1621
  // src/plugin.ts
1652
- createRequire(import.meta.url);
1653
1622
  var VIRTUAL_TOOLS_ID = "virtual:@standardagents-tools";
1654
1623
  var RESOLVED_VIRTUAL_TOOLS_ID = "\0" + VIRTUAL_TOOLS_ID;
1655
1624
  var VIRTUAL_ROUTES_ID = "virtual:@standardagents-routes";
@@ -1668,6 +1637,8 @@ var VIRTUAL_PROMPTS_ID = "virtual:@standardagents-prompts";
1668
1637
  var RESOLVED_VIRTUAL_PROMPTS_ID = "\0" + VIRTUAL_PROMPTS_ID;
1669
1638
  var VIRTUAL_AGENTS_ID = "virtual:@standardagents-agents";
1670
1639
  var RESOLVED_VIRTUAL_AGENTS_ID = "\0" + VIRTUAL_AGENTS_ID;
1640
+ var VIRTUAL_EFFECTS_ID = "virtual:@standardagents-effects";
1641
+ var RESOLVED_VIRTUAL_EFFECTS_ID = "\0" + VIRTUAL_EFFECTS_ID;
1671
1642
  var VIRTUAL_BUILDER_ID = "virtual:@standardagents/builder";
1672
1643
  var RESOLVED_VIRTUAL_BUILDER_ID = "\0" + VIRTUAL_BUILDER_ID;
1673
1644
  function scanApiDirectory(dir, baseRoute = "") {
@@ -1843,6 +1814,33 @@ async function scanPromptsDirectory(dir) {
1843
1814
  async function scanAgentsDirectory(dir) {
1844
1815
  return scanConfigDirectory(dir, /export\s+default\s+defineAgent/);
1845
1816
  }
1817
+ async function scanEffectsDirectory(dir) {
1818
+ const effects = [];
1819
+ if (!fs2.existsSync(dir)) {
1820
+ return effects;
1821
+ }
1822
+ const entries = await fs2.promises.readdir(dir, { withFileTypes: true });
1823
+ for (const entry of entries) {
1824
+ if (entry.isFile() && entry.name.endsWith(".ts")) {
1825
+ const fileName = entry.name.replace(".ts", "");
1826
+ const filePath = path3.join(dir, entry.name);
1827
+ const importPath = "./" + path3.relative(process.cwd(), filePath).replace(/\\/g, "/");
1828
+ if (fileName === "CLAUDE" || fileName.startsWith("_")) {
1829
+ continue;
1830
+ }
1831
+ try {
1832
+ const content = fs2.readFileSync(filePath, "utf-8");
1833
+ if (!content.includes("defineEffect")) {
1834
+ continue;
1835
+ }
1836
+ } catch {
1837
+ continue;
1838
+ }
1839
+ effects.push({ name: fileName, importPath });
1840
+ }
1841
+ }
1842
+ return effects;
1843
+ }
1846
1844
  function parseRequestBody(req) {
1847
1845
  return new Promise((resolve, reject) => {
1848
1846
  let body = "";
@@ -1873,6 +1871,7 @@ function agentbuilder(options = {}) {
1873
1871
  const modelsDir = options.modelsDir ? path3.resolve(process.cwd(), options.modelsDir) : path3.resolve(process.cwd(), "agents/models");
1874
1872
  const promptsDir = options.promptsDir ? path3.resolve(process.cwd(), options.promptsDir) : path3.resolve(process.cwd(), "agents/prompts");
1875
1873
  const agentsDir = options.agentsDir ? path3.resolve(process.cwd(), options.agentsDir) : path3.resolve(process.cwd(), "agents/agents");
1874
+ const effectsDir = options.effectsDir ? path3.resolve(process.cwd(), options.effectsDir) : path3.resolve(process.cwd(), "agents/effects");
1876
1875
  const outputDir = path3.resolve(process.cwd(), ".agents");
1877
1876
  const typeGenConfig = {
1878
1877
  modelsDir,
@@ -2072,7 +2071,15 @@ function agentbuilder(options = {}) {
2072
2071
  "zod",
2073
2072
  "openai"
2074
2073
  ];
2074
+ const currentDir = path3.dirname(fileURLToPath(import.meta.url));
2075
+ const isInDist = currentDir.endsWith("dist");
2076
+ const builderClientDir = path3.resolve(
2077
+ currentDir,
2078
+ isInDist ? "./client" : "../dist/client"
2079
+ );
2075
2080
  return {
2081
+ // Set publicDir to builder's client assets so Cloudflare plugin preserves assets config
2082
+ publicDir: fs2.existsSync(builderClientDir) ? builderClientDir : void 0,
2076
2083
  optimizeDeps: {
2077
2084
  // Exclude our packages from pre-bundling - they contain cloudflare:workers imports
2078
2085
  // that cannot be resolved during dependency optimization
@@ -2145,6 +2152,9 @@ function agentbuilder(options = {}) {
2145
2152
  if (id === VIRTUAL_AGENTS_ID) {
2146
2153
  return RESOLVED_VIRTUAL_AGENTS_ID;
2147
2154
  }
2155
+ if (id === VIRTUAL_EFFECTS_ID) {
2156
+ return RESOLVED_VIRTUAL_EFFECTS_ID;
2157
+ }
2148
2158
  if (id === VIRTUAL_BUILDER_ID) {
2149
2159
  return RESOLVED_VIRTUAL_BUILDER_ID;
2150
2160
  }
@@ -2223,6 +2233,48 @@ function isPublicRoute(routePath) {
2223
2233
  return false;
2224
2234
  }
2225
2235
 
2236
+ // CORS headers for API responses
2237
+ const CORS_HEADERS = {
2238
+ "Access-Control-Allow-Origin": "*",
2239
+ "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
2240
+ "Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With",
2241
+ "Access-Control-Max-Age": "86400",
2242
+ };
2243
+
2244
+ // Helper to create headers with CORS
2245
+ function corsHeaders(contentType) {
2246
+ return {
2247
+ "Content-Type": contentType,
2248
+ ...CORS_HEADERS,
2249
+ };
2250
+ }
2251
+
2252
+ // Helper to add CORS headers to any Response without touching the body
2253
+ function addCorsHeaders(response) {
2254
+ // Skip WebSocket upgrade responses - they can't be wrapped
2255
+ if (response.status === 101) {
2256
+ return response;
2257
+ }
2258
+
2259
+ // Skip if already has CORS headers
2260
+ if (response.headers.has("Access-Control-Allow-Origin")) {
2261
+ return response;
2262
+ }
2263
+
2264
+ // Create new headers with CORS added
2265
+ const newHeaders = new Headers(response.headers);
2266
+ for (const [key, value] of Object.entries(CORS_HEADERS)) {
2267
+ newHeaders.set(key, value);
2268
+ }
2269
+
2270
+ // Return new Response with same body stream (not cloned, just transferred)
2271
+ return new Response(response.body, {
2272
+ status: response.status,
2273
+ statusText: response.statusText,
2274
+ headers: newHeaders,
2275
+ });
2276
+ }
2277
+
2226
2278
  export async function router(request, env) {
2227
2279
  const url = new URL(request.url);
2228
2280
  const pathname = url.pathname;
@@ -2232,6 +2284,14 @@ export async function router(request, env) {
2232
2284
  return null;
2233
2285
  }
2234
2286
 
2287
+ // Handle CORS preflight requests
2288
+ if (request.method === "OPTIONS") {
2289
+ return new Response(null, {
2290
+ status: 204,
2291
+ headers: CORS_HEADERS,
2292
+ });
2293
+ }
2294
+
2235
2295
  // Strip mount point prefix for route matching, ensuring we keep the leading slash
2236
2296
  let routePath = pathname.slice(MOUNT_POINT.length) || "/";
2237
2297
  if (!routePath.startsWith('/')) {
@@ -2266,7 +2326,7 @@ ${threadRouteCode}
2266
2326
 
2267
2327
  // If requireAuth returns a Response, it's an error (401)
2268
2328
  if (authResult instanceof Response) {
2269
- return authResult;
2329
+ return addCorsHeaders(authResult);
2270
2330
  }
2271
2331
 
2272
2332
  authContext = authResult;
@@ -2285,16 +2345,17 @@ ${threadRouteCode}
2285
2345
  const result = await controller(context);
2286
2346
 
2287
2347
  if (result instanceof Response) {
2288
- return result;
2348
+ return addCorsHeaders(result);
2289
2349
  }
2290
2350
  if (typeof result === "string") {
2291
2351
  return new Response(result, {
2292
- headers: {
2293
- "Content-Type": "text/plain",
2294
- },
2352
+ headers: corsHeaders("text/plain"),
2295
2353
  });
2296
2354
  }
2297
- return Response.json(result);
2355
+ // JSON responses get CORS headers
2356
+ return new Response(JSON.stringify(result), {
2357
+ headers: corsHeaders("application/json"),
2358
+ });
2298
2359
  }
2299
2360
 
2300
2361
  // Serve UI for all other routes (SPA fallback)
@@ -2309,13 +2370,15 @@ async function serveUI(pathname, env) {
2309
2370
  // Create a proper request for the asset path
2310
2371
  // Use a dummy origin since we only care about the path
2311
2372
  // Re-add mount point since pathname was stripped by router
2312
- const assetUrl = \`http://localhost\${MOUNT_POINT}\${pathname}\`;
2373
+ // Handle root mountPoint "/" specially to avoid double slashes
2374
+ const mountPrefix = MOUNT_POINT === "/" ? "" : MOUNT_POINT;
2375
+ const assetUrl = \`http://localhost\${mountPrefix}\${pathname}\`;
2313
2376
  let response = await env.ASSETS.fetch(assetUrl);
2314
2377
 
2315
2378
  // If not found, fall back to index.html for SPA routing
2316
2379
  const isIndexHtml = response.status === 404 || pathname === "/" || !pathname.includes(".");
2317
2380
  if (isIndexHtml) {
2318
- response = await env.ASSETS.fetch(\`http://localhost\${MOUNT_POINT}/index.html\`);
2381
+ response = await env.ASSETS.fetch(\`http://localhost\${mountPrefix}/index.html\`);
2319
2382
 
2320
2383
  // Transform HTML to use configured mount point
2321
2384
  if (response.status === 200) {
@@ -2462,6 +2525,31 @@ ${agentsCode}
2462
2525
  };
2463
2526
 
2464
2527
  export const agentNames = ${JSON.stringify(agents.filter((a) => !a.error).map((a) => a.name))};
2528
+ `;
2529
+ }
2530
+ if (id === RESOLVED_VIRTUAL_EFFECTS_ID) {
2531
+ const effects = await scanEffectsDirectory(effectsDir);
2532
+ const effectsCode = effects.map(({ name, importPath, error }) => {
2533
+ if (error) {
2534
+ const escapedError = error.replace(/"/g, '\\"').replace(/\n/g, "\\n");
2535
+ return ` "${name}": async () => { throw new Error("${escapedError}"); },`;
2536
+ } else {
2537
+ return ` "${name}": async () => {
2538
+ try {
2539
+ return (await import("${importPath}")).default;
2540
+ } catch (error) {
2541
+ console.error('Failed to import effect ${name}:', error);
2542
+ throw error;
2543
+ }
2544
+ },`;
2545
+ }
2546
+ }).join("\n");
2547
+ return `// Virtual agent effects module
2548
+ export const effects = {
2549
+ ${effectsCode}
2550
+ };
2551
+
2552
+ export const effectNames = ${JSON.stringify(effects.filter((e) => !e.error).map((e) => e.name))};
2465
2553
  `;
2466
2554
  }
2467
2555
  if (id === RESOLVED_VIRTUAL_BUILDER_ID) {
@@ -2470,6 +2558,7 @@ export const agentNames = ${JSON.stringify(agents.filter((a) => !a.error).map((a
2470
2558
  const models = await scanModelsDirectory(modelsDir);
2471
2559
  const prompts = await scanPromptsDirectory(promptsDir);
2472
2560
  const agents = await scanAgentsDirectory(agentsDir);
2561
+ const effects = await scanEffectsDirectory(effectsDir);
2473
2562
  const toAbsolutePath = (relativePath) => {
2474
2563
  if (relativePath.startsWith("./")) {
2475
2564
  return path3.resolve(process.cwd(), relativePath).replace(/\\/g, "/");
@@ -2548,6 +2637,22 @@ export const agentNames = ${JSON.stringify(agents.filter((a) => !a.error).map((a
2548
2637
  console.error('Failed to import agent ${name}:', error);
2549
2638
  throw error;
2550
2639
  }
2640
+ },`;
2641
+ }
2642
+ }).join("\n");
2643
+ const effectsCode = effects.map(({ name, importPath, error }) => {
2644
+ const absPath = toAbsolutePath(importPath);
2645
+ if (error) {
2646
+ const escapedError = error.replace(/"/g, '\\"').replace(/\n/g, "\\n");
2647
+ return ` "${name}": async () => { throw new Error("${escapedError}"); },`;
2648
+ } else {
2649
+ return ` "${name}": async () => {
2650
+ try {
2651
+ return (await import("${absPath}")).default;
2652
+ } catch (error) {
2653
+ console.error('Failed to import effect ${name}:', error);
2654
+ throw error;
2655
+ }
2551
2656
  },`;
2552
2657
  }
2553
2658
  }).join("\n");
@@ -2558,7 +2663,8 @@ import { DurableAgentBuilder as _BaseDurableAgentBuilder } from '@standardagents
2558
2663
 
2559
2664
  // Import sip WASM module and initializer
2560
2665
  // Static import allows workerd to pre-compile the WASM at bundle time
2561
- import _sipWasm from '@standardagents/sip/dist/sip.wasm';
2666
+ // WASM is bundled in builder's dist to avoid transitive dependency resolution issues
2667
+ import _sipWasm from '@standardagents/builder/dist/sip.wasm';
2562
2668
  import { initWithWasmModule as _initSipWasm } from '@standardagents/sip';
2563
2669
 
2564
2670
  // Re-export router from virtual:@standardagents-routes
@@ -2585,6 +2691,10 @@ const _agents = {
2585
2691
  ${agentsCode}
2586
2692
  };
2587
2693
 
2694
+ const _effects = {
2695
+ ${effectsCode}
2696
+ };
2697
+
2588
2698
  /**
2589
2699
  * DurableThread with all virtual module methods already implemented.
2590
2700
  * Simply extend this class in your agents/Thread.ts file.
@@ -2619,6 +2729,10 @@ export class DurableThread extends _BaseDurableThread {
2619
2729
  agents() {
2620
2730
  return _agents;
2621
2731
  }
2732
+
2733
+ effects() {
2734
+ return _effects;
2735
+ }
2622
2736
  }
2623
2737
 
2624
2738
  /**
@@ -2645,6 +2759,10 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
2645
2759
  agents() {
2646
2760
  return _agents;
2647
2761
  }
2762
+
2763
+ effects() {
2764
+ return _effects;
2765
+ }
2648
2766
  }
2649
2767
  `;
2650
2768
  }
@@ -2657,6 +2775,7 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
2657
2775
  this.addWatchFile(modelsDir);
2658
2776
  this.addWatchFile(promptsDir);
2659
2777
  this.addWatchFile(agentsDir);
2778
+ this.addWatchFile(effectsDir);
2660
2779
  },
2661
2780
  configureServer(server) {
2662
2781
  server.watcher.on("add", async (file) => {
@@ -2901,20 +3020,12 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
2901
3020
  const getIncludePastTools = (c) => c.match(/includePastTools:\s*(true|false)/)?.[1] === "true";
2902
3021
  const getParallelToolCalls = (c) => c.match(/parallelToolCalls:\s*(true|false)/)?.[1] === "true";
2903
3022
  const getToolChoice = (c) => c.match(/toolChoice:\s*['"]([^'"]+)['"]/)?.[1];
2904
- const getBeforeTool = (c) => c.match(/beforeTool:\s*['"]([^'"]+)['"]/)?.[1];
2905
- const getAfterTool = (c) => c.match(/afterTool:\s*['"]([^'"]+)['"]/)?.[1];
2906
3023
  const getTools = (c) => {
2907
3024
  const match = c.match(/tools:\s*\[([^\]]*)\]/);
2908
3025
  if (!match) return [];
2909
3026
  const items = match[1].match(/['"]([^'"]+)['"]/g);
2910
3027
  return items ? items.map((s) => s.replace(/['"]/g, "")) : [];
2911
3028
  };
2912
- const getHandoffAgents = (c) => {
2913
- const match = c.match(/handoffAgents:\s*\[([^\]]*)\]/);
2914
- if (!match) return [];
2915
- const items = match[1].match(/['"]([^'"]+)['"]/g);
2916
- return items ? items.map((s) => s.replace(/['"]/g, "")) : [];
2917
- };
2918
3029
  const getPrompt = (c) => {
2919
3030
  const backtickMatch = c.match(/prompt:\s*`([\s\S]*?)`/);
2920
3031
  if (backtickMatch) return backtickMatch[1];
@@ -2942,10 +3053,7 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
2942
3053
  include_past_tools: getIncludePastTools(content),
2943
3054
  parallel_tool_calls: getParallelToolCalls(content),
2944
3055
  tool_choice: getToolChoice(content) || "auto",
2945
- before_tool: getBeforeTool(content) || null,
2946
- after_tool: getAfterTool(content) || null,
2947
3056
  tools: getTools(content),
2948
- prompts: getHandoffAgents(content),
2949
3057
  reasoning: null,
2950
3058
  // Complex to parse
2951
3059
  created_at: Math.floor(Date.now() / 1e3)
@@ -3111,6 +3219,13 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
3111
3219
  const items = match[1].match(/['"]([^'"]+)['"]/g);
3112
3220
  return items ? items.map((s) => s.replace(/['"]/g, "")) : [];
3113
3221
  };
3222
+ const getSidePrompt = (c, side) => {
3223
+ const sideRegex = new RegExp(`${side}:\\s*\\{([^}]+)\\}`, "s");
3224
+ const sideMatch = c.match(sideRegex);
3225
+ if (!sideMatch) return null;
3226
+ const promptMatch = sideMatch[1].match(/prompt:\s*['"]([^'"]+)['"]/);
3227
+ return promptMatch ? promptMatch[1] : null;
3228
+ };
3114
3229
  const name = getName(content);
3115
3230
  if (!name) return null;
3116
3231
  return {
@@ -3121,6 +3236,8 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
3121
3236
  default_prompt: getDefaultPrompt(content) || "",
3122
3237
  default_model: getDefaultModel(content) || "",
3123
3238
  tools: getTools(content),
3239
+ side_a_agent_prompt: getSidePrompt(content, "sideA"),
3240
+ side_b_agent_prompt: getSidePrompt(content, "sideB"),
3124
3241
  created_at: Math.floor(Date.now() / 1e3)
3125
3242
  };
3126
3243
  } catch (error) {