@axiom-lattice/core 2.1.79 → 2.1.81

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.mjs CHANGED
@@ -1,245 +1,28 @@
1
- // src/base/BaseLatticeManager.ts
2
- var _BaseLatticeManager = class _BaseLatticeManager {
3
- /**
4
- * 受保护的构造函数,防止外部直接实例化
5
- */
6
- constructor() {
7
- }
8
- /**
9
- * 获取管理器实例(由子类实现)
10
- */
11
- static getInstance() {
12
- throw new Error("\u5FC5\u987B\u7531\u5B50\u7C7B\u5B9E\u73B0");
13
- }
14
- /**
15
- * 构造完整的键名,包含类型前缀和租户ID
16
- * @param tenantId 租户ID,全局共享使用 "default"
17
- * @param key 原始键名
18
- */
19
- getFullKey(tenantId, key) {
20
- return `${this.getLatticeType()}:${tenantId}:${key}`;
21
- }
22
- // ========== 带租户的新API ==========
23
- /**
24
- * 带租户的注册项目
25
- * @param tenantId 租户ID
26
- * @param key 项目键名(不含前缀)
27
- * @param item 项目实例
28
- */
29
- registerWithTenant(tenantId, key, item) {
30
- const fullKey = this.getFullKey(tenantId, key);
31
- if (_BaseLatticeManager.registry.has(fullKey)) {
32
- throw new Error(`\u9879\u76EE "${fullKey}" \u5DF2\u7ECF\u5B58\u5728\uFF0C\u65E0\u6CD5\u91CD\u590D\u6CE8\u518C`);
33
- }
34
- _BaseLatticeManager.registry.set(fullKey, item);
35
- }
36
- /**
37
- * 带租户的获取指定项目(同步)
38
- * @param tenantId 租户ID
39
- * @param key 项目键名(不含前缀)
40
- */
41
- getWithTenant(tenantId, key) {
42
- const fullKey = this.getFullKey(tenantId, key);
43
- return _BaseLatticeManager.registry.get(fullKey);
44
- }
45
- /**
46
- * 带租户的获取指定项目(异步,支持从store回退加载)
47
- * 如果内存中不存在且子类实现了loadItemFromStore,则尝试从store加载
48
- * @param tenantId 租户ID
49
- * @param key 项目键名(不含前缀)
50
- * @returns 项目实例,如果未找到则返回undefined
51
- */
52
- async getOrLoadWithTenant(tenantId, key) {
53
- const item = this.getWithTenant(tenantId, key);
54
- if (item !== void 0) {
55
- return item;
56
- }
57
- if (this.loadItemFromStore) {
58
- const loadedItem = await this.loadItemFromStore(tenantId, key);
59
- if (loadedItem !== void 0) {
60
- this.registerWithTenant(tenantId, key, loadedItem);
61
- return loadedItem;
62
- }
63
- }
64
- return void 0;
65
- }
66
- /**
67
- * 带租户的检查项目是否存在(同步)
68
- * @param tenantId 租户ID
69
- * @param key 项目键名(不含前缀)
70
- */
71
- hasWithTenant(tenantId, key) {
72
- const fullKey = this.getFullKey(tenantId, key);
73
- return _BaseLatticeManager.registry.has(fullKey);
74
- }
75
- /**
76
- * 带租户的检查项目是否存在(异步,支持从store回退加载)
77
- * 如果内存中不存在且子类实现了loadItemFromStore,则尝试从store加载
78
- * @param tenantId 租户ID
79
- * @param key 项目键名(不含前缀)
80
- * @returns 如果存在或能从store加载则返回true
81
- */
82
- async hasOrLoadWithTenant(tenantId, key) {
83
- if (this.hasWithTenant(tenantId, key)) {
84
- return true;
85
- }
86
- if (this.loadItemFromStore) {
87
- const loadedItem = await this.loadItemFromStore(tenantId, key);
88
- if (loadedItem !== void 0) {
89
- this.registerWithTenant(tenantId, key, loadedItem);
90
- return true;
91
- }
92
- }
93
- return false;
94
- }
95
- /**
96
- * 带租户的移除项目
97
- * @param tenantId 租户ID
98
- * @param key 项目键名(不含前缀)
99
- */
100
- removeWithTenant(tenantId, key) {
101
- const fullKey = this.getFullKey(tenantId, key);
102
- return _BaseLatticeManager.registry.delete(fullKey);
103
- }
104
- /**
105
- * 获取指定租户的所有项目
106
- * @param tenantId 租户ID
107
- */
108
- getAllByTenant(tenantId) {
109
- const prefix = `${this.getLatticeType()}:${tenantId}:`;
110
- const result = [];
111
- for (const [key, value] of _BaseLatticeManager.registry.entries()) {
112
- if (key.startsWith(prefix)) {
113
- result.push(value);
114
- }
115
- }
116
- return result;
117
- }
118
- /**
119
- * 清空指定租户的所有项目
120
- * @param tenantId 租户ID
121
- */
122
- clearByTenant(tenantId) {
123
- const prefix = `${this.getLatticeType()}:${tenantId}:`;
124
- const keysToDelete = [];
125
- for (const key of _BaseLatticeManager.registry.keys()) {
126
- if (key.startsWith(prefix)) {
127
- keysToDelete.push(key);
128
- }
129
- }
130
- for (const key of keysToDelete) {
131
- _BaseLatticeManager.registry.delete(key);
132
- }
133
- }
134
- // ========== 向后兼容的旧API(使用 default 租户) ==========
135
- /**
136
- * 注册项目(向后兼容,使用 "default" 租户)
137
- * @deprecated Use registerWithTenant(tenantId, key, item) instead
138
- * @param key 项目键名(不含前缀)
139
- * @param item 项目实例
140
- */
141
- register(key, item) {
142
- this.registerWithTenant("default", key, item);
143
- }
144
- /**
145
- * 获取指定项目(向后兼容,使用 "default" 租户)
146
- * @deprecated Use getWithTenant(tenantId, key) instead
147
- * @param key 项目键名(不含前缀)
148
- */
149
- get(key) {
150
- return this.getWithTenant("default", key);
151
- }
152
- /**
153
- * 获取所有当前类型的项目(向后兼容,包含所有租户)
154
- */
155
- getAll() {
156
- const prefix = `${this.getLatticeType()}:`;
157
- const result = [];
158
- for (const [key, value] of _BaseLatticeManager.registry.entries()) {
159
- if (key.startsWith(prefix)) {
160
- result.push(value);
161
- }
162
- }
163
- return result;
164
- }
165
- /**
166
- * 检查项目是否存在(向后兼容,使用 "default" 租户)
167
- * @deprecated Use hasWithTenant(tenantId, key) instead
168
- * @param key 项目键名(不含前缀)
169
- */
170
- has(key) {
171
- return this.hasWithTenant("default", key);
172
- }
173
- /**
174
- * 移除项目(向后兼容,使用 "default" 租户)
175
- * @deprecated Use removeWithTenant(tenantId, key) instead
176
- * @param key 项目键名(不含前缀)
177
- */
178
- remove(key) {
179
- return this.removeWithTenant("default", key);
180
- }
181
- /**
182
- * 清空当前类型的所有项目(向后兼容,包含所有租户)
183
- */
184
- clear() {
185
- const prefix = `${this.getLatticeType()}:`;
186
- const keysToDelete = [];
187
- for (const key of _BaseLatticeManager.registry.keys()) {
188
- if (key.startsWith(prefix)) {
189
- keysToDelete.push(key);
190
- }
191
- }
192
- for (const key of keysToDelete) {
193
- _BaseLatticeManager.registry.delete(key);
194
- }
195
- }
196
- /**
197
- * 获取当前类型的项目数量(向后兼容,包含所有租户)
198
- */
199
- count() {
200
- const prefix = `${this.getLatticeType()}:`;
201
- let count = 0;
202
- for (const key of _BaseLatticeManager.registry.keys()) {
203
- if (key.startsWith(prefix)) {
204
- count++;
205
- }
206
- }
207
- return count;
208
- }
209
- /**
210
- * 获取当前类型的项目键名列表(向后兼容,包含所有租户)
211
- * 返回格式: {tenantId}:{key}
212
- */
213
- keys() {
214
- const prefix = `${this.getLatticeType()}:`;
215
- const prefixLength = prefix.length;
216
- const result = [];
217
- for (const key of _BaseLatticeManager.registry.keys()) {
218
- if (key.startsWith(prefix)) {
219
- result.push(key.substring(prefixLength));
220
- }
221
- }
222
- return result;
223
- }
224
- /**
225
- * 获取当前类型的项目键名列表(仅指定租户,不含租户前缀)
226
- * @param tenantId 租户ID
227
- */
228
- keysByTenant(tenantId) {
229
- const prefix = `${this.getLatticeType()}:${tenantId}:`;
230
- const prefixLength = prefix.length;
231
- const result = [];
232
- for (const key of _BaseLatticeManager.registry.keys()) {
233
- if (key.startsWith(prefix)) {
234
- result.push(key.substring(prefixLength));
235
- }
236
- }
237
- return result;
238
- }
239
- };
240
- // 全局统一的Lattice注册表
241
- _BaseLatticeManager.registry = /* @__PURE__ */ new Map();
242
- var BaseLatticeManager = _BaseLatticeManager;
1
+ import {
2
+ BaseLatticeManager,
3
+ MemoryLatticeManager,
4
+ MemoryType,
5
+ getCheckpointSaver,
6
+ registerCheckpointSaver
7
+ } from "./chunk-C5HUS7YV.mjs";
8
+ import {
9
+ buildInput,
10
+ buildStateAnnotation,
11
+ compileInternal,
12
+ compileWorkflow,
13
+ createAgentNode,
14
+ createMapNode,
15
+ createNodeHandler,
16
+ extractOutput,
17
+ invokeWithRetry,
18
+ parallelLimit,
19
+ parseYaml,
20
+ renderTemplate,
21
+ resolvePath,
22
+ toJsonSchema,
23
+ toSafeStateExpr,
24
+ validateDSL
25
+ } from "./chunk-SGRFQY3E.mjs";
243
26
 
244
27
  // src/model_lattice/ModelLattice.ts
245
28
  import { ChatDeepSeek } from "@langchain/deepseek";
@@ -364,9 +147,11 @@ var ModelLattice = class extends BaseChatModel {
364
147
  maxRetries: config.maxRetries || 2,
365
148
  apiKey: config.apiKey || process.env[config.apiKeyEnvName || "SILICONCLOUD_API_KEY"],
366
149
  configuration: {
367
- baseURL: "https://api.siliconflow.cn/v1"
150
+ baseURL: config.baseURL || "https://api.siliconflow.cn/v1"
368
151
  },
369
- streaming: config.streaming
152
+ streaming: config.streaming,
153
+ modelKwargs: config.modelKwargs,
154
+ ...config.extra || {}
370
155
  });
371
156
  } else if (config.provider === "volcengine") {
372
157
  return new ChatOpenAI({
@@ -648,11 +433,11 @@ var ToolLatticeManager = class _ToolLatticeManager extends BaseLatticeManager {
648
433
  * @param key Lattice键名
649
434
  * @param tool 已有的StructuredTool实例
650
435
  */
651
- registerExistingTool(key, tool51) {
436
+ registerExistingTool(key, tool52) {
652
437
  const config = {
653
- name: tool51.name,
654
- description: tool51.description,
655
- schema: tool51.schema,
438
+ name: tool52.name,
439
+ description: tool52.description,
440
+ schema: tool52.schema,
656
441
  // StructuredTool的schema已经是Zod兼容的
657
442
  needUserApprove: false
658
443
  // MCP工具默认不需要用户批准
@@ -660,7 +445,7 @@ var ToolLatticeManager = class _ToolLatticeManager extends BaseLatticeManager {
660
445
  const toolLattice = {
661
446
  key,
662
447
  config,
663
- client: tool51
448
+ client: tool52
664
449
  };
665
450
  this.register(key, toolLattice);
666
451
  }
@@ -686,7 +471,7 @@ var ToolLatticeManager = class _ToolLatticeManager extends BaseLatticeManager {
686
471
  };
687
472
  var toolLatticeManager = ToolLatticeManager.getInstance();
688
473
  var registerToolLattice = (key, config, executor) => toolLatticeManager.registerLattice(key, config, executor);
689
- var registerExistingTool = (key, tool51) => toolLatticeManager.registerExistingTool(key, tool51);
474
+ var registerExistingTool = (key, tool52) => toolLatticeManager.registerExistingTool(key, tool52);
690
475
  var getToolLattice = (key) => toolLatticeManager.getToolLattice(key);
691
476
  var getToolDefinition = (key) => toolLatticeManager.getToolDefinition(key);
692
477
  var getToolClient = (key) => toolLatticeManager.getToolClient(key);
@@ -953,6 +738,7 @@ var InMemoryAssistantStore = class {
953
738
  name: data.name,
954
739
  description: data.description,
955
740
  graphDefinition: data.graphDefinition,
741
+ ownerUserId: data.ownerUserId,
956
742
  createdAt: now,
957
743
  updatedAt: now
958
744
  };
@@ -999,6 +785,17 @@ var InMemoryAssistantStore = class {
999
785
  }
1000
786
  return tenantAssistants.has(id);
1001
787
  }
788
+ /**
789
+ * Get assistant by owner user ID
790
+ */
791
+ async getByOwner(tenantId, userId) {
792
+ const tenantAssistants = this.assistants.get(tenantId);
793
+ if (!tenantAssistants) return null;
794
+ for (const assistant of tenantAssistants.values()) {
795
+ if (assistant.ownerUserId === userId) return assistant;
796
+ }
797
+ return null;
798
+ }
1002
799
  /**
1003
800
  * Clear all assistants for a tenant (useful for testing)
1004
801
  */
@@ -2231,7 +2028,7 @@ var InMemoryThreadMessageQueueStore = class {
2231
2028
  return this.messages.get(threadId);
2232
2029
  }
2233
2030
  async addMessage(params) {
2234
- const { threadId, tenantId, assistantId, content, type = "human", priority = 0, command, custom_run_config, id } = params;
2031
+ const { threadId, tenantId, assistantId, workspaceId, projectId, content, type = "human", priority = 0, command, custom_run_config, id } = params;
2235
2032
  const threadMessages = this.getMessagesForThread(threadId);
2236
2033
  const message = {
2237
2034
  id: id || this.generateId(),
@@ -2242,6 +2039,8 @@ var InMemoryThreadMessageQueueStore = class {
2242
2039
  status: "pending",
2243
2040
  tenantId,
2244
2041
  assistantId,
2042
+ workspaceId,
2043
+ projectId,
2245
2044
  priority,
2246
2045
  command,
2247
2046
  custom_run_config
@@ -2250,7 +2049,7 @@ var InMemoryThreadMessageQueueStore = class {
2250
2049
  return message;
2251
2050
  }
2252
2051
  async addMessageAtHead(params) {
2253
- const { threadId, tenantId, assistantId, content, type = "system", id, command, custom_run_config } = params;
2052
+ const { threadId, tenantId, assistantId, workspaceId, projectId, content, type = "system", id, command, custom_run_config } = params;
2254
2053
  const threadMessages = this.getMessagesForThread(threadId);
2255
2054
  let resolvedTenantId = tenantId || "default";
2256
2055
  let resolvedAssistantId = assistantId || "";
@@ -2268,6 +2067,8 @@ var InMemoryThreadMessageQueueStore = class {
2268
2067
  status: "pending",
2269
2068
  tenantId: resolvedTenantId,
2270
2069
  assistantId: resolvedAssistantId,
2070
+ workspaceId,
2071
+ projectId,
2271
2072
  priority: 100,
2272
2073
  // High priority for head messages (STEER/Command)
2273
2074
  command,
@@ -2299,7 +2100,9 @@ var InMemoryThreadMessageQueueStore = class {
2299
2100
  result.push({
2300
2101
  tenantId: firstMessage.tenantId || "default",
2301
2102
  assistantId: firstMessage.assistantId || "",
2302
- threadId
2103
+ threadId,
2104
+ workspaceId: firstMessage.workspaceId || void 0,
2105
+ projectId: firstMessage.projectId || void 0
2303
2106
  });
2304
2107
  }
2305
2108
  }
@@ -2422,6 +2225,7 @@ var InMemoryWorkflowTrackingStore = class {
2422
2225
  tenantId: request.tenantId,
2423
2226
  stepType: request.stepType,
2424
2227
  stepName: request.stepName,
2228
+ threadId: request.threadId,
2425
2229
  edgeFrom: request.edgeFrom,
2426
2230
  edgeTo: request.edgeTo,
2427
2231
  edgePurpose: request.edgePurpose,
@@ -2436,6 +2240,19 @@ var InMemoryWorkflowTrackingStore = class {
2436
2240
  this.steps.set(request.runId, runSteps);
2437
2241
  return step;
2438
2242
  }
2243
+ async upsertRunStep(request) {
2244
+ const runSteps = this.steps.get(request.runId) || [];
2245
+ const existing = runSteps.find(
2246
+ (s) => s.stepType === request.stepType && s.stepName === request.stepName
2247
+ );
2248
+ if (existing) {
2249
+ if (!existing.threadId && request.threadId) {
2250
+ existing.threadId = request.threadId;
2251
+ }
2252
+ return existing;
2253
+ }
2254
+ return this.createRunStep(request);
2255
+ }
2439
2256
  async updateRunStep(runId, stepId, updates) {
2440
2257
  const runSteps = this.steps.get(runId);
2441
2258
  if (!runSteps) return null;
@@ -2492,6 +2309,11 @@ var InMemoryChannelInstallationStore = class {
2492
2309
  (inst) => inst.tenantId === tenantId && (!channel || inst.channel === channel)
2493
2310
  );
2494
2311
  }
2312
+ async getAllInstallations(channel) {
2313
+ return Array.from(this.installations.values()).filter(
2314
+ (inst) => !channel || inst.channel === channel
2315
+ );
2316
+ }
2495
2317
  /**
2496
2318
  * Creates a new channel installation for a tenant.
2497
2319
  *
@@ -2768,6 +2590,107 @@ var InMemoryA2AApiKeyStore = class {
2768
2590
  }
2769
2591
  };
2770
2592
 
2593
+ // src/store_lattice/InMemoryTaskStore.ts
2594
+ import { v4 as uuidv4 } from "uuid";
2595
+ var InMemoryTaskStore = class {
2596
+ constructor() {
2597
+ this.tasks = /* @__PURE__ */ new Map();
2598
+ }
2599
+ /**
2600
+ * Create a new task
2601
+ */
2602
+ async create(params) {
2603
+ if (!this.tasks.has(params.tenantId)) {
2604
+ this.tasks.set(params.tenantId, /* @__PURE__ */ new Map());
2605
+ }
2606
+ const now = /* @__PURE__ */ new Date();
2607
+ const task = {
2608
+ id: uuidv4(),
2609
+ tenantId: params.tenantId,
2610
+ ownerType: params.ownerType,
2611
+ ownerId: params.ownerId,
2612
+ title: params.title,
2613
+ description: params.description,
2614
+ status: params.status || "pending",
2615
+ priority: params.priority || "medium",
2616
+ dueDate: params.dueDate,
2617
+ metadata: params.metadata,
2618
+ parentId: params.parentId,
2619
+ sourceId: params.sourceId,
2620
+ context: params.context,
2621
+ createdAt: now,
2622
+ updatedAt: now
2623
+ };
2624
+ this.tasks.get(params.tenantId).set(task.id, task);
2625
+ return task;
2626
+ }
2627
+ /**
2628
+ * Get task by ID
2629
+ */
2630
+ async getById(tenantId, id) {
2631
+ const tenantTasks = this.tasks.get(tenantId);
2632
+ if (!tenantTasks) return null;
2633
+ return tenantTasks.get(id) || null;
2634
+ }
2635
+ /**
2636
+ * List tasks matching filter criteria
2637
+ */
2638
+ async list(filter2) {
2639
+ const tenantTasks = this.tasks.get(filter2.tenantId);
2640
+ if (!tenantTasks) return [];
2641
+ let results = Array.from(tenantTasks.values());
2642
+ if (filter2.ownerType) results = results.filter((t) => t.ownerType === filter2.ownerType);
2643
+ if (filter2.ownerId) results = results.filter((t) => t.ownerId === filter2.ownerId);
2644
+ if (filter2.status) results = results.filter((t) => t.status === filter2.status);
2645
+ if (filter2.priority) results = results.filter((t) => t.priority === filter2.priority);
2646
+ if (filter2.parentId) results = results.filter((t) => t.parentId === filter2.parentId);
2647
+ if (filter2.sourceId) results = results.filter((t) => t.sourceId === filter2.sourceId);
2648
+ if (filter2.metadata) {
2649
+ for (const [key, value] of Object.entries(filter2.metadata)) {
2650
+ results = results.filter((t) => t.metadata?.[key] === value);
2651
+ }
2652
+ }
2653
+ results.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
2654
+ const offset = filter2.offset || 0;
2655
+ const limit = filter2.limit || 100;
2656
+ return results.slice(offset, offset + limit);
2657
+ }
2658
+ /**
2659
+ * Update an existing task
2660
+ */
2661
+ async update(tenantId, id, updates) {
2662
+ const tenantTasks = this.tasks.get(tenantId);
2663
+ if (!tenantTasks) return null;
2664
+ const existing = tenantTasks.get(id);
2665
+ if (!existing) return null;
2666
+ const updated = {
2667
+ ...existing,
2668
+ ...updates,
2669
+ updatedAt: /* @__PURE__ */ new Date()
2670
+ };
2671
+ tenantTasks.set(id, updated);
2672
+ return updated;
2673
+ }
2674
+ /**
2675
+ * Delete a task by ID
2676
+ */
2677
+ async delete(tenantId, id) {
2678
+ const tenantTasks = this.tasks.get(tenantId);
2679
+ if (!tenantTasks) return false;
2680
+ return tenantTasks.delete(id);
2681
+ }
2682
+ /**
2683
+ * Clear all tasks for a tenant (useful for testing)
2684
+ */
2685
+ clear(tenantId) {
2686
+ if (tenantId) {
2687
+ this.tasks.delete(tenantId);
2688
+ } else {
2689
+ this.tasks.clear();
2690
+ }
2691
+ }
2692
+ };
2693
+
2771
2694
  // src/store_lattice/StoreLatticeManager.ts
2772
2695
  var StoreLatticeManager = class _StoreLatticeManager extends BaseLatticeManager {
2773
2696
  /**
@@ -2948,6 +2871,12 @@ storeLatticeManager.registerLattice(
2948
2871
  "a2aApiKey",
2949
2872
  defaultA2AApiKeyStore
2950
2873
  );
2874
+ var defaultTaskStore = new InMemoryTaskStore();
2875
+ storeLatticeManager.registerLattice(
2876
+ "default",
2877
+ "task",
2878
+ defaultTaskStore
2879
+ );
2951
2880
 
2952
2881
  // src/tool_lattice/manage_binding/index.ts
2953
2882
  function getInstallationStore() {
@@ -2959,7 +2888,7 @@ var manageBindingSchema = z3.object({
2959
2888
  channelInstallationId: z3.string().optional().describe("Channel installation ID (auto-detected if omitted and only one exists for this channel)"),
2960
2889
  senderId: z3.string().optional().describe("Sender identifier (email address, Lark openId, Slack userId)"),
2961
2890
  agentId: z3.string().optional().describe("Target agent ID to route messages to"),
2962
- threadMode: z3.enum(["fixed", "per_conversation"]).optional().default("per_conversation").describe("Thread mode: per_conversation (recommended) or fixed"),
2891
+ threadMode: z3.enum(["fixed", "per_conversation"]).optional().default("per_conversation").describe("Thread mode (ignored when channel adapter has its own thread strategy, e.g. Lark)"),
2963
2892
  senderDisplayName: z3.string().optional().describe("Human-readable name for the sender")
2964
2893
  });
2965
2894
  registerToolLattice(
@@ -2968,9 +2897,13 @@ registerToolLattice(
2968
2897
  name: "manage_binding",
2969
2898
  description: `Manage sender-to-agent bindings for external channels (email, Lark, Slack).
2970
2899
 
2900
+ Bindings are OPTIONAL \u2014 if no binding exists for a sender, messages route to the installation's fallbackAgentId. Only create a binding when a specific sender needs a different agent.
2901
+
2902
+ Thread isolation is handled automatically by the channel adapter (e.g. Lark isolates by sender+date). threadMode is only used when the channel adapter does not have its own strategy.
2903
+
2971
2904
  - list_installations: List available channel installations. Filter by channel type (optional). Use this first to discover available channelInstallationIds.
2972
- - create: Bind a sender to an agent. Required: channel, senderId, agentId. Optional: threadMode (default: per_conversation). channelInstallationId is optional \u2014 auto-detected if only one installation exists for this channel.
2973
- - update: Update an existing binding. Required: channel, senderId. Optional: agentId, threadMode (default: per_conversation), senderDisplayName.
2905
+ - create: Bind a sender to an agent. Required: channel, senderId, agentId. Optional: threadMode. channelInstallationId auto-detected if only one exists.
2906
+ - update: Update an existing binding. Required: channel, senderId. Optional: agentId, threadMode, senderDisplayName.
2974
2907
  - delete: Remove a binding. Required: channel, senderId.
2975
2908
  - list: List all bindings. Optional: channel, agentId, channelInstallationId.
2976
2909
 
@@ -2978,7 +2911,7 @@ A sender can only be bound to ONE agent per channel+installation combination.`,
2978
2911
  schema: manageBindingSchema
2979
2912
  },
2980
2913
  async (input, config) => {
2981
- const registry2 = getBindingRegistry();
2914
+ const registry3 = getBindingRegistry();
2982
2915
  const runConfig = config?.configurable?.runConfig || {};
2983
2916
  const tenantId = runConfig.tenantId || "default";
2984
2917
  switch (input.action) {
@@ -3001,7 +2934,7 @@ A sender can only be bound to ONE agent per channel+installation combination.`,
3001
2934
  error: `No channelInstallationId provided and unable to auto-detect. Use action=list_installations to find available installations for channel "${input.channel}".`
3002
2935
  });
3003
2936
  }
3004
- const binding = await registry2.create({
2937
+ const binding = await registry3.create({
3005
2938
  channel: input.channel,
3006
2939
  channelInstallationId: installId,
3007
2940
  tenantId,
@@ -3023,7 +2956,7 @@ A sender can only be bound to ONE agent per channel+installation combination.`,
3023
2956
  error: `No channelInstallationId provided and unable to auto-detect. Use action=list_installations first.`
3024
2957
  });
3025
2958
  }
3026
- const existing = await registry2.resolve({
2959
+ const existing = await registry3.resolve({
3027
2960
  channel: input.channel,
3028
2961
  senderId: input.senderId,
3029
2962
  channelInstallationId: installId,
@@ -3032,7 +2965,7 @@ A sender can only be bound to ONE agent per channel+installation combination.`,
3032
2965
  if (!existing) {
3033
2966
  return JSON.stringify({ success: false, error: "Binding not found" });
3034
2967
  }
3035
- const updated = await registry2.update(existing.id, {
2968
+ const updated = await registry3.update(existing.id, {
3036
2969
  agentId: input.agentId,
3037
2970
  threadMode: input.threadMode,
3038
2971
  senderDisplayName: input.senderDisplayName
@@ -3050,7 +2983,7 @@ A sender can only be bound to ONE agent per channel+installation combination.`,
3050
2983
  error: `No channelInstallationId provided and unable to auto-detect.`
3051
2984
  });
3052
2985
  }
3053
- const existing = await registry2.resolve({
2986
+ const existing = await registry3.resolve({
3054
2987
  channel: input.channel,
3055
2988
  senderId: input.senderId,
3056
2989
  channelInstallationId: installId,
@@ -3059,11 +2992,11 @@ A sender can only be bound to ONE agent per channel+installation combination.`,
3059
2992
  if (!existing) {
3060
2993
  return JSON.stringify({ success: false, error: "Binding not found" });
3061
2994
  }
3062
- await registry2.delete(existing.id);
2995
+ await registry3.delete(existing.id);
3063
2996
  return JSON.stringify({ success: true, message: "Binding deleted" });
3064
2997
  }
3065
2998
  case "list": {
3066
- const bindings = await registry2.list({
2999
+ const bindings = await registry3.list({
3067
3000
  channel: input.channel,
3068
3001
  agentId: input.agentId,
3069
3002
  tenantId,
@@ -7049,86 +6982,6 @@ import {
7049
6982
  getSubAgentsFromConfig
7050
6983
  } from "@axiom-lattice/protocols";
7051
6984
 
7052
- // src/memory_lattice/DefaultMemorySaver.ts
7053
- import { MemorySaver } from "@langchain/langgraph";
7054
-
7055
- // src/memory_lattice/MemoryLatticeManager.ts
7056
- import { MemoryType } from "@axiom-lattice/protocols";
7057
- var _MemoryLatticeManager = class _MemoryLatticeManager extends BaseLatticeManager {
7058
- /**
7059
- * 私有构造函数,防止外部直接实例化
7060
- */
7061
- constructor() {
7062
- super();
7063
- }
7064
- /**
7065
- * 获取单例实例
7066
- */
7067
- static getInstance() {
7068
- if (!_MemoryLatticeManager.instance) {
7069
- _MemoryLatticeManager.instance = new _MemoryLatticeManager();
7070
- }
7071
- return _MemoryLatticeManager.instance;
7072
- }
7073
- /**
7074
- * 获取Lattice类型
7075
- */
7076
- getLatticeType() {
7077
- return "memory";
7078
- }
7079
- /**
7080
- * 注册检查点保存器
7081
- * @param key 保存器键名
7082
- * @param saver 检查点保存器实例
7083
- */
7084
- registerCheckpointSaver(key, saver) {
7085
- if (_MemoryLatticeManager.checkpointSavers.has(key)) {
7086
- console.warn(`\u68C0\u67E5\u70B9\u4FDD\u5B58\u5668 "${key}" \u5DF2\u7ECF\u5B58\u5728\uFF0C\u5C06\u4F1A\u8986\u76D6\u65E7\u7684\u68C0\u67E5\u70B9\u4FDD\u5B58\u5668`);
7087
- }
7088
- _MemoryLatticeManager.checkpointSavers.set(key, saver);
7089
- }
7090
- /**
7091
- * 获取检查点保存器
7092
- * @param key 保存器键名
7093
- */
7094
- getCheckpointSaver(key) {
7095
- const saver = _MemoryLatticeManager.checkpointSavers.get(key);
7096
- if (!saver) {
7097
- throw new Error(`\u68C0\u67E5\u70B9\u4FDD\u5B58\u5668 "${key}" \u4E0D\u5B58\u5728`);
7098
- }
7099
- return saver;
7100
- }
7101
- /**
7102
- * 获取所有已注册的检查点保存器键名
7103
- */
7104
- getCheckpointSaverKeys() {
7105
- return Array.from(_MemoryLatticeManager.checkpointSavers.keys());
7106
- }
7107
- /**
7108
- * 检查检查点保存器是否存在
7109
- * @param key 保存器键名
7110
- */
7111
- hasCheckpointSaver(key) {
7112
- return _MemoryLatticeManager.checkpointSavers.has(key);
7113
- }
7114
- /**
7115
- * 移除检查点保存器
7116
- * @param key 保存器键名
7117
- */
7118
- removeCheckpointSaver(key) {
7119
- return _MemoryLatticeManager.checkpointSavers.delete(key);
7120
- }
7121
- };
7122
- // 检查点保存器注册表
7123
- _MemoryLatticeManager.checkpointSavers = /* @__PURE__ */ new Map();
7124
- var MemoryLatticeManager = _MemoryLatticeManager;
7125
- var getCheckpointSaver = (key) => MemoryLatticeManager.getInstance().getCheckpointSaver(key);
7126
- var registerCheckpointSaver = (key, saver) => MemoryLatticeManager.getInstance().registerCheckpointSaver(key, saver);
7127
-
7128
- // src/memory_lattice/DefaultMemorySaver.ts
7129
- var memory = new MemorySaver();
7130
- registerCheckpointSaver("default", memory);
7131
-
7132
6985
  // src/agent_lattice/builders/state.ts
7133
6986
  import "@langchain/langgraph/zod";
7134
6987
  import { MessagesZodState } from "@langchain/langgraph";
@@ -7606,25 +7459,253 @@ metadata:
7606
7459
  **You** (test): "Here are 3 test cases \u2014 'summarize this sales CSV', 'filter rows where region is West', 'show monthly revenue trends'. Let me run these and we'll review."
7607
7460
 
7608
7461
  Then iterate based on what the user says.
7609
- `
7610
- };
7611
- function getBuiltInSkillMeta(name) {
7612
- const content = BUILTIN_SKILLS[name];
7613
- if (!content) return null;
7614
- try {
7615
- const { meta } = parseSkillFrontmatter(content);
7616
- return meta;
7617
- } catch {
7618
- return null;
7619
- }
7620
- }
7621
- function getBuiltInSkillContent(name) {
7622
- return BUILTIN_SKILLS[name];
7623
- }
7624
- function getAllBuiltInSkillMetas() {
7625
- return Object.keys(BUILTIN_SKILLS).map((name) => getBuiltInSkillMeta(name)).filter((meta) => meta !== null);
7626
- }
7627
- function getBuiltInSkillNames() {
7462
+ `,
7463
+ "create-workflow": `---
7464
+ name: create-workflow
7465
+ description: Design and build multi-step AI workflows using the YAML linear DSL. Use whenever users want to orchestrate agents in a pipeline with routing, parallelism, human-in-the-loop, or batch processing.
7466
+ license: MIT
7467
+ metadata:
7468
+ category: meta
7469
+ version: "5.0"
7470
+ ---
7471
+
7472
+ # YAML Workflow Designer
7473
+
7474
+ Use the linear YAML DSL \u2014 steps execute top-to-bottom. Use \`parallel:\` for concurrency. No dependency graph thinking required.
7475
+
7476
+ ## Core Model: Linear + Parallel
7477
+
7478
+ - **Linear** \u2014 steps execute in written order. No \`needs\`, no dependency declarations.
7479
+ - **parallel** \u2014 a block where all children run concurrently. Block completes when all children finish.
7480
+ - **if** \u2014 JS expression. Step runs only when truthy. Omit to always run.
7481
+ - **prompt** \u2014 agent instruction with **{{label}}** refs. **{{input}}** is the user message.
7482
+ - **output** \u2014 shorthand schema using **{ field: type }** notation.
7483
+ - **ask** \u2014 boolean. Injects user clarification middleware for human interaction.
7484
+
7485
+ ## When to Use parallel vs map
7486
+
7487
+ This is the most important design decision. **They are fundamentally different:**
7488
+
7489
+ | | parallel | map |
7490
+ |---|---|---|
7491
+ | **Concern** | **Business parallelism** \u2014 reduce business processing time | **Data parallelism** \u2014 handle data volume |
7492
+ | **Tasks** | Each child does a **different** task | All items do the **same** task |
7493
+ | **Count** | Few (2-5), each hand-written | Dynamic, driven by source data |
7494
+ | **Input** | Independent prompts per child | Single \`each.prompt\` template, \`{{item}}\` for current element |
7495
+ | **if** | Per-child conditional | Whole block conditional |
7496
+ | **Example** | Legal review + Market analysis in parallel | Audit each line item in an invoice |
7497
+
7498
+ **Rule of thumb:** If you're writing the same prompt twice, you probably want \`map\`. If each branch has a unique purpose, use \`parallel\`.
7499
+
7500
+ ## Step Format
7501
+
7502
+ ### Agent Step
7503
+
7504
+ \`\`\`yaml
7505
+ - label:
7506
+ prompt: instruction with {{refs}}
7507
+ if: "expression"
7508
+ output: { field: type }
7509
+ ask: true
7510
+ \`\`\`
7511
+
7512
+ ### Parallel Block
7513
+
7514
+ \`\`\`yaml
7515
+ - parallel:
7516
+ - child1:
7517
+ prompt: ...
7518
+ if: "expression"
7519
+ - child2:
7520
+ prompt: ...
7521
+ \`\`\`
7522
+
7523
+ Parallel children are agent steps only. No nested parallel or map inside parallel.
7524
+
7525
+ ### Map Step
7526
+
7527
+ \`\`\`yaml
7528
+ - label:
7529
+ map:
7530
+ source: "extract.items"
7531
+ if: "extract.items.length > 0"
7532
+ each:
7533
+ prompt: Process {{item}}
7534
+ output: { result: string }
7535
+ batch: 50
7536
+ concurrency: 5
7537
+ \`\`\`
7538
+
7539
+ ## Schema Shorthand
7540
+
7541
+ Write **{ field: type }** instead of JSON Schema:
7542
+
7543
+ | Shorthand | Meaning |
7544
+ |-----------|---------|
7545
+ | **field: string** | string property |
7546
+ | **field: number** | number property |
7547
+ | **field: boolean** | boolean property |
7548
+ | **field: string[]** | array of strings |
7549
+ | **field: number[]** | array of numbers |
7550
+ | **field: [{ a: string, b: number }]** | array of objects |
7551
+ | **field: { sub: string }** | nested object |
7552
+
7553
+ Use **block style** (each field on its own line). Flow style \`{ field: "type" }\` with quoted values also works.
7554
+
7555
+ ## Template Syntax
7556
+
7557
+ | Syntax | Resolves to |
7558
+ |--------|------------|
7559
+ | \`{{input}}\` | Initial user message |
7560
+ | \`{{label}}\` | Full output of step |
7561
+ | \`{{label.field}}\` | Nested field access |
7562
+ | \`{{item}}\` | Current element in map iteration |
7563
+
7564
+ ## Design Patterns
7565
+
7566
+ ### Linear Pipeline
7567
+
7568
+ \`\`\`yaml
7569
+ steps:
7570
+ - extract:
7571
+ prompt: Extract data from {{input}}
7572
+ - transform:
7573
+ prompt: Transform {{extract}}
7574
+ - final:
7575
+ prompt: Combine raw {{extract}} with transformed {{transform}}
7576
+ \`\`\`
7577
+
7578
+ ### Classify -> Route via Parallel + if
7579
+
7580
+ \`\`\`yaml
7581
+ steps:
7582
+ - classify:
7583
+ prompt: Classify intent from {{input}}
7584
+ output:
7585
+ intent: string
7586
+ urgency: number
7587
+ - parallel:
7588
+ - billing:
7589
+ if: "classify.intent == 'billing'"
7590
+ prompt: Handle billing: {{input}}
7591
+ ask: true
7592
+ - technical:
7593
+ if: "classify.intent == 'technical'"
7594
+ prompt: Handle technical: {{input}}
7595
+ - escalate:
7596
+ if: "classify.urgency >= 8"
7597
+ prompt: Urgent handling
7598
+ ask: true
7599
+ \`\`\`
7600
+
7601
+ ### Parallel Processing
7602
+
7603
+ \`\`\`yaml
7604
+ steps:
7605
+ - gather:
7606
+ prompt: Gather data from {{input}}
7607
+ - parallel:
7608
+ - legal:
7609
+ prompt: Legal analysis of {{gather}}
7610
+ output:
7611
+ risk: string
7612
+ compliant: boolean
7613
+ - market:
7614
+ prompt: Market analysis of {{gather}}
7615
+ output:
7616
+ opportunity: string
7617
+ score: number
7618
+ - report:
7619
+ prompt: |
7620
+ Synthesize findings:
7621
+ Legal: {{legal}}
7622
+ Market: {{market}}
7623
+ \`\`\`
7624
+
7625
+ ### Approval Flow with Human
7626
+
7627
+ \`\`\`yaml
7628
+ steps:
7629
+ - draft:
7630
+ prompt: Draft response to {{input}}
7631
+ - review:
7632
+ prompt: Present {{draft}} to user for approval
7633
+ output:
7634
+ approved: boolean
7635
+ comments: string
7636
+ ask: true
7637
+ - publish:
7638
+ if: "review.approved"
7639
+ prompt: Publish {{draft}}
7640
+ - revise:
7641
+ if: "!review.approved"
7642
+ prompt: Revise based on {{review.comments}}
7643
+ \`\`\`
7644
+
7645
+ ### Map (Iteration)
7646
+
7647
+ \`\`\`yaml
7648
+ steps:
7649
+ - extract:
7650
+ prompt: Extract items from {{input}}
7651
+ output:
7652
+ items:
7653
+ - name: string
7654
+ - map_items:
7655
+ map:
7656
+ source: "extract.items"
7657
+ each:
7658
+ prompt: Audit {{item.name}}
7659
+ output:
7660
+ result: string
7661
+ - summary:
7662
+ prompt: Summarize findings: {{map_items}}
7663
+ \`\`\`
7664
+
7665
+ ## Keep Business Logic in Agents
7666
+
7667
+ The DSL is for orchestration (what runs when). Business logic (validation, branching, error handling, user interaction) belongs inside agent prompts, not as workflow if conditions. An agent can validate, branch, and ask questions \u2014 all in one step.
7668
+
7669
+ **Rule:** if you have more if conditions than workflow phases, move logic into richer agent prompts.
7670
+
7671
+ ## What You NEVER Write
7672
+
7673
+ - **needs** \u2014 not supported. Steps execute linearly. Use parallel for concurrency.
7674
+ - **edges** \u2014 auto-generated from step order and parallel structure
7675
+ - **nested parallel** \u2014 parallel children are flat agent steps only
7676
+ - **map inside parallel** \u2014 map is a top-level step only
7677
+ - **json schema** \u2014 use **{ field: type }** block style
7678
+ - do not use {{}} markers in if expressions
7679
+ - **workflow-level business logic** \u2014 decisions belong inside agent prompts
7680
+
7681
+ ## Checklist
7682
+
7683
+ - Every step has a unique label
7684
+ - Steps execute top-to-bottom \u2014 no dependency thinking needed
7685
+ - \`{{label}}\` can reference ANY upstream step output
7686
+ - if uses plain JS, no {{}}
7687
+ - Schema uses block style shorthand
7688
+ - parallel children are flat agent steps
7689
+ - Business logic stays inside agent prompts
7690
+ - ask: true for human interaction`
7691
+ };
7692
+ function getBuiltInSkillMeta(name) {
7693
+ const content = BUILTIN_SKILLS[name];
7694
+ if (!content) return null;
7695
+ try {
7696
+ const { meta } = parseSkillFrontmatter(content);
7697
+ return meta;
7698
+ } catch {
7699
+ return null;
7700
+ }
7701
+ }
7702
+ function getBuiltInSkillContent(name) {
7703
+ return BUILTIN_SKILLS[name];
7704
+ }
7705
+ function getAllBuiltInSkillMetas() {
7706
+ return Object.keys(BUILTIN_SKILLS).map((name) => getBuiltInSkillMeta(name)).filter((meta) => meta !== null);
7707
+ }
7708
+ function getBuiltInSkillNames() {
7628
7709
  return Object.keys(BUILTIN_SKILLS);
7629
7710
  }
7630
7711
  function isBuiltInSkill(name) {
@@ -10517,7 +10598,7 @@ ${currentSystemPrompt}` : dateContext;
10517
10598
  // src/deep_agent_new/middleware/scheduler.ts
10518
10599
  import { tool as tool45, createMiddleware as createMiddleware13 } from "langchain";
10519
10600
  import { z as z48 } from "zod";
10520
- import { v4 as uuidv4 } from "uuid";
10601
+ import { v4 as uuidv42 } from "uuid";
10521
10602
  import { ScheduledTaskStatus as ScheduledTaskStatus3, ScheduleExecutionType as ScheduleExecutionType3 } from "@axiom-lattice/protocols";
10522
10603
 
10523
10604
  // src/schedule_lattice/ScheduleLatticeManager.ts
@@ -12162,7 +12243,6 @@ var Agent = class {
12162
12243
  const runnable_agent = await getAgentClientAsync(this.tenant_id, this.assistant_id);
12163
12244
  const agentLattice = agentLatticeManager.getAgentLatticeWithTenant(this.tenant_id, this.assistant_id);
12164
12245
  const { messages, ...rest } = input;
12165
- const lifecycleManager = this;
12166
12246
  const runConfig = {
12167
12247
  thread_id: this.thread_id,
12168
12248
  "x-tenant-id": this.tenant_id,
@@ -12214,43 +12294,13 @@ var Agent = class {
12214
12294
  }
12215
12295
  );
12216
12296
  try {
12217
- for await (const chunk of agentStream) {
12218
- if (signal?.aborted) {
12219
- await lifecycleManager.chunkBuffer.abortThread(lifecycleManager.thread_id);
12220
- throw new Error("Agent execution was aborted");
12221
- }
12222
- let data;
12223
- let chunkContent = "";
12224
- if (chunk[0] === "updates") {
12225
- const update = chunk[1];
12226
- const values = Object.values(update);
12227
- const messages2 = values[0]?.messages;
12228
- if (messages2?.[0]?.tool_call_id) {
12229
- data = messages2[0].toDict();
12230
- }
12231
- } else if (chunk[0] === "messages") {
12232
- const messages2 = chunk[1];
12233
- data = messages2?.[0]?.toDict();
12234
- }
12235
- if (chunk?.[1]?.__interrupt__) {
12236
- const interruptData = chunk?.[1]?.__interrupt__[0];
12237
- data = {
12238
- type: "interrupt",
12239
- id: interruptData.id,
12240
- data: { content: interruptData.value }
12241
- };
12242
- }
12243
- if (data) {
12244
- lifecycleManager.addChunk(data);
12245
- }
12246
- }
12297
+ await this.consumeAgentStream(agentStream, signal);
12247
12298
  } catch (error) {
12248
12299
  console.error("Stream error:", error);
12249
- await lifecycleManager.chunkBuffer.abortThread(lifecycleManager.thread_id);
12250
12300
  throw error;
12251
12301
  }
12252
12302
  } catch (error) {
12253
- await this.chunkBuffer.abortThread(lifecycleManager.thread_id);
12303
+ await this.chunkBuffer.abortThread(this.thread_id);
12254
12304
  throw error;
12255
12305
  }
12256
12306
  };
@@ -12531,8 +12581,8 @@ var Agent = class {
12531
12581
  this.assistant_id = assistant_id;
12532
12582
  this.thread_id = thread_id;
12533
12583
  this.tenant_id = tenant_id;
12534
- this.workspace_id = workspace_id;
12535
- this.project_id = project_id;
12584
+ this.workspace_id = workspace_id || "default";
12585
+ this.project_id = project_id || "default";
12536
12586
  this.custom_run_config = custom_run_config;
12537
12587
  }
12538
12588
  getHumanPendingContent(message) {
@@ -12626,10 +12676,132 @@ var Agent = class {
12626
12676
  const inputMessage = { ...queueMessage, input };
12627
12677
  return this.agentExecutor(inputMessage, signal);
12628
12678
  }
12679
+ /**
12680
+ * Like {@link invoke} but returns the full LangGraph state (all annotations)
12681
+ * instead of only messages. Messages are serialized to dicts; other state
12682
+ * fields are returned as-is.
12683
+ *
12684
+ * @remarks
12685
+ * Only call this when you need the full state. Existing callers (gateway,
12686
+ * workflows) should keep using {@link invoke} which returns only messages
12687
+ * to avoid exposing internal annotation data.
12688
+ */
12689
+ async invokeWithState(queueMessage, signal) {
12690
+ const messageId = v4();
12691
+ const input = {
12692
+ ...queueMessage.input,
12693
+ messages: [new HumanMessage({ id: messageId, content: queueMessage.input.message })]
12694
+ };
12695
+ const inputMessage = { ...queueMessage, input };
12696
+ const { runnable_agent, runConfig } = await this.getLatticeClientAndRuntimeConfig(inputMessage.custom_run_config);
12697
+ const { messages, ...rest } = inputMessage.input;
12698
+ if (signal?.aborted) {
12699
+ throw new Error("Agent execution was aborted");
12700
+ }
12701
+ let result;
12702
+ result = await runnable_agent.invoke(
12703
+ inputMessage.command ? new Command2(inputMessage.command) : { ...rest, messages, "x-tenant-id": this.tenant_id },
12704
+ {
12705
+ context: { runConfig },
12706
+ configurable: {
12707
+ run_id: v4(),
12708
+ ...runConfig,
12709
+ runConfig
12710
+ },
12711
+ recursionLimit: 200,
12712
+ signal
12713
+ }
12714
+ );
12715
+ if (signal?.aborted) {
12716
+ throw new Error("Agent execution was aborted");
12717
+ }
12718
+ const { messages: _rawMessages, ...restState } = result;
12719
+ const serializedMessages = result.messages.map((message) => {
12720
+ const { type, data } = message.toDict();
12721
+ return { ...data, role: type };
12722
+ });
12723
+ return { messages: serializedMessages, ...restState };
12724
+ }
12629
12725
  async getPendingMessages() {
12630
12726
  const store = this.getQueueStore();
12631
12727
  return await store.getPendingMessages(this.thread_id);
12632
12728
  }
12729
+ async consumeAgentStream(agentStream, signal) {
12730
+ for await (const chunk of agentStream) {
12731
+ if (signal?.aborted) {
12732
+ await this.chunkBuffer.abortThread(this.thread_id);
12733
+ throw new Error("Agent execution was aborted");
12734
+ }
12735
+ let data;
12736
+ if (chunk[0] === "updates") {
12737
+ const update = chunk[1];
12738
+ const values = Object.values(update);
12739
+ const messages = values[0]?.messages;
12740
+ if (messages?.[0]?.tool_call_id) {
12741
+ data = messages[0].toDict();
12742
+ }
12743
+ } else if (chunk[0] === "messages") {
12744
+ const messages = chunk[1];
12745
+ data = messages?.[0]?.toDict();
12746
+ }
12747
+ if (chunk?.[1]?.__interrupt__) {
12748
+ const interruptData = chunk?.[1]?.__interrupt__[0];
12749
+ data = {
12750
+ type: "interrupt",
12751
+ id: interruptData.id,
12752
+ data: { content: interruptData.value }
12753
+ };
12754
+ }
12755
+ if (data) {
12756
+ this.addChunk(data);
12757
+ }
12758
+ }
12759
+ }
12760
+ /**
12761
+ * Resume LangGraph execution from the last checkpoint.
12762
+ *
12763
+ * Streams with `null` input — this tells LangGraph to continue from
12764
+ * wherever it left off using the checkpointed state for this thread.
12765
+ * All output chunks are buffered via {@link addChunk}.
12766
+ */
12767
+ async resumeGraphFromCheckpoint(signal) {
12768
+ const runnable_agent = await getAgentClientAsync(this.tenant_id, this.assistant_id);
12769
+ const agentLattice = agentLatticeManager.getAgentLatticeWithTenant(this.tenant_id, this.assistant_id);
12770
+ if (!runnable_agent) {
12771
+ throw new Error(`Agent ${this.assistant_id} not found`);
12772
+ }
12773
+ const runConfig = {
12774
+ thread_id: this.thread_id,
12775
+ "x-tenant-id": this.tenant_id,
12776
+ "x-workspace-id": this.workspace_id,
12777
+ "x-project-id": this.project_id,
12778
+ "x-thread-id": this.thread_id,
12779
+ "x-assistant-id": this.assistant_id,
12780
+ ...agentLattice?.config?.runConfig || {},
12781
+ tenantId: this.tenant_id,
12782
+ workspaceId: this.workspace_id,
12783
+ projectId: this.project_id,
12784
+ ...this.custom_run_config || {},
12785
+ assistant_id: this.assistant_id
12786
+ };
12787
+ const agentStream = await runnable_agent.stream(
12788
+ null,
12789
+ {
12790
+ context: {
12791
+ runConfig
12792
+ },
12793
+ configurable: {
12794
+ ...runConfig,
12795
+ runConfig
12796
+ },
12797
+ streamMode: ["updates", "messages"],
12798
+ subgraphs: false,
12799
+ recursionLimit: 200,
12800
+ signal
12801
+ }
12802
+ );
12803
+ await this.consumeAgentStream(agentStream, signal);
12804
+ }
12633
12805
  getQueueStore() {
12634
12806
  if (!this.queueStore) {
12635
12807
  try {
@@ -12759,6 +12931,8 @@ var Agent = class {
12759
12931
  threadId: this.thread_id,
12760
12932
  tenantId: this.tenant_id,
12761
12933
  assistantId: this.assistant_id,
12934
+ workspaceId: this.workspace_id,
12935
+ projectId: this.project_id,
12762
12936
  content,
12763
12937
  type: pendingType,
12764
12938
  command: queueMessage.command,
@@ -12775,6 +12949,8 @@ var Agent = class {
12775
12949
  threadId: this.thread_id,
12776
12950
  tenantId: this.tenant_id,
12777
12951
  assistantId: this.assistant_id,
12952
+ workspaceId: this.workspace_id,
12953
+ projectId: this.project_id,
12778
12954
  content,
12779
12955
  type: pendingType,
12780
12956
  command: queueMessage.command,
@@ -12848,6 +13024,8 @@ var Agent = class {
12848
13024
  threadId: thread.threadId,
12849
13025
  tenantId: thread.tenantId,
12850
13026
  assistantId: thread.assistantId,
13027
+ workspaceId: this.workspace_id,
13028
+ projectId: this.project_id,
12851
13029
  content: reminderContent,
12852
13030
  type: "system"
12853
13031
  });
@@ -12919,9 +13097,14 @@ var Agent = class {
12919
13097
  /**
12920
13098
  * Resume processing after a server restart.
12921
13099
  *
12922
- * Resets any stuck "processing" messages back to "pending" and restarts the
12923
- * queue processor. Skips threads that are in `INTERRUPTED` state (the
12924
- * interruption was intentional).
13100
+ * If the graph was mid-execution (BUSY) it resumes from the LangGraph
13101
+ * checkpoint without re-injecting the message the message has already
13102
+ * been consumed and is in the graph state. Processing messages are removed
13103
+ * rather than replayed.
13104
+ *
13105
+ * Skips threads that are in `INTERRUPTED` state (the interruption was
13106
+ * intentional). IDLE threads simply clean up and restart the queue
13107
+ * processor for any remaining pending messages.
12925
13108
  *
12926
13109
  * Called during gateway startup to recover threads that were mid-execution
12927
13110
  * when the server went down.
@@ -12939,9 +13122,32 @@ var Agent = class {
12939
13122
  return;
12940
13123
  }
12941
13124
  const store = this.getQueueStore();
12942
- const resetCount = await store.resetProcessingToPending(this.thread_id);
12943
- if (resetCount > 0) {
12944
- console.log(`[Agent] Reset ${resetCount} processing messages to pending for thread ${this.thread_id}`);
13125
+ if (runStatus === "busy" /* BUSY */) {
13126
+ this.abortController = new AbortController();
13127
+ try {
13128
+ await this.resumeGraphFromCheckpoint(this.abortController.signal);
13129
+ const processingMessages = await store.getProcessingMessages(this.thread_id);
13130
+ for (const msg of processingMessages) {
13131
+ await store.removeMessage(msg.id);
13132
+ }
13133
+ if (processingMessages.length > 0) {
13134
+ console.log(`[Agent] Removed ${processingMessages.length} processing messages for thread ${this.thread_id}`);
13135
+ }
13136
+ } catch (error) {
13137
+ console.error(`[Agent] Failed to resume graph for thread ${this.thread_id}:`, error);
13138
+ await this.chunkBuffer.abortThread(this.thread_id);
13139
+ throw error;
13140
+ } finally {
13141
+ this.abortController = null;
13142
+ }
13143
+ } else {
13144
+ const processingMessages = await store.getProcessingMessages(this.thread_id);
13145
+ for (const msg of processingMessages) {
13146
+ await store.removeMessage(msg.id);
13147
+ }
13148
+ if (processingMessages.length > 0) {
13149
+ console.log(`[Agent] Removed ${processingMessages.length} processing messages for thread ${this.thread_id}`);
13150
+ }
12945
13151
  }
12946
13152
  await this.startQueueProcessorIfNeeded();
12947
13153
  }
@@ -13132,7 +13338,7 @@ var AgentInstanceManager = class _AgentInstanceManager {
13132
13338
  console.log(`[AgentInstanceManager] Found ${threadsWithPending.length} threads with pending messages, restoring...`);
13133
13339
  for (const threadInfo of threadsWithPending) {
13134
13340
  try {
13135
- await this.restoreThread(threadInfo, queueStore);
13341
+ await this.restoreThread(threadInfo);
13136
13342
  stats.restored++;
13137
13343
  } catch (error) {
13138
13344
  console.error(`[AgentInstanceManager] Failed to restore thread ${threadInfo.threadId}:`, error);
@@ -13150,16 +13356,14 @@ var AgentInstanceManager = class _AgentInstanceManager {
13150
13356
  * Restore a single thread
13151
13357
  * Delegates actual recovery logic to Agent.resumeTask()
13152
13358
  */
13153
- async restoreThread(threadInfo, queueStore) {
13154
- const { tenantId, assistantId, threadId } = threadInfo;
13359
+ async restoreThread(threadInfo) {
13360
+ const { tenantId, assistantId, threadId, workspaceId, projectId } = threadInfo;
13155
13361
  const threadParams = {
13156
13362
  tenant_id: tenantId,
13157
13363
  assistant_id: assistantId,
13158
13364
  thread_id: threadId,
13159
- workspace_id: "default",
13160
- // TODO: Get from thread store
13161
- project_id: "default"
13162
- // TODO: Get from thread store
13365
+ workspace_id: workspaceId,
13366
+ project_id: projectId
13163
13367
  };
13164
13368
  const agent = this.getAgent(threadParams);
13165
13369
  await agent.resumeTask();
@@ -13250,7 +13454,7 @@ function createSchedulerMiddleware(options = {}) {
13250
13454
  async (input, config) => {
13251
13455
  const runConfig = getRunConfig(config);
13252
13456
  const scheduleLattice = getScheduleLattice(SCHEDULE_LATTICE_KEY);
13253
- const taskId = uuidv4();
13457
+ const taskId = uuidv42();
13254
13458
  const executeAt = input.executeAt;
13255
13459
  const success = await scheduleLattice.client.scheduleOnce(
13256
13460
  taskId,
@@ -13285,7 +13489,7 @@ function createSchedulerMiddleware(options = {}) {
13285
13489
  async (input, config) => {
13286
13490
  const runConfig = getRunConfig(config);
13287
13491
  const scheduleLattice = getScheduleLattice(SCHEDULE_LATTICE_KEY);
13288
- const taskId = uuidv4();
13492
+ const taskId = uuidv42();
13289
13493
  const executeAt = Date.now() + input.delayMs;
13290
13494
  const success = await scheduleLattice.client.scheduleOnce(
13291
13495
  taskId,
@@ -13320,7 +13524,7 @@ function createSchedulerMiddleware(options = {}) {
13320
13524
  async (input, config) => {
13321
13525
  const runConfig = getRunConfig(config);
13322
13526
  const scheduleLattice = getScheduleLattice(SCHEDULE_LATTICE_KEY);
13323
- const taskId = uuidv4();
13527
+ const taskId = uuidv42();
13324
13528
  const success = await scheduleLattice.client.scheduleCron(
13325
13529
  taskId,
13326
13530
  AGENT_ADD_MESSAGE_TASK_TYPE,
@@ -13408,6 +13612,138 @@ function createSchedulerMiddleware(options = {}) {
13408
13612
  });
13409
13613
  }
13410
13614
 
13615
+ // src/middlewares/taskMiddleware.ts
13616
+ import { createMiddleware as createMiddleware14, tool as tool46 } from "langchain";
13617
+ import { z as z49 } from "zod";
13618
+ function getRunConfig2(config) {
13619
+ const c = config;
13620
+ return c?.configurable?.runConfig ?? {};
13621
+ }
13622
+ function getTaskStore() {
13623
+ return getStoreLattice("default", "task").store;
13624
+ }
13625
+ var manageTaskSchema = z49.object({
13626
+ action: z49.enum(["create", "list", "update", "delete", "complete"]).describe("\u64CD\u4F5C\u7C7B\u578B"),
13627
+ id: z49.string().optional().describe("\u4EFB\u52A1 ID (update/delete/complete \u5FC5\u586B)"),
13628
+ title: z49.string().optional().describe("\u4EFB\u52A1\u6807\u9898 (create \u5FC5\u586B)"),
13629
+ description: z49.string().optional().describe("\u4EFB\u52A1\u63CF\u8FF0"),
13630
+ priority: z49.enum(["low", "medium", "high"]).optional().describe("\u4F18\u5148\u7EA7"),
13631
+ status: z49.enum(["pending", "in_progress", "completed", "cancelled"]).optional().describe("\u72B6\u6001"),
13632
+ dueDate: z49.string().optional().describe("\u622A\u6B62\u65E5\u671F (ISO 8601)"),
13633
+ metadata: z49.record(z49.unknown()).optional().describe("\u7ED3\u6784\u5316\u5143\u6570\u636E (projectId, module \u7B49)"),
13634
+ parentId: z49.string().optional().describe("\u7236\u4EFB\u52A1 ID (\u5B50\u4EFB\u52A1\u5173\u8054)"),
13635
+ sourceId: z49.string().optional().describe("\u6765\u6E90\u4F1A\u8BDD/thread ID"),
13636
+ context: z49.record(z49.unknown()).optional().describe("\u9644\u52A0\u4E0A\u4E0B\u6587"),
13637
+ ownerType: z49.enum(["user", "agent"]).optional().describe("\u6240\u6709\u8005\u7C7B\u578B\uFF0C\u4E0D\u4F20\u9ED8\u8BA4\u4E3A user"),
13638
+ ownerId: z49.string().optional().describe("\u6240\u6709\u8005 ID\uFF0C\u4E0D\u4F20\u81EA\u52A8\u53D6\u5F53\u524D\u7528\u6237/Agent")
13639
+ });
13640
+ function createTaskMiddleware() {
13641
+ return createMiddleware14({
13642
+ name: "TaskMiddleware",
13643
+ contextSchema,
13644
+ wrapModelCall: async (request, handler) => {
13645
+ const taskPrompt = `## \u4EFB\u52A1\u7BA1\u7406\u80FD\u529B
13646
+ \u4F60\u53EF\u4EE5\u901A\u8FC7 manage_task \u5DE5\u5177\u7BA1\u7406\u6301\u4E45\u5316\u4EFB\u52A1\u3002ownerType \u548C ownerId \u7684\u9ED8\u8BA4\u884C\u4E3A\uFF1A
13647
+ - \u4E0D\u4F20\u53C2\u6570: \u9ED8\u8BA4\u4E3A\u5F53\u524D\u7528\u6237\u521B\u5EFA\u4EFB\u52A1 (ownerType="user", ownerId \u81EA\u52A8\u53D6\u5F53\u524D\u7528\u6237)
13648
+ - ownerType="agent": \u4E3A\u81EA\u5DF1\u521B\u5EFA\u6267\u884C\u5B50\u4EFB\u52A1 (ownerId \u81EA\u52A8\u53D6\u5F53\u524D Agent)
13649
+ - \u663E\u5F0F\u4F20 ownerId: \u4E3A\u6307\u5B9A agent/user \u521B\u5EFA\u4EFB\u52A1\uFF08\u62D3\u6251\u573A\u666F\uFF09`;
13650
+ return handler({
13651
+ ...request,
13652
+ systemPrompt: taskPrompt + "\n\n" + (request.systemPrompt ?? "")
13653
+ });
13654
+ },
13655
+ tools: [
13656
+ tool46(
13657
+ async (input, config) => {
13658
+ const rc = getRunConfig2(config);
13659
+ const tenantId = rc.tenantId || "default";
13660
+ const ownerId = input.ownerId || (input.ownerType === "agent" ? rc.assistant_id : null) || rc.user_id;
13661
+ const store = getTaskStore();
13662
+ switch (input.action) {
13663
+ case "create": {
13664
+ if (!input.title) {
13665
+ return JSON.stringify({ success: false, error: "create requires title" });
13666
+ }
13667
+ const task = await store.create({
13668
+ tenantId,
13669
+ ownerType: input.ownerType || "user",
13670
+ ownerId,
13671
+ title: input.title,
13672
+ description: input.description,
13673
+ priority: input.priority || "medium",
13674
+ status: input.status || "pending",
13675
+ dueDate: input.dueDate,
13676
+ metadata: input.metadata,
13677
+ parentId: input.parentId,
13678
+ sourceId: input.sourceId,
13679
+ context: input.context
13680
+ });
13681
+ return JSON.stringify({ success: true, data: task });
13682
+ }
13683
+ case "list": {
13684
+ const tasks = await store.list({
13685
+ tenantId,
13686
+ ownerType: input.ownerType,
13687
+ ownerId: input.ownerId,
13688
+ status: input.status,
13689
+ priority: input.priority
13690
+ });
13691
+ return JSON.stringify({ success: true, data: tasks, count: tasks.length });
13692
+ }
13693
+ case "update": {
13694
+ if (!input.id) {
13695
+ return JSON.stringify({ success: false, error: "update requires id" });
13696
+ }
13697
+ const { action, ...updates } = input;
13698
+ const updated = await store.update(tenantId, input.id, updates);
13699
+ if (!updated) {
13700
+ return JSON.stringify({ success: false, error: "Task not found" });
13701
+ }
13702
+ return JSON.stringify({ success: true, data: updated });
13703
+ }
13704
+ case "delete": {
13705
+ if (!input.id) {
13706
+ return JSON.stringify({ success: false, error: "delete requires id" });
13707
+ }
13708
+ const deleted = await store.delete(tenantId, input.id);
13709
+ return JSON.stringify({ success: deleted, message: deleted ? "Task deleted" : "Task not found" });
13710
+ }
13711
+ case "complete": {
13712
+ if (!input.id) {
13713
+ return JSON.stringify({ success: false, error: "complete requires id" });
13714
+ }
13715
+ const updated = await store.update(tenantId, input.id, { status: "completed" });
13716
+ if (!updated) {
13717
+ return JSON.stringify({ success: false, error: "Task not found" });
13718
+ }
13719
+ return JSON.stringify({ success: true, data: updated });
13720
+ }
13721
+ default:
13722
+ return JSON.stringify({ success: false, error: `Unknown action: ${input.action}` });
13723
+ }
13724
+ },
13725
+ {
13726
+ name: "manage_task",
13727
+ description: `\u7BA1\u7406\u6301\u4E45\u5316\u4EFB\u52A1\u7CFB\u7EDF\u3002CRUD \u64CD\u4F5C\u7528\u6237\u548C Agent \u7684\u4EFB\u52A1\u3002
13728
+
13729
+ ## ownerType \u548C ownerId \u7684\u9ED8\u8BA4\u903B\u8F91
13730
+ - \u4E0D\u4F20 ownerType \u548C ownerId: \u7CFB\u7EDF\u81EA\u52A8\u4E3A\u5F53\u524D\u7528\u6237\u521B\u5EFA\u4EFB\u52A1 (ownerType="user", ownerId \u53D6\u81EA\u5F53\u524D\u767B\u5F55\u7528\u6237)
13731
+ - \u4F20 ownerType="agent" \u4E0D\u4F20 ownerId: \u7CFB\u7EDF\u81EA\u52A8\u4E3A\u5F53\u524D Agent \u521B\u5EFA\u5B50\u4EFB\u52A1
13732
+ - \u663E\u5F0F\u4F20 ownerId: \u7CFB\u7EDF\u4F7F\u7528\u4F60\u6307\u5B9A\u7684 ID\uFF0C\u53EF\u8DE8 Agent \u6D3E\u53D1\u4EFB\u52A1\uFF08\u62D3\u6251\u573A\u666F\uFF09
13733
+
13734
+ ## Actions
13735
+ - create: \u521B\u5EFA\u4EFB\u52A1 (title \u5FC5\u586B, priority/description/dueDate/metadata/parentId/context \u53EF\u9009)
13736
+ - list: \u5217\u51FA\u4EFB\u52A1\uFF0C\u53EF\u6309 ownerType/status/priority \u8FC7\u6EE4
13737
+ - update: \u66F4\u65B0\u4EFB\u52A1 (id \u5FC5\u586B\uFF0C\u53EA\u4F20\u8981\u6539\u7684\u5B57\u6BB5)
13738
+ - delete: \u5220\u9664\u4EFB\u52A1 (id \u5FC5\u586B)
13739
+ - complete: \u5FEB\u901F\u6807\u8BB0\u5B8C\u6210 (id \u5FC5\u586B)`,
13740
+ schema: manageTaskSchema
13741
+ }
13742
+ )
13743
+ ]
13744
+ });
13745
+ }
13746
+
13411
13747
  // src/agent_lattice/builders/CustomMiddlewareRegistry.ts
13412
13748
  var CustomMiddlewareRegistry = class {
13413
13749
  /**
@@ -13543,6 +13879,9 @@ async function createCommonMiddlewares(middlewareConfigs, filesystemBackend, fsI
13543
13879
  case "scheduler":
13544
13880
  middlewares.push(createSchedulerMiddleware(config.config));
13545
13881
  break;
13882
+ case "task":
13883
+ middlewares.push(createTaskMiddleware());
13884
+ break;
13546
13885
  case "custom":
13547
13886
  {
13548
13887
  const customConfig = config.config;
@@ -13750,9 +14089,9 @@ var ReActAgentGraphBuilder = class {
13750
14089
  */
13751
14090
  async build(agentLattice, params) {
13752
14091
  const tools = params.tools.map((t) => {
13753
- const tool51 = getToolClient(t.key);
13754
- return tool51;
13755
- }).filter((tool51) => tool51 !== void 0);
14092
+ const tool52 = getToolClient(t.key);
14093
+ return tool52;
14094
+ }).filter((tool52) => tool52 !== void 0);
13756
14095
  const stateSchema2 = createReactAgentSchema(params.stateSchema);
13757
14096
  const middlewareConfigs = params.middleware || [];
13758
14097
  const filesystemBackend = createFilesystemBackendFactory(middlewareConfigs);
@@ -13764,7 +14103,8 @@ var ReActAgentGraphBuilder = class {
13764
14103
  name: agentLattice.config.name,
13765
14104
  checkpointer: getCheckpointSaver("default"),
13766
14105
  stateSchema: stateSchema2,
13767
- middleware: middlewares
14106
+ middleware: middlewares,
14107
+ responseFormat: params.responseFormat
13768
14108
  });
13769
14109
  }
13770
14110
  };
@@ -13778,11 +14118,11 @@ import {
13778
14118
  } from "langchain";
13779
14119
 
13780
14120
  // src/deep_agent_new/middleware/subagents.ts
13781
- import { z as z49 } from "zod/v3";
14121
+ import { z as z50 } from "zod/v3";
13782
14122
  import {
13783
- createMiddleware as createMiddleware14,
14123
+ createMiddleware as createMiddleware15,
13784
14124
  createAgent as createAgent2,
13785
- tool as tool46,
14125
+ tool as tool47,
13786
14126
  ToolMessage as ToolMessage4,
13787
14127
  humanInTheLoopMiddleware
13788
14128
  } from "langchain";
@@ -14215,7 +14555,7 @@ function createTaskTool(options) {
14215
14555
  generalPurposeAgent
14216
14556
  });
14217
14557
  const finalTaskDescription = taskDescription ? taskDescription : getTaskToolDescription(subagentDescriptions);
14218
- return tool46(
14558
+ return tool47(
14219
14559
  async (input, config) => {
14220
14560
  const { description, subagent_type, async } = input;
14221
14561
  let assistant_id = subagent_type;
@@ -14249,12 +14589,16 @@ function createTaskTool(options) {
14249
14589
  const subagent_thread_id = config.configurable?.thread_id + "____" + assistant_id + "_" + config.toolCall.id;
14250
14590
  if (async) {
14251
14591
  const tenantId = config.configurable?.runConfig?.tenantId;
14592
+ const workspaceId = config.configurable?.runConfig?.workspaceId;
14593
+ const projectId = config.configurable?.runConfig?.projectId;
14252
14594
  const mainAssistantId = config.configurable?.runConfig?.assistant_id;
14253
14595
  const mainThreadId = config.configurable?.runConfig?.thread_id;
14254
14596
  const mainRuntimeAgent = agentInstanceManager.getAgent({
14255
14597
  assistant_id: mainAssistantId,
14256
14598
  thread_id: mainThreadId,
14257
- tenant_id: tenantId
14599
+ tenant_id: tenantId,
14600
+ workspace_id: workspaceId,
14601
+ project_id: projectId
14258
14602
  });
14259
14603
  if (mainRuntimeAgent) {
14260
14604
  mainRuntimeAgent.addAsyncTask({
@@ -14333,15 +14677,15 @@ The result will be delivered as a notification when complete. Do not poll.`,
14333
14677
  {
14334
14678
  name: "task",
14335
14679
  description: finalTaskDescription,
14336
- schema: z49.object({
14337
- description: z49.string().describe("The task to execute with the selected agent"),
14338
- subagent_type: z49.string().describe(
14680
+ schema: z50.object({
14681
+ description: z50.string().describe("The task to execute with the selected agent"),
14682
+ subagent_type: z50.string().describe(
14339
14683
  `Name of the agent to use. Available: ${Object.keys(
14340
14684
  subagentGraphs
14341
14685
  ).join(", ")}`
14342
14686
  ),
14343
14687
  ...allowAsync ? {
14344
- async: z49.boolean().default(false).describe(
14688
+ async: z50.boolean().default(false).describe(
14345
14689
  "When true, runs the task in the background and returns immediately. Use for independent tasks that can run in parallel. The result is delivered as a notification when complete. Use check_async_task or list_async_tasks to monitor progress."
14346
14690
  )
14347
14691
  } : {}
@@ -14360,7 +14704,7 @@ function getMainAgentFromConfig(config) {
14360
14704
  });
14361
14705
  }
14362
14706
  function createCheckAsyncTaskTool() {
14363
- return tool46(
14707
+ return tool47(
14364
14708
  async (input, config) => {
14365
14709
  const { task_id } = input;
14366
14710
  const mainAgent = getMainAgentFromConfig(config);
@@ -14420,14 +14764,14 @@ Description: ${cached.description}`;
14420
14764
  {
14421
14765
  name: "check_async_task",
14422
14766
  description: "Get the current status and result of an async background task. Use this to check if a previously launched async task has completed.",
14423
- schema: z49.object({
14424
- task_id: z49.string().describe("The task ID returned when the async task was started")
14767
+ schema: z50.object({
14768
+ task_id: z50.string().describe("The task ID returned when the async task was started")
14425
14769
  })
14426
14770
  }
14427
14771
  );
14428
14772
  }
14429
14773
  function createListAsyncTasksTool() {
14430
- return tool46(
14774
+ return tool47(
14431
14775
  async (_input, config) => {
14432
14776
  const mainAgent = getMainAgentFromConfig(config);
14433
14777
  if (!mainAgent) {
@@ -14473,12 +14817,12 @@ function createListAsyncTasksTool() {
14473
14817
  {
14474
14818
  name: "list_async_tasks",
14475
14819
  description: "List all async background tasks with their current status. Use this before reporting task status to the user. Statuses in conversation history may be stale.",
14476
- schema: z49.object({})
14820
+ schema: z50.object({})
14477
14821
  }
14478
14822
  );
14479
14823
  }
14480
14824
  function createCancelAsyncTaskTool() {
14481
- return tool46(
14825
+ return tool47(
14482
14826
  async (input, config) => {
14483
14827
  const { task_id } = input;
14484
14828
  const mainAgent = getMainAgentFromConfig(config);
@@ -14517,8 +14861,8 @@ function createCancelAsyncTaskTool() {
14517
14861
  {
14518
14862
  name: "cancel_async_task",
14519
14863
  description: "Cancel a running async background task.",
14520
- schema: z49.object({
14521
- task_id: z49.string().describe("The task ID to cancel")
14864
+ schema: z50.object({
14865
+ task_id: z50.string().describe("The task ID to cancel")
14522
14866
  })
14523
14867
  }
14524
14868
  );
@@ -14554,7 +14898,7 @@ function createSubAgentMiddleware(options) {
14554
14898
  );
14555
14899
  }
14556
14900
  const effectiveSystemPrompt = allowAsync ? systemPrompt + getAsyncPromptText() : systemPrompt;
14557
- return createMiddleware14({
14901
+ return createMiddleware15({
14558
14902
  name: "subAgentMiddleware",
14559
14903
  tools: allTools,
14560
14904
  wrapModelCall: async (request, handler) => {
@@ -14575,14 +14919,12 @@ ${effectiveSystemPrompt}` : effectiveSystemPrompt;
14575
14919
 
14576
14920
  // src/deep_agent_new/middleware/patch_tool_calls.ts
14577
14921
  import {
14578
- createMiddleware as createMiddleware15,
14922
+ createMiddleware as createMiddleware16,
14579
14923
  ToolMessage as ToolMessage5,
14580
14924
  AIMessage as AIMessage2
14581
14925
  } from "langchain";
14582
- import { RemoveMessage } from "@langchain/core/messages";
14583
- import { REMOVE_ALL_MESSAGES } from "@langchain/langgraph";
14584
14926
  function createPatchToolCallsMiddleware() {
14585
- return createMiddleware15({
14927
+ return createMiddleware16({
14586
14928
  name: "patchToolCallsMiddleware",
14587
14929
  beforeAgent: async (state) => {
14588
14930
  const messages = state.messages;
@@ -14611,11 +14953,12 @@ function createPatchToolCallsMiddleware() {
14611
14953
  }
14612
14954
  }
14613
14955
  }
14956
+ if (patchedMessages.length === messages.length) {
14957
+ return;
14958
+ }
14614
14959
  return {
14615
- messages: [
14616
- new RemoveMessage({ id: REMOVE_ALL_MESSAGES }),
14617
- ...patchedMessages
14618
- ]
14960
+ messages: patchedMessages.slice(messages.length)
14961
+ // only the new ToolMessage patches
14619
14962
  };
14620
14963
  }
14621
14964
  });
@@ -15728,8 +16071,8 @@ var MemoryBackend = class {
15728
16071
 
15729
16072
  // src/deep_agent_new/middleware/todos.ts
15730
16073
  import { Command as Command4 } from "@langchain/langgraph";
15731
- import { z as z50 } from "zod";
15732
- import { createMiddleware as createMiddleware16, tool as tool47, ToolMessage as ToolMessage6 } from "langchain";
16074
+ import { z as z51 } from "zod";
16075
+ import { createMiddleware as createMiddleware17, tool as tool48, ToolMessage as ToolMessage6 } from "langchain";
15733
16076
  var WRITE_TODOS_DESCRIPTION = `Use this tool to create and manage a structured task list for your current work session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
15734
16077
  It also helps the user understand the progress of the task and overall progress of their requests.
15735
16078
  Only use this tool if you think it will be helpful in staying organized. If the user's request is trivial and takes less than 3 steps, it is better to NOT use this tool and just do the taks directly.
@@ -15956,14 +16299,14 @@ Writing todos takes time and tokens, use it when it is helpful for managing comp
15956
16299
  ## Important To-Do List Usage Notes to Remember
15957
16300
  - The \`write_todos\` tool should never be called multiple times in parallel.
15958
16301
  - Don't be afraid to revise the To-Do list as you go. New information may reveal new tasks that need to be done, or old tasks that are irrelevant.`;
15959
- var TodoStatus = z50.enum(["pending", "in_progress", "completed"]).describe("Status of the todo");
15960
- var TodoSchema = z50.object({
15961
- content: z50.string().describe("Content of the todo item"),
16302
+ var TodoStatus = z51.enum(["pending", "in_progress", "completed"]).describe("Status of the todo");
16303
+ var TodoSchema = z51.object({
16304
+ content: z51.string().describe("Content of the todo item"),
15962
16305
  status: TodoStatus
15963
16306
  });
15964
- var stateSchema = z50.object({ todos: z50.array(TodoSchema).default([]) });
16307
+ var stateSchema = z51.object({ todos: z51.array(TodoSchema).default([]) });
15965
16308
  function todoListMiddleware(options) {
15966
- const writeTodos = tool47(
16309
+ const writeTodos = tool48(
15967
16310
  ({ todos }, config) => {
15968
16311
  return new Command4({
15969
16312
  update: {
@@ -15980,12 +16323,12 @@ function todoListMiddleware(options) {
15980
16323
  {
15981
16324
  name: "write_todos",
15982
16325
  description: options?.toolDescription ?? WRITE_TODOS_DESCRIPTION,
15983
- schema: z50.object({
15984
- todos: z50.array(TodoSchema).describe("List of todo items to update")
16326
+ schema: z51.object({
16327
+ todos: z51.array(TodoSchema).describe("List of todo items to update")
15985
16328
  })
15986
16329
  }
15987
16330
  );
15988
- return createMiddleware16({
16331
+ return createMiddleware17({
15989
16332
  name: "todoListMiddleware",
15990
16333
  stateSchema,
15991
16334
  tools: [writeTodos],
@@ -16097,7 +16440,7 @@ var DeepAgentGraphBuilder = class {
16097
16440
  const tools = params.tools.map((t) => {
16098
16441
  const toolClient = getToolClient(t.key);
16099
16442
  return toolClient;
16100
- }).filter((tool51) => tool51 !== void 0);
16443
+ }).filter((tool52) => tool52 !== void 0);
16101
16444
  const subagents = await Promise.all(params.subAgents.map(async (sa) => {
16102
16445
  if (sa.client) {
16103
16446
  return {
@@ -16127,6 +16470,7 @@ var DeepAgentGraphBuilder = class {
16127
16470
  contextSchema: params.stateSchema,
16128
16471
  systemPrompt: params.prompt,
16129
16472
  subagents,
16473
+ responseFormat: params.responseFormat,
16130
16474
  checkpointer: getCheckpointSaver("default"),
16131
16475
  skills: params.skillCategories,
16132
16476
  backend: filesystemBackend,
@@ -16137,7 +16481,7 @@ var DeepAgentGraphBuilder = class {
16137
16481
  };
16138
16482
 
16139
16483
  // src/agent_team/agent_team.ts
16140
- import { z as z53 } from "zod/v3";
16484
+ import { z as z54 } from "zod/v3";
16141
16485
  import { createAgent as createAgent5 } from "langchain";
16142
16486
 
16143
16487
  // src/agent_team/types.ts
@@ -16573,14 +16917,14 @@ var InMemoryMailboxStore = class {
16573
16917
  };
16574
16918
 
16575
16919
  // src/agent_team/middleware/team.ts
16576
- import { z as z52 } from "zod/v3";
16577
- import { createMiddleware as createMiddleware17, createAgent as createAgent4, tool as tool49, ToolMessage as ToolMessage8 } from "langchain";
16920
+ import { z as z53 } from "zod/v3";
16921
+ import { createMiddleware as createMiddleware18, createAgent as createAgent4, tool as tool50, ToolMessage as ToolMessage8 } from "langchain";
16578
16922
  import { Command as Command6, getCurrentTaskInput as getCurrentTaskInput3 } from "@langchain/langgraph";
16579
- import { v4 as uuidv42 } from "uuid";
16923
+ import { v4 as uuidv43 } from "uuid";
16580
16924
 
16581
16925
  // src/agent_team/middleware/teammate_tools.ts
16582
- import { z as z51 } from "zod/v3";
16583
- import { tool as tool48, ToolMessage as ToolMessage7 } from "langchain";
16926
+ import { z as z52 } from "zod/v3";
16927
+ import { tool as tool49, ToolMessage as ToolMessage7 } from "langchain";
16584
16928
  import { Command as Command5 } from "@langchain/langgraph";
16585
16929
 
16586
16930
  // src/agent_team/middleware/formatMessages.ts
@@ -16605,7 +16949,7 @@ ${meta}${body}`;
16605
16949
  // src/agent_team/middleware/teammate_tools.ts
16606
16950
  function createTeammateTools(options) {
16607
16951
  const { teamId, agentId, taskListStore, mailboxStore } = options;
16608
- const claimTaskTool = tool48(
16952
+ const claimTaskTool = tool49(
16609
16953
  async (input) => {
16610
16954
  const task = await taskListStore.claimTaskById(
16611
16955
  teamId,
@@ -16630,12 +16974,12 @@ function createTeammateTools(options) {
16630
16974
  {
16631
16975
  name: "claim_task",
16632
16976
  description: "Pick a task to work on by task_id. Use check_tasks first to see all tasks; then call this with the task_id you choose. The task's assignee is set to you and you should focus on that task until you complete_task or fail_task it.",
16633
- schema: z51.object({
16634
- task_id: z51.string().describe("ID of the task to claim (e.g. task-01). Use check_tasks to see IDs.")
16977
+ schema: z52.object({
16978
+ task_id: z52.string().describe("ID of the task to claim (e.g. task-01). Use check_tasks to see IDs.")
16635
16979
  })
16636
16980
  }
16637
16981
  );
16638
- const completeTaskTool = tool48(
16982
+ const completeTaskTool = tool49(
16639
16983
  async (input) => {
16640
16984
  const task = await taskListStore.completeTask(
16641
16985
  teamId,
@@ -16656,13 +17000,13 @@ function createTeammateTools(options) {
16656
17000
  {
16657
17001
  name: "complete_task",
16658
17002
  description: "Mark a claimed task as completed with a result summary. Call this after you have finished working on a task.",
16659
- schema: z51.object({
16660
- task_id: z51.string().describe("ID of the task to complete"),
16661
- result: z51.string().describe("Summary of the task result")
17003
+ schema: z52.object({
17004
+ task_id: z52.string().describe("ID of the task to complete"),
17005
+ result: z52.string().describe("Summary of the task result")
16662
17006
  })
16663
17007
  }
16664
17008
  );
16665
- const failTaskTool = tool48(
17009
+ const failTaskTool = tool49(
16666
17010
  async (input) => {
16667
17011
  const task = await taskListStore.failTask(
16668
17012
  teamId,
@@ -16683,13 +17027,13 @@ function createTeammateTools(options) {
16683
17027
  {
16684
17028
  name: "fail_task",
16685
17029
  description: "Mark a claimed task as failed with an error description. Call this if you cannot complete the task.",
16686
- schema: z51.object({
16687
- task_id: z51.string().describe("ID of the task to fail"),
16688
- error: z51.string().describe("Description of why the task failed")
17030
+ schema: z52.object({
17031
+ task_id: z52.string().describe("ID of the task to fail"),
17032
+ error: z52.string().describe("Description of why the task failed")
16689
17033
  })
16690
17034
  }
16691
17035
  );
16692
- const sendMessageTool = tool48(
17036
+ const sendMessageTool = tool49(
16693
17037
  async (input) => {
16694
17038
  await mailboxStore.sendMessage(
16695
17039
  teamId,
@@ -16703,11 +17047,11 @@ function createTeammateTools(options) {
16703
17047
  {
16704
17048
  name: "send_message",
16705
17049
  description: 'Send a message to the team lead or another teammate via the mailbox. Use "team_lead" to message the team lead. Use this to report discoveries, request guidance, or suggest new tasks.',
16706
- schema: z51.object({
16707
- to: z51.string().describe(
17050
+ schema: z52.object({
17051
+ to: z52.string().describe(
16708
17052
  'Recipient agent name (e.g. "team_lead" or a teammate name)'
16709
17053
  ),
16710
- content: z51.string().describe("Message content")
17054
+ content: z52.string().describe("Message content")
16711
17055
  })
16712
17056
  }
16713
17057
  );
@@ -16727,7 +17071,7 @@ function createTeammateTools(options) {
16727
17071
  read: msg.read
16728
17072
  }));
16729
17073
  };
16730
- const readMessagesTool = tool48(
17074
+ const readMessagesTool = tool49(
16731
17075
  async (input, config) => {
16732
17076
  const formatAndMarkAsRead = async (msgs2) => {
16733
17077
  for (const msg of msgs2) {
@@ -16786,10 +17130,10 @@ function createTeammateTools(options) {
16786
17130
  {
16787
17131
  name: "read_messages",
16788
17132
  description: "Read unread messages from the mailbox. Returns immediately if messages exist, otherwise waits for up to 3 minutes for new messages.",
16789
- schema: z51.object({})
17133
+ schema: z52.object({})
16790
17134
  }
16791
17135
  );
16792
- const checkTasksTool = tool48(
17136
+ const checkTasksTool = tool49(
16793
17137
  async () => {
16794
17138
  const tasks = await taskListStore.getAllTasks(teamId);
16795
17139
  return formatTaskSummary(tasks);
@@ -16797,10 +17141,10 @@ function createTeammateTools(options) {
16797
17141
  {
16798
17142
  name: "check_tasks",
16799
17143
  description: "Use this tool to get the current status of all tasks in a team. This is your primary way to monitor task progress.",
16800
- schema: z51.object({})
17144
+ schema: z52.object({})
16801
17145
  }
16802
17146
  );
16803
- const broadcastMessageTool = tool48(
17147
+ const broadcastMessageTool = tool49(
16804
17148
  async (input) => {
16805
17149
  const allAgents = await mailboxStore.getRegisteredAgents(teamId);
16806
17150
  const recipients = allAgents.filter((a) => a !== agentId);
@@ -16819,8 +17163,8 @@ function createTeammateTools(options) {
16819
17163
  {
16820
17164
  name: "broadcast_message",
16821
17165
  description: "Send a message to everyone in the team except yourself. Use this to share updates or information with all teammates and the team lead at once.",
16822
- schema: z51.object({
16823
- content: z51.string().describe("Message content to broadcast to others")
17166
+ schema: z52.object({
17167
+ content: z52.string().describe("Message content to broadcast to others")
16824
17168
  })
16825
17169
  }
16826
17170
  );
@@ -17054,7 +17398,7 @@ async function spawnTeammate(options) {
17054
17398
  function createTeamMiddleware(options) {
17055
17399
  const { teamConfig, taskListStore, mailboxStore, tenantId } = options;
17056
17400
  const defaultModel = teamConfig.model ?? "claude-sonnet-4-5-20250929";
17057
- const createTeamTool = tool49(
17401
+ const createTeamTool = tool50(
17058
17402
  async (input, config) => {
17059
17403
  const state = getCurrentTaskInput3();
17060
17404
  if (state?.team?.teamId) {
@@ -17066,7 +17410,7 @@ function createTeamMiddleware(options) {
17066
17410
  });
17067
17411
  return msg;
17068
17412
  }
17069
- const teamId = uuidv42();
17413
+ const teamId = uuidv43();
17070
17414
  const createdTasks = await taskListStore.addTasks(
17071
17415
  teamId,
17072
17416
  input.tasks.map((t) => ({
@@ -17209,20 +17553,20 @@ After calling create_team, you MUST:
17209
17553
  2. When messages indicate task changes, call check_tasks to get full task status
17210
17554
  3. Continue until all tasks show "completed" or "failed"
17211
17555
  4. Do NOT assume tasks are done - always verify with check_tasks`,
17212
- schema: z52.object({
17213
- tasks: z52.array(
17214
- z52.object({
17215
- id: z52.string().describe("Task ID in format task-01, task-02, etc."),
17216
- title: z52.string().describe("Short task title"),
17217
- description: z52.string().describe("Detailed task description - what exactly needs to be done"),
17218
- dependencies: z52.array(z52.string()).optional().default([]).describe('Array of task IDs that must complete before this task (e.g. ["task-01"])')
17556
+ schema: z53.object({
17557
+ tasks: z53.array(
17558
+ z53.object({
17559
+ id: z53.string().describe("Task ID in format task-01, task-02, etc."),
17560
+ title: z53.string().describe("Short task title"),
17561
+ description: z53.string().describe("Detailed task description - what exactly needs to be done"),
17562
+ dependencies: z53.array(z53.string()).optional().default([]).describe('Array of task IDs that must complete before this task (e.g. ["task-01"])')
17219
17563
  })
17220
17564
  ).describe("List of tasks for teammates to work on. Each task needs unique ID (task-01, task-02, etc.)."),
17221
- teammates: z52.array(
17222
- z52.object({
17223
- name: z52.string().describe("Teammate name (must match a pre-configured teammate type)"),
17224
- role: z52.string().describe("Role category (e.g. researcher, writer, coder, reviewer)"),
17225
- description: z52.string().describe("What this teammate will focus on - specific instructions for their work")
17565
+ teammates: z53.array(
17566
+ z53.object({
17567
+ name: z53.string().describe("Teammate name (must match a pre-configured teammate type)"),
17568
+ role: z53.string().describe("Role category (e.g. researcher, writer, coder, reviewer)"),
17569
+ description: z53.string().describe("What this teammate will focus on - specific instructions for their work")
17226
17570
  })
17227
17571
  ).describe("Teammate agents to create. Each should have a clear role and focus.")
17228
17572
  })
@@ -17233,7 +17577,7 @@ After calling create_team, you MUST:
17233
17577
  if (state?.team?.teamId) return state.team.teamId;
17234
17578
  throw new Error("No team_id provided and no team in state. Call create_team first.");
17235
17579
  };
17236
- const addTasksTool = tool49(
17580
+ const addTasksTool = tool50(
17237
17581
  async (input, config) => {
17238
17582
  const teamId = resolveTeamId();
17239
17583
  const created = await taskListStore.addTasks(
@@ -17285,20 +17629,20 @@ IMPORTANT: Dependencies
17285
17629
 
17286
17630
  IMPORTANT: Assigning to a specific teammate
17287
17631
  - When you need a particular teammate to do the work, set assignee to that teammate's name (e.g. assignee: "researcher"). They can then claim or see the task as assigned to them.`,
17288
- schema: z52.object({
17289
- tasks: z52.array(
17290
- z52.object({
17291
- id: z52.string().describe("Task ID in format task-01, task-02, etc. Must be unique."),
17292
- title: z52.string().describe("Short task title"),
17293
- description: z52.string().describe("Detailed task description - what needs to be done"),
17294
- assignee: z52.string().optional().describe("Teammate name to assign this task to (use when you need that person to do the work)"),
17295
- dependencies: z52.array(z52.string()).optional().default([]).describe("Array of task IDs that must complete before this task")
17632
+ schema: z53.object({
17633
+ tasks: z53.array(
17634
+ z53.object({
17635
+ id: z53.string().describe("Task ID in format task-01, task-02, etc. Must be unique."),
17636
+ title: z53.string().describe("Short task title"),
17637
+ description: z53.string().describe("Detailed task description - what needs to be done"),
17638
+ assignee: z53.string().optional().describe("Teammate name to assign this task to (use when you need that person to do the work)"),
17639
+ dependencies: z53.array(z53.string()).optional().default([]).describe("Array of task IDs that must complete before this task")
17296
17640
  })
17297
17641
  ).describe("New tasks to add to the team")
17298
17642
  })
17299
17643
  }
17300
17644
  );
17301
- const assignTaskTool = tool49(
17645
+ const assignTaskTool = tool50(
17302
17646
  async (input, config) => {
17303
17647
  const teamId = resolveTeamId();
17304
17648
  const task = await taskListStore.updateTask(teamId, input.task_id, {
@@ -17320,13 +17664,13 @@ IMPORTANT: Assigning to a specific teammate
17320
17664
  {
17321
17665
  name: "assign_task",
17322
17666
  description: "Assign a task to a specific teammate. Use when you need to reassign work to a different teammate. Omit team_id to use the active team from state.",
17323
- schema: z52.object({
17324
- task_id: z52.string().describe("Task ID to assign"),
17325
- assignee: z52.string().describe("Teammate name to assign this task to")
17667
+ schema: z53.object({
17668
+ task_id: z53.string().describe("Task ID to assign"),
17669
+ assignee: z53.string().describe("Teammate name to assign this task to")
17326
17670
  })
17327
17671
  }
17328
17672
  );
17329
- const setTaskStatusTool = tool49(
17673
+ const setTaskStatusTool = tool50(
17330
17674
  async (input, config) => {
17331
17675
  const teamId = resolveTeamId();
17332
17676
  const task = await taskListStore.updateTask(teamId, input.task_id, {
@@ -17348,13 +17692,13 @@ IMPORTANT: Assigning to a specific teammate
17348
17692
  {
17349
17693
  name: "set_task_status",
17350
17694
  description: "Set a task's status. Use to reopen a task (set to pending), mark as failed, or correct status. Values: pending, claimed, in_progress, completed, failed. Omit team_id to use the active team from state.",
17351
- schema: z52.object({
17352
- task_id: z52.string().describe("Task ID to update"),
17353
- status: z52.enum(["pending", "claimed", "in_progress", "completed", "failed"]).describe("New status for the task")
17695
+ schema: z53.object({
17696
+ task_id: z53.string().describe("Task ID to update"),
17697
+ status: z53.enum(["pending", "claimed", "in_progress", "completed", "failed"]).describe("New status for the task")
17354
17698
  })
17355
17699
  }
17356
17700
  );
17357
- const setTaskDependenciesTool = tool49(
17701
+ const setTaskDependenciesTool = tool50(
17358
17702
  async (input, config) => {
17359
17703
  const teamId = resolveTeamId();
17360
17704
  const task = await taskListStore.updateTask(teamId, input.task_id, {
@@ -17376,13 +17720,13 @@ IMPORTANT: Assigning to a specific teammate
17376
17720
  {
17377
17721
  name: "set_task_dependencies",
17378
17722
  description: 'Set which task IDs must complete before this task can be claimed. Pass an array of task IDs (e.g. ["task-01", "task-02"]). Use to fix task order or add/remove dependencies. Omit team_id to use the active team from state.',
17379
- schema: z52.object({
17380
- task_id: z52.string().describe("Task ID to update"),
17381
- dependencies: z52.array(z52.string()).describe("Task IDs that must complete before this task can be claimed")
17723
+ schema: z53.object({
17724
+ task_id: z53.string().describe("Task ID to update"),
17725
+ dependencies: z53.array(z53.string()).describe("Task IDs that must complete before this task can be claimed")
17382
17726
  })
17383
17727
  }
17384
17728
  );
17385
- const checkTasksTool = tool49(
17729
+ const checkTasksTool = tool50(
17386
17730
  async (input, config) => {
17387
17731
  const teamId = resolveTeamId();
17388
17732
  const tasks = await taskListStore.getAllTasks(teamId);
@@ -17422,12 +17766,12 @@ Task Status Values:
17422
17766
  - in_progress: Teammate is actively working on this task
17423
17767
  - completed: Task finished successfully
17424
17768
  - failed: Task encountered an error`,
17425
- schema: z52.object({
17426
- team_id: z52.string().optional().describe("Team ID (omit to use active team)")
17769
+ schema: z53.object({
17770
+ team_id: z53.string().optional().describe("Team ID (omit to use active team)")
17427
17771
  })
17428
17772
  }
17429
17773
  );
17430
- const sendMessageTool = tool49(
17774
+ const sendMessageTool = tool50(
17431
17775
  async (input, config) => {
17432
17776
  const teamId = resolveTeamId();
17433
17777
  await mailboxStore.sendMessage(
@@ -17446,13 +17790,13 @@ Task Status Values:
17446
17790
  {
17447
17791
  name: "send_message",
17448
17792
  description: "Send a message to a specific teammate in the team. Omit team_id to use the active team from state.",
17449
- schema: z52.object({
17450
- to: z52.string().describe("Recipient teammate name"),
17451
- content: z52.string().describe("Message content")
17793
+ schema: z53.object({
17794
+ to: z53.string().describe("Recipient teammate name"),
17795
+ content: z53.string().describe("Message content")
17452
17796
  })
17453
17797
  }
17454
17798
  );
17455
- const readMessagesTool = tool49(
17799
+ const readMessagesTool = tool50(
17456
17800
  async (input, config) => {
17457
17801
  const teamId = resolveTeamId();
17458
17802
  const formatAndMarkAsRead = async (msgs2) => {
@@ -17534,12 +17878,12 @@ Task Status Values:
17534
17878
  {
17535
17879
  name: "read_messages",
17536
17880
  description: "Read unread messages from teammates. Returns immediately if messages exist, otherwise waits for up to 3 minutes for new messages.",
17537
- schema: z52.object({
17538
- team_id: z52.string().optional().describe("Team ID (omit to use active team)")
17881
+ schema: z53.object({
17882
+ team_id: z53.string().optional().describe("Team ID (omit to use active team)")
17539
17883
  })
17540
17884
  }
17541
17885
  );
17542
- const disbandTeamTool = tool49(
17886
+ const disbandTeamTool = tool50(
17543
17887
  async (input, config) => {
17544
17888
  const teamId = resolveTeamId();
17545
17889
  await mailboxStore.broadcastMessage(
@@ -17560,7 +17904,7 @@ Task Status Values:
17560
17904
  description: "Disband a team when all work is done. Before calling: (1) Call check_tasks to verify no tasks are still pending/in_progress; (2) if any are, discuss with the team via read_messages and broadcast_message/send_message whether to continue or stop/cancel them; (3) only after alignment (all tasks completed/failed or explicitly stopped), then call this tool. This will: 1) Send a shutdown message to all teammates, 2) Wait briefly for them to clean up, 3) Clear all tasks and messages. Omit team_id to use the active team from state."
17561
17905
  }
17562
17906
  );
17563
- const broadcastMessageTool = tool49(
17907
+ const broadcastMessageTool = tool50(
17564
17908
  async (input, config) => {
17565
17909
  const teamId = resolveTeamId();
17566
17910
  await mailboxStore.broadcastMessage(
@@ -17578,12 +17922,12 @@ Task Status Values:
17578
17922
  {
17579
17923
  name: "broadcast_message",
17580
17924
  description: "Send a message to all teammates at once. Use this to communicate with everyone in the team. Omit team_id to use the active team from state.",
17581
- schema: z52.object({
17582
- content: z52.string().describe("Message content to broadcast to all teammates")
17925
+ schema: z53.object({
17926
+ content: z53.string().describe("Message content to broadcast to all teammates")
17583
17927
  })
17584
17928
  }
17585
17929
  );
17586
- return createMiddleware17({
17930
+ return createMiddleware18({
17587
17931
  name: "teamMiddleware",
17588
17932
  tools: [
17589
17933
  createTeamTool,
@@ -17611,37 +17955,37 @@ ${TEAM_SYSTEM_PROMPT}` : TEAM_SYSTEM_PROMPT;
17611
17955
  }
17612
17956
 
17613
17957
  // src/agent_team/agent_team.ts
17614
- var TeammateInfoSchema = z53.object({
17615
- name: z53.string().describe("Teammate name"),
17616
- role: z53.string().describe("Role category (e.g. research, writing, review)"),
17617
- description: z53.string().describe("What this teammate focuses on")
17958
+ var TeammateInfoSchema = z54.object({
17959
+ name: z54.string().describe("Teammate name"),
17960
+ role: z54.string().describe("Role category (e.g. research, writing, review)"),
17961
+ description: z54.string().describe("What this teammate focuses on")
17618
17962
  });
17619
- var TeamTaskInfoSchema = z53.object({
17620
- id: z53.string(),
17621
- title: z53.string(),
17622
- description: z53.string(),
17623
- status: z53.string().optional()
17963
+ var TeamTaskInfoSchema = z54.object({
17964
+ id: z54.string(),
17965
+ title: z54.string(),
17966
+ description: z54.string(),
17967
+ status: z54.string().optional()
17624
17968
  });
17625
- var MailboxMessageSchema = z53.object({
17626
- id: z53.string().describe("Unique message identifier"),
17627
- from: z53.string().describe("Sender agent name"),
17628
- to: z53.string().describe("Recipient agent name"),
17629
- content: z53.string().describe("Message content"),
17630
- timestamp: z53.string().describe("ISO timestamp when the message was sent"),
17631
- type: z53.nativeEnum(MessageType).describe("Message type"),
17632
- read: z53.boolean().describe("Whether the recipient has read this message")
17969
+ var MailboxMessageSchema = z54.object({
17970
+ id: z54.string().describe("Unique message identifier"),
17971
+ from: z54.string().describe("Sender agent name"),
17972
+ to: z54.string().describe("Recipient agent name"),
17973
+ content: z54.string().describe("Message content"),
17974
+ timestamp: z54.string().describe("ISO timestamp when the message was sent"),
17975
+ type: z54.nativeEnum(MessageType).describe("Message type"),
17976
+ read: z54.boolean().describe("Whether the recipient has read this message")
17633
17977
  });
17634
- var TeamInfoSchema = z53.object({
17635
- teamId: z53.string().describe("Unique team identifier"),
17636
- teamLeadId: z53.string().default("team_lead").describe("Team lead agent ID"),
17637
- teammates: z53.array(TeammateInfoSchema).describe("Active teammates in this team"),
17638
- tasks: z53.array(TeamTaskInfoSchema).optional().describe("Initial tasks snapshot"),
17639
- createdAt: z53.string().optional().describe("ISO timestamp when team was created")
17978
+ var TeamInfoSchema = z54.object({
17979
+ teamId: z54.string().describe("Unique team identifier"),
17980
+ teamLeadId: z54.string().default("team_lead").describe("Team lead agent ID"),
17981
+ teammates: z54.array(TeammateInfoSchema).describe("Active teammates in this team"),
17982
+ tasks: z54.array(TeamTaskInfoSchema).optional().describe("Initial tasks snapshot"),
17983
+ createdAt: z54.string().optional().describe("ISO timestamp when team was created")
17640
17984
  });
17641
- var TEAM_STATE_SCHEMA = z53.object({
17985
+ var TEAM_STATE_SCHEMA = z54.object({
17642
17986
  team: TeamInfoSchema.optional().describe("Team info: teamId, teamLeadId, teammates, tasks. Set when create_team succeeds."),
17643
- tasks: z53.array(TeamTaskInfoSchema).optional().describe("Current tasks snapshot from check_tasks. Updated on each check."),
17644
- team_mailbox: z53.array(MailboxMessageSchema).optional().describe("All team mailbox messages for display")
17987
+ tasks: z54.array(TeamTaskInfoSchema).optional().describe("Current tasks snapshot from check_tasks. Updated on each check."),
17988
+ team_mailbox: z54.array(MailboxMessageSchema).optional().describe("All team mailbox messages for display")
17645
17989
  });
17646
17990
  var TEAM_LEAD_BASE_PROMPT = `You are a team lead that coordinates a team of specialized agents. In order to complete the objective that the user asks of you, you will need to:
17647
17991
 
@@ -17722,7 +18066,7 @@ var TeamAgentGraphBuilder = class {
17722
18066
  const tools = params.tools.map((t) => {
17723
18067
  const toolClient = getToolClient(t.key);
17724
18068
  return toolClient;
17725
- }).filter((tool51) => tool51 !== void 0);
18069
+ }).filter((tool52) => tool52 !== void 0);
17726
18070
  const teammates = params.subAgents.map((sa) => {
17727
18071
  const baseConfig = sa.config;
17728
18072
  return {
@@ -17768,14 +18112,14 @@ import {
17768
18112
  } from "langchain";
17769
18113
 
17770
18114
  // src/middlewares/topologyMiddleware.ts
17771
- import { createMiddleware as createMiddleware18 } from "langchain";
18115
+ import { createMiddleware as createMiddleware19 } from "langchain";
17772
18116
  import { AIMessage as AIMessage3, ToolMessage as ToolMessage9 } from "@langchain/core/messages";
17773
- import { tool as tool50 } from "langchain";
17774
- import { z as z54 } from "zod";
18117
+ import { tool as tool51 } from "langchain";
18118
+ import { z as z55 } from "zod";
17775
18119
  import { GraphInterrupt as GraphInterrupt4 } from "@langchain/langgraph";
17776
- var CompletedEdgeSchema = z54.object({
17777
- to: z54.string(),
17778
- purpose: z54.string()
18120
+ var CompletedEdgeSchema = z55.object({
18121
+ to: z55.string(),
18122
+ purpose: z55.string()
17779
18123
  });
17780
18124
  function deriveCompletedEdges(messages, edges) {
17781
18125
  const completedToolCallIds = /* @__PURE__ */ new Set();
@@ -17802,16 +18146,16 @@ function deriveCompletedEdges(messages, edges) {
17802
18146
  }
17803
18147
  function createTopologyMiddleware(options) {
17804
18148
  const { edges, trackingStore } = options;
17805
- return createMiddleware18({
18149
+ return createMiddleware19({
17806
18150
  name: "TopologyMiddleware",
17807
- contextSchema: z54.object({
17808
- runConfig: z54.any()
18151
+ contextSchema: z55.object({
18152
+ runConfig: z55.any()
17809
18153
  }),
17810
- stateSchema: z54.object({
17811
- currentAgentId: z54.string().default(""),
17812
- completedEdges: z54.array(CompletedEdgeSchema).default([]),
17813
- runId: z54.string().default(""),
17814
- stepIdMap: z54.record(z54.string()).default({})
18154
+ stateSchema: z55.object({
18155
+ currentAgentId: z55.string().default(""),
18156
+ completedEdges: z55.array(CompletedEdgeSchema).default([]),
18157
+ runId: z55.string().default(""),
18158
+ stepIdMap: z55.record(z55.string()).default({})
17815
18159
  }),
17816
18160
  beforeAgent: async (state, runtime) => {
17817
18161
  if (state.runId) {
@@ -17862,14 +18206,14 @@ ${request.systemPrompt}` : topologyPrompt;
17862
18206
  return handler({ ...request, systemPrompt: newSystemPrompt });
17863
18207
  },
17864
18208
  tools: [
17865
- tool50(
18209
+ tool51(
17866
18210
  async (_input) => {
17867
18211
  return "placeholder";
17868
18212
  },
17869
18213
  {
17870
18214
  name: "read_topo_progress",
17871
18215
  description: "Check the current progress of the workflow execution plan. Returns which steps have been completed and which are still pending.",
17872
- schema: z54.object({})
18216
+ schema: z55.object({})
17873
18217
  }
17874
18218
  )
17875
18219
  ],
@@ -18145,7 +18489,7 @@ var ProcessingAgentGraphBuilder = class {
18145
18489
  const tools = params.tools.map((t) => {
18146
18490
  const toolClient = getToolClient(t.key);
18147
18491
  return toolClient;
18148
- }).filter((tool51) => tool51 !== void 0);
18492
+ }).filter((tool52) => tool52 !== void 0);
18149
18493
  const subagents = await Promise.all(params.subAgents.map(async (sa) => {
18150
18494
  if (sa.client) {
18151
18495
  return {
@@ -18179,6 +18523,7 @@ var ProcessingAgentGraphBuilder = class {
18179
18523
  contextSchema: params.stateSchema,
18180
18524
  systemPrompt: params.prompt,
18181
18525
  subagents,
18526
+ responseFormat: params.responseFormat,
18182
18527
  checkpointer: getCheckpointSaver("default"),
18183
18528
  skills: params.skillCategories,
18184
18529
  backend: filesystemBackend,
@@ -18410,6 +18755,100 @@ function extractLastHumanMessage(messages) {
18410
18755
  return "";
18411
18756
  }
18412
18757
 
18758
+ // src/agent_lattice/builders/WorkflowAgentGraphBuilder.ts
18759
+ import { createAgent as createAgent7 } from "langchain";
18760
+ import { isWorkflowAgentConfig } from "@axiom-lattice/protocols";
18761
+ var DEFAULT_AGENT_PROMPT = "Complete the task accurately and concisely. Follow the instructions in the user's message.";
18762
+ var WorkflowAgentGraphBuilder = class {
18763
+ async build(agentLattice, params) {
18764
+ if (!isWorkflowAgentConfig(agentLattice.config)) {
18765
+ throw new Error(
18766
+ `WorkflowAgentGraphBuilder received wrong agent type: ${agentLattice.config.type}`
18767
+ );
18768
+ }
18769
+ const config = agentLattice.config;
18770
+ const yaml = config.workflowYaml;
18771
+ const tenantId = agentLattice.config.tenantId ?? "default";
18772
+ const checkpointer = getCheckpointSaver("default");
18773
+ const tools = params.tools.map((t) => t.executor).filter(Boolean);
18774
+ const middlewareConfigs = params.middleware || [];
18775
+ const middlewares = await createCommonMiddlewares(middlewareConfigs, void 0, false);
18776
+ const askMiddlewares = await createCommonMiddlewares([
18777
+ {
18778
+ id: "ask_user_to_clarify",
18779
+ type: "ask_user_to_clarify",
18780
+ name: "Ask User Clarify",
18781
+ description: "For workflow steps requiring user interaction",
18782
+ enabled: true,
18783
+ config: {}
18784
+ }
18785
+ ], void 0, false);
18786
+ const noWrapMiddlewares = middlewares.filter((m) => !m.wrapModelCall);
18787
+ const noWrapAskMiddlewares = askMiddlewares.filter((m) => !m.wrapModelCall);
18788
+ console.log(`[WF BUILDER] building default agent | toolCount=${tools.length} | middlewareCount=${middlewares.length}`);
18789
+ const defaultAgent = createAgent7({
18790
+ model: params.model,
18791
+ tools,
18792
+ systemPrompt: params.prompt || DEFAULT_AGENT_PROMPT,
18793
+ checkpointer,
18794
+ middleware: middlewares
18795
+ });
18796
+ console.log(`[WF BUILDER] default agent built`);
18797
+ const agentCache = /* @__PURE__ */ new Map();
18798
+ const resolveAgent = async (ref, responseFormat, stepType) => {
18799
+ if (ref) {
18800
+ console.log(`[WF BUILDER] resolveAgent: looking up ref="${ref}"`);
18801
+ return await getAgentClientAsync(tenantId, ref);
18802
+ }
18803
+ const isAsk = stepType === "ask";
18804
+ if (responseFormat) {
18805
+ const key = (isAsk ? "ask:" : "agent:") + JSON.stringify(responseFormat);
18806
+ console.log(`[WF BUILDER] resolveAgent: cacheKey=${key.slice(0, 80)}... | cached=${agentCache.has(key)}`);
18807
+ if (!agentCache.has(key)) {
18808
+ console.log(`[WF BUILDER] creating ${isAsk ? "ask" : "agent"} with responseFormat`);
18809
+ const agent = createAgent7({
18810
+ model: params.model,
18811
+ tools,
18812
+ systemPrompt: params.prompt || DEFAULT_AGENT_PROMPT,
18813
+ checkpointer,
18814
+ middleware: isAsk ? noWrapAskMiddlewares : noWrapMiddlewares,
18815
+ responseFormat
18816
+ });
18817
+ agentCache.set(key, agent);
18818
+ }
18819
+ return agentCache.get(key);
18820
+ }
18821
+ if (isAsk) {
18822
+ const key = "ask:default";
18823
+ if (!agentCache.has(key)) {
18824
+ console.log(`[WF BUILDER] creating ask default agent`);
18825
+ const agent = createAgent7({
18826
+ model: params.model,
18827
+ tools,
18828
+ systemPrompt: params.prompt || DEFAULT_AGENT_PROMPT,
18829
+ checkpointer,
18830
+ middleware: askMiddlewares
18831
+ });
18832
+ agentCache.set(key, agent);
18833
+ }
18834
+ return agentCache.get(key);
18835
+ }
18836
+ console.log(`[WF BUILDER] resolveAgent: using defaultAgent`);
18837
+ return defaultAgent;
18838
+ };
18839
+ let trackingStore;
18840
+ try {
18841
+ const storeLattice = getStoreLattice("default", "workflowTracking");
18842
+ trackingStore = storeLattice.store;
18843
+ console.log(`[WF BUILDER] trackingStore registered`);
18844
+ } catch {
18845
+ console.warn(`[WF BUILDER] no trackingStore registered`);
18846
+ }
18847
+ const graph = compileWorkflow(yaml, resolveAgent, checkpointer, trackingStore);
18848
+ return graph;
18849
+ }
18850
+ };
18851
+
18413
18852
  // src/agent_lattice/builders/AgentGraphBuilderFactory.ts
18414
18853
  var AgentGraphBuilderFactory = class _AgentGraphBuilderFactory {
18415
18854
  constructor() {
@@ -18434,6 +18873,7 @@ var AgentGraphBuilderFactory = class _AgentGraphBuilderFactory {
18434
18873
  this.builders.set(AgentType.TEAM, new TeamAgentGraphBuilder());
18435
18874
  this.builders.set(AgentType.PROCESSING, new ProcessingAgentGraphBuilder());
18436
18875
  this.builders.set(AgentType.A2A_REMOTE, new RemoteAgentGraphBuilder());
18876
+ this.builders.set(AgentType.WORKFLOW, new WorkflowAgentGraphBuilder());
18437
18877
  }
18438
18878
  /**
18439
18879
  * 注册自定义Builder
@@ -18526,6 +18966,7 @@ var AgentParamsBuilder = class {
18526
18966
  subAgents: [...subAgents, ...internalSubAgents],
18527
18967
  prompt: agentLattice.config.prompt,
18528
18968
  stateSchema: agentLattice.config.schema,
18969
+ responseFormat: agentLattice.config.responseFormat,
18529
18970
  skillCategories: skills,
18530
18971
  middleware: agentLattice.config.middleware,
18531
18972
  tenantId: agentLattice.config.tenantId
@@ -19108,8 +19549,65 @@ ${body}` : `${frontmatter}
19108
19549
  }
19109
19550
  };
19110
19551
 
19552
+ // src/store_lattice/InMemoryMenuStore.ts
19553
+ import { randomUUID as randomUUID3 } from "crypto";
19554
+ var InMemoryMenuStore = class {
19555
+ constructor() {
19556
+ this.items = /* @__PURE__ */ new Map();
19557
+ }
19558
+ async list(params) {
19559
+ const results = Array.from(this.items.values()).filter((item) => {
19560
+ if (item.tenantId !== params.tenantId) return false;
19561
+ if (params.menuTarget && item.menuTarget !== params.menuTarget) return false;
19562
+ if (!item.enabled) return false;
19563
+ return true;
19564
+ });
19565
+ results.sort((a, b) => a.sortOrder - b.sortOrder);
19566
+ return results;
19567
+ }
19568
+ async getById(id) {
19569
+ return this.items.get(id) || null;
19570
+ }
19571
+ async create(input) {
19572
+ const now = /* @__PURE__ */ new Date();
19573
+ const item = {
19574
+ id: randomUUID3(),
19575
+ tenantId: input.tenantId,
19576
+ menuTarget: input.menuTarget,
19577
+ group: input.group,
19578
+ name: input.name,
19579
+ icon: input.icon,
19580
+ sortOrder: input.sortOrder ?? 0,
19581
+ contentType: input.contentType,
19582
+ contentConfig: input.contentConfig,
19583
+ enabled: true,
19584
+ createdAt: now,
19585
+ updatedAt: now
19586
+ };
19587
+ this.items.set(item.id, item);
19588
+ return item;
19589
+ }
19590
+ async update(id, patch) {
19591
+ const existing = this.items.get(id);
19592
+ if (!existing) throw new Error(`MenuItem ${id} not found`);
19593
+ const updated = {
19594
+ ...existing,
19595
+ ...patch,
19596
+ updatedAt: /* @__PURE__ */ new Date()
19597
+ };
19598
+ this.items.set(id, updated);
19599
+ return updated;
19600
+ }
19601
+ async delete(id) {
19602
+ this.items.delete(id);
19603
+ }
19604
+ clear() {
19605
+ this.items.clear();
19606
+ }
19607
+ };
19608
+
19111
19609
  // src/agent_lattice/agentArchitectTools.ts
19112
- import z55 from "zod";
19610
+ import z56 from "zod";
19113
19611
  import { v4 as v43 } from "uuid";
19114
19612
  import { AgentType as AgentType3 } from "@axiom-lattice/protocols";
19115
19613
  function getTenantId(exeConfig) {
@@ -19139,7 +19637,7 @@ registerToolLattice(
19139
19637
  {
19140
19638
  name: "list_agents",
19141
19639
  description: "List all agents for the current workspace. Returns a summary with id, name, description, and type for each agent.",
19142
- schema: z55.object({})
19640
+ schema: z56.object({})
19143
19641
  },
19144
19642
  async (_input, exeConfig) => {
19145
19643
  try {
@@ -19166,8 +19664,8 @@ registerToolLattice(
19166
19664
  {
19167
19665
  name: "get_agent",
19168
19666
  description: "Get the full configuration of a specific agent by its ID. Returns the complete AgentConfig including prompt, middleware, tools, and sub-agents.",
19169
- schema: z55.object({
19170
- id: z55.string().describe("The agent ID to retrieve")
19667
+ schema: z56.object({
19668
+ id: z56.string().describe("The agent ID to retrieve")
19171
19669
  })
19172
19670
  },
19173
19671
  async (input, exeConfig) => {
@@ -19184,24 +19682,24 @@ registerToolLattice(
19184
19682
  }
19185
19683
  }
19186
19684
  );
19187
- var middlewareConfigSchema = z55.object({
19188
- id: z55.string(),
19189
- type: z55.string(),
19190
- name: z55.string(),
19191
- description: z55.string(),
19192
- enabled: z55.boolean(),
19193
- config: z55.record(z55.any()).optional()
19685
+ var middlewareConfigSchema = z56.object({
19686
+ id: z56.string(),
19687
+ type: z56.string(),
19688
+ name: z56.string(),
19689
+ description: z56.string(),
19690
+ enabled: z56.boolean(),
19691
+ config: z56.record(z56.any()).optional()
19194
19692
  });
19195
- var createAgentSchema = z55.object({
19196
- name: z55.string().describe("Human-friendly display name for the agent. The machine ID (used in other tools) is auto-generated as a slug from this name (e.g. 'My Cool Agent' \u2192 'my-cool-agent')."),
19197
- description: z55.string().optional().describe("Short description"),
19198
- type: z55.enum(["react", "deep_agent"]).describe("Agent type. Use 'react' for simple single-responsibility agents, 'deep_agent' for complex open-ended agents. For PROCESSING agents (workflow orchestration), use create_processing_agent instead."),
19199
- prompt: z55.string().describe("System prompt for the agent"),
19200
- tools: z55.array(z55.string()).optional().describe("Tool keys (strings) to assign. Call list_tools first to see available keys. Each element is a plain string like 'sap_api_search'. IMPORTANT: tools is a FLAT string array of tool names. Do NOT put middleware-like objects here \u2014 middleware goes in the separate 'middleware' field."),
19201
- middleware: z55.array(middlewareConfigSchema).optional().describe("Middleware configuration objects. Each has {id, type, name, description, enabled, config}. IMPORTANT: middleware objects are NOT tools. Do NOT put tool keys (strings) here \u2014 tool names go in the separate 'tools' array. For user approval/confirmation scenarios, use type: 'ask_user_to_clarify' with config: {}."),
19202
- subAgents: z55.array(z55.string()).optional().describe("Sub-agent IDs (deep_agent only)"),
19203
- internalSubAgents: z55.array(z55.any()).optional().describe("Inline sub-agent configs (deep_agent only)"),
19204
- modelKey: z55.string().optional().describe("Model key to use")
19693
+ var createAgentSchema = z56.object({
19694
+ name: z56.string().describe("Human-friendly display name for the agent. The machine ID (used in other tools) is auto-generated as a slug from this name (e.g. 'My Cool Agent' \u2192 'my-cool-agent')."),
19695
+ description: z56.string().optional().describe("Short description"),
19696
+ type: z56.enum(["react", "deep_agent"]).describe("Agent type. Use 'react' for simple single-responsibility agents, 'deep_agent' for complex open-ended agents. For PROCESSING agents (workflow orchestration), use create_processing_agent instead."),
19697
+ prompt: z56.string().describe("System prompt for the agent"),
19698
+ tools: z56.array(z56.string()).optional().describe("Tool keys (strings) to assign. Call list_tools first to see available keys. Each element is a plain string like 'sap_api_search'. IMPORTANT: tools is a FLAT string array of tool names. Do NOT put middleware-like objects here \u2014 middleware goes in the separate 'middleware' field."),
19699
+ middleware: z56.array(middlewareConfigSchema).optional().describe("Middleware configuration objects. Each has {id, type, name, description, enabled, config}. IMPORTANT: middleware objects are NOT tools. Do NOT put tool keys (strings) here \u2014 tool names go in the separate 'tools' array. For user approval/confirmation scenarios, use type: 'ask_user_to_clarify' with config: {}."),
19700
+ subAgents: z56.array(z56.string()).optional().describe("Sub-agent IDs (deep_agent only)"),
19701
+ internalSubAgents: z56.array(z56.any()).optional().describe("Inline sub-agent configs (deep_agent only)"),
19702
+ modelKey: z56.string().optional().describe("Model key to use")
19205
19703
  });
19206
19704
  registerToolLattice(
19207
19705
  "create_agent",
@@ -19239,21 +19737,21 @@ registerToolLattice(
19239
19737
  }
19240
19738
  }
19241
19739
  );
19242
- var topologyEdgeSchema = z55.object({
19243
- from: z55.string().describe("Source agent ID. For the first edge, this is the orchestrator (use the orchestrator's name as a placeholder \u2014 the tool will replace it with the actual ID). For subsequent chained edges, this is the previous stage's sub-agent ID."),
19244
- to: z55.string().describe("Target agent ID (the sub-agent to delegate to)"),
19245
- purpose: z55.string().describe("Business purpose of this delegation step \u2014 what the sub-agent should accomplish")
19740
+ var topologyEdgeSchema = z56.object({
19741
+ from: z56.string().describe("Source agent ID. For the first edge, this is the orchestrator (use the orchestrator's name as a placeholder \u2014 the tool will replace it with the actual ID). For subsequent chained edges, this is the previous stage's sub-agent ID."),
19742
+ to: z56.string().describe("Target agent ID (the sub-agent to delegate to)"),
19743
+ purpose: z56.string().describe("Business purpose of this delegation step \u2014 what the sub-agent should accomplish")
19246
19744
  });
19247
- var createProcessingAgentSchema = z55.object({
19248
- name: z55.string().describe("Display name for the processing agent"),
19249
- description: z55.string().optional().describe("Short description"),
19250
- prompt: z55.string().describe("System prompt for the orchestrator. Should describe how to route tasks through the topology."),
19251
- edges: z55.array(topologyEdgeSchema).min(1).describe("Topology edges defining the workflow. Each edge describes a delegation step with its business purpose. The orchestrator will follow this topology to delegate tasks to sub-agents."),
19252
- tools: z55.array(z55.string()).optional().describe("Tool keys (strings) to assign to the orchestrator. Call list_tools first to see available keys. Each element is a plain string like 'sap_api_search'. IMPORTANT: tools is a FLAT string array. Do NOT put middleware-like objects here \u2014 middleware goes in the separate 'middleware' field."),
19253
- subAgents: z55.array(z55.string()).describe("IDs of sub-agents that form the workflow pipeline. These must be created first via create_agent."),
19254
- internalSubAgents: z55.array(z55.any()).optional().describe("Inline sub-agent configs (alternative to pre-created sub-agents)"),
19255
- middleware: z55.array(middlewareConfigSchema).optional().describe("Additional middleware config objects beyond the auto-managed topology middleware. Each has {id, type, name, description, enabled, config}. IMPORTANT: middleware objects are NOT tools. Do NOT put tool keys (strings) here. For user approval/confirmation scenarios, use type: 'ask_user_to_clarify' with config: {}."),
19256
- modelKey: z55.string().optional().describe("Model key to use")
19745
+ var createProcessingAgentSchema = z56.object({
19746
+ name: z56.string().describe("Display name for the processing agent"),
19747
+ description: z56.string().optional().describe("Short description"),
19748
+ prompt: z56.string().describe("System prompt for the orchestrator. Should describe how to route tasks through the topology."),
19749
+ edges: z56.array(topologyEdgeSchema).min(1).describe("Topology edges defining the workflow. Each edge describes a delegation step with its business purpose. The orchestrator will follow this topology to delegate tasks to sub-agents."),
19750
+ tools: z56.array(z56.string()).optional().describe("Tool keys (strings) to assign to the orchestrator. Call list_tools first to see available keys. Each element is a plain string like 'sap_api_search'. IMPORTANT: tools is a FLAT string array. Do NOT put middleware-like objects here \u2014 middleware goes in the separate 'middleware' field."),
19751
+ subAgents: z56.array(z56.string()).describe("IDs of sub-agents that form the workflow pipeline. These must be created first via create_agent."),
19752
+ internalSubAgents: z56.array(z56.any()).optional().describe("Inline sub-agent configs (alternative to pre-created sub-agents)"),
19753
+ middleware: z56.array(middlewareConfigSchema).optional().describe("Additional middleware config objects beyond the auto-managed topology middleware. Each has {id, type, name, description, enabled, config}. IMPORTANT: middleware objects are NOT tools. Do NOT put tool keys (strings) here. For user approval/confirmation scenarios, use type: 'ask_user_to_clarify' with config: {}."),
19754
+ modelKey: z56.string().optional().describe("Model key to use")
19257
19755
  }).refine(
19258
19756
  (data) => {
19259
19757
  const edgeTargets = new Set(data.edges.map((e) => e.to));
@@ -19335,16 +19833,177 @@ registerToolLattice(
19335
19833
  }
19336
19834
  }
19337
19835
  );
19338
- var updateProcessingAgentSchema = z55.object({
19339
- id: z55.string().describe("The PROCESSING agent ID to update"),
19340
- name: z55.string().optional().describe("New display name for the orchestrator"),
19341
- description: z55.string().optional().describe("New short description"),
19342
- prompt: z55.string().optional().describe("New system prompt for the orchestrator"),
19343
- edges: z55.array(topologyEdgeSchema).min(1).optional().describe("New topology edges. First edge's from must reference the orchestrator by name (the tool replaces it). Subsequent edges chain from previous sub-agent IDs."),
19344
- tools: z55.array(z55.string()).optional().describe("Tool keys (strings) to assign to the orchestrator. Each element is a plain string like 'sap_api_search'. IMPORTANT: tools is a FLAT string array \u2014 do NOT put middleware-like objects here."),
19345
- subAgents: z55.array(z55.string()).optional().describe("New IDs of sub-agents in the workflow pipeline"),
19346
- middleware: z55.array(middlewareConfigSchema).optional().describe("Additional middleware config objects (topology middleware is auto-managed, do not include it). Each has {id, type, name, description, enabled, config}. IMPORTANT: middleware objects are NOT tools. Do NOT put tool keys (strings) here. For user approval/confirmation scenarios, use type: 'ask_user_to_clarify' with config: {}."),
19347
- modelKey: z55.string().optional().describe("New model key")
19836
+ var createWorkflowSchema = z56.object({
19837
+ name: z56.string().describe("Display name for the workflow agent"),
19838
+ description: z56.string().optional().describe("Short description"),
19839
+ skillLoaded: z56.literal(true).describe("MUST be true. Set after loading the 'create-workflow' skill."),
19840
+ yaml: z56.string().describe("The YAML workflow definition in linear DSL format (steps execute top-to-bottom, use parallel: for concurrency)"),
19841
+ tools: z56.array(z56.string()).optional().describe("Tool keys for the workflow agent"),
19842
+ middleware: z56.array(middlewareConfigSchema).optional().describe("Middleware configs"),
19843
+ modelKey: z56.string().optional().describe("Model key")
19844
+ });
19845
+ registerToolLattice(
19846
+ "create_workflow",
19847
+ {
19848
+ name: "create_workflow",
19849
+ description: "Create a WORKFLOW agent from YAML DSL. Load the 'create-workflow' skill first. Linear model \u2014 steps execute top-to-bottom. Use parallel: for concurrency. Data flows via {{label}} automatically. Business logic stays in agent prompts.",
19850
+ schema: createWorkflowSchema
19851
+ },
19852
+ async (input, exeConfig) => {
19853
+ try {
19854
+ const tenantId = getTenantId(exeConfig);
19855
+ const store = getAssistStore();
19856
+ const id = await generateAgentId(tenantId, input.name);
19857
+ try {
19858
+ const { compileWorkflow: compileWorkflow2 } = await import("./compile-4RFYHUBE.mjs");
19859
+ const { getCheckpointSaver: getCheckpointSaver2 } = await import("./memory_lattice-E66HTTVV.mjs");
19860
+ await compileWorkflow2(input.yaml, async () => ({ invoke: async () => ({}) }), getCheckpointSaver2("default"));
19861
+ } catch (e) {
19862
+ return JSON.stringify({ error: `DSL validation failed: ${e.message}` });
19863
+ }
19864
+ const config = {
19865
+ key: id,
19866
+ name: input.name,
19867
+ description: input.description || "",
19868
+ type: AgentType3.WORKFLOW,
19869
+ prompt: input.description || `Workflow: ${input.name}`,
19870
+ workflowYaml: input.yaml,
19871
+ ...input.tools && input.tools.length > 0 ? { tools: input.tools } : {},
19872
+ ...input.middleware && input.middleware.length > 0 ? { middleware: input.middleware } : {},
19873
+ ...input.modelKey ? { modelKey: input.modelKey } : {}
19874
+ };
19875
+ await store.createAssistant(tenantId, id, {
19876
+ name: input.name,
19877
+ description: input.description,
19878
+ graphDefinition: config
19879
+ });
19880
+ eventBus.publish("assistant:created", { id, name: input.name, tenantId });
19881
+ return JSON.stringify({ id, name: input.name, type: "workflow" });
19882
+ } catch (error) {
19883
+ return JSON.stringify({ error: `Failed to create workflow: ${error.message}` });
19884
+ }
19885
+ }
19886
+ );
19887
+ registerToolLattice(
19888
+ "validate_workflow",
19889
+ {
19890
+ name: "validate_workflow",
19891
+ description: "Validate a workflow agent's DSL for correctness by compiling it.",
19892
+ schema: z56.object({
19893
+ id: z56.string().describe("The workflow agent ID to validate")
19894
+ })
19895
+ },
19896
+ async (input, exeConfig) => {
19897
+ try {
19898
+ const tenantId = getTenantId(exeConfig);
19899
+ const store = getAssistStore();
19900
+ const agent = await store.getAssistantById(tenantId, input.id);
19901
+ if (!agent) {
19902
+ return JSON.stringify({ error: `Agent '${input.id}' not found` });
19903
+ }
19904
+ const graphDef = agent.graphDefinition;
19905
+ if (!graphDef || graphDef.type !== AgentType3.WORKFLOW) {
19906
+ return JSON.stringify({ error: `Agent '${input.id}' is not a workflow agent` });
19907
+ }
19908
+ const yaml = graphDef.workflowYaml;
19909
+ if (!yaml) {
19910
+ return JSON.stringify({ error: `Agent '${input.id}' has no workflow DSL` });
19911
+ }
19912
+ try {
19913
+ const { compileWorkflow: compileWorkflow2 } = await import("./compile-4RFYHUBE.mjs");
19914
+ const { getCheckpointSaver: getCheckpointSaver2 } = await import("./memory_lattice-E66HTTVV.mjs");
19915
+ await compileWorkflow2(yaml, async () => ({ invoke: async () => ({}) }), getCheckpointSaver2("default"));
19916
+ } catch (e) {
19917
+ return JSON.stringify({
19918
+ agentId: input.id,
19919
+ valid: false,
19920
+ issues: [{ type: "error", message: e.message }]
19921
+ });
19922
+ }
19923
+ return JSON.stringify({ agentId: input.id, valid: true, issues: [] });
19924
+ } catch (error) {
19925
+ return JSON.stringify({ error: `Failed to validate workflow: ${error.message}` });
19926
+ }
19927
+ }
19928
+ );
19929
+ var updateWorkflowSchema = z56.object({
19930
+ id: z56.string().describe("The workflow agent ID to update"),
19931
+ name: z56.string().optional().describe("New display name"),
19932
+ description: z56.string().optional().describe("New description"),
19933
+ yaml: z56.string().optional().describe("Replacement YAML workflow DSL. Omit to keep existing."),
19934
+ tools: z56.array(z56.string()).optional().describe("Replacement tool keys"),
19935
+ middleware: z56.array(middlewareConfigSchema).optional().describe("Replacement middleware configs"),
19936
+ modelKey: z56.string().optional().describe("Replacement model key")
19937
+ });
19938
+ registerToolLattice(
19939
+ "update_workflow",
19940
+ {
19941
+ name: "update_workflow",
19942
+ description: "Update an existing workflow agent. Provide the agent ID and only the fields to change. Pass yaml string to replace the DSL, or omit to keep it.",
19943
+ schema: updateWorkflowSchema
19944
+ },
19945
+ async (input, exeConfig) => {
19946
+ console.log(`[update_workflow] CALLED id=${input.id} hasYaml=${input.yaml !== void 0}`);
19947
+ try {
19948
+ const tenantId = getTenantId(exeConfig);
19949
+ const store = getAssistStore();
19950
+ const existing = await store.getAssistantById(tenantId, input.id);
19951
+ if (!existing) {
19952
+ console.log(`[update_workflow] ERROR: agent not found: ${input.id}`);
19953
+ return JSON.stringify({ error: `Agent '${input.id}' not found` });
19954
+ }
19955
+ const existingConfig = existing.graphDefinition || {};
19956
+ if (existingConfig.type !== AgentType3.WORKFLOW) {
19957
+ console.log(`[update_workflow] ERROR: not a workflow agent: ${input.id}`);
19958
+ return JSON.stringify({ error: `Agent '${input.id}' is not a workflow agent` });
19959
+ }
19960
+ const mergedConfig = { ...existingConfig };
19961
+ if (input.name !== void 0) mergedConfig.name = input.name;
19962
+ if (input.description !== void 0) mergedConfig.description = input.description;
19963
+ if (input.yaml !== void 0) mergedConfig.workflowYaml = input.yaml;
19964
+ if (input.tools !== void 0) mergedConfig.tools = input.tools;
19965
+ if (input.middleware !== void 0) mergedConfig.middleware = input.middleware;
19966
+ if (input.modelKey !== void 0) mergedConfig.modelKey = input.modelKey;
19967
+ if (input.yaml !== void 0) {
19968
+ console.log(`[update_workflow] validating DSL: ${input.id}`);
19969
+ try {
19970
+ const { compileWorkflow: compileWorkflow2 } = await import("./compile-4RFYHUBE.mjs");
19971
+ const { getCheckpointSaver: getCheckpointSaver2 } = await import("./memory_lattice-E66HTTVV.mjs");
19972
+ await compileWorkflow2(input.yaml, async () => ({ invoke: async () => ({}) }), getCheckpointSaver2("default"));
19973
+ console.log(`[update_workflow] DSL validation passed: ${input.id}`);
19974
+ } catch (e) {
19975
+ console.log(`[update_workflow] DSL validation FAILED: ${input.id} - ${e.message}`);
19976
+ return JSON.stringify({
19977
+ error: `DSL validation failed: ${e.message}`,
19978
+ issues: [{ type: "error", message: e.message }]
19979
+ });
19980
+ }
19981
+ }
19982
+ const newName = input.name || existing.name;
19983
+ await store.updateAssistant(tenantId, input.id, {
19984
+ name: newName,
19985
+ description: input.description !== void 0 ? input.description : existing.description,
19986
+ graphDefinition: mergedConfig
19987
+ });
19988
+ eventBus.publish("assistant:updated", { id: input.id, name: newName, tenantId });
19989
+ console.log(`[update_workflow] SUCCESS: id=${input.id} name=${newName}`);
19990
+ return JSON.stringify({ id: input.id, name: newName, type: "workflow" });
19991
+ } catch (error) {
19992
+ console.log(`[update_workflow] EXCEPTION: ${error.message}`);
19993
+ return JSON.stringify({ error: `Failed to update workflow: ${error.message}` });
19994
+ }
19995
+ }
19996
+ );
19997
+ var updateProcessingAgentSchema = z56.object({
19998
+ id: z56.string().describe("The PROCESSING agent ID to update"),
19999
+ name: z56.string().optional().describe("New display name for the orchestrator"),
20000
+ description: z56.string().optional().describe("New short description"),
20001
+ prompt: z56.string().optional().describe("New system prompt for the orchestrator"),
20002
+ edges: z56.array(topologyEdgeSchema).min(1).optional().describe("New topology edges. First edge's from must reference the orchestrator by name (the tool replaces it). Subsequent edges chain from previous sub-agent IDs."),
20003
+ tools: z56.array(z56.string()).optional().describe("Tool keys (strings) to assign to the orchestrator. Each element is a plain string like 'sap_api_search'. IMPORTANT: tools is a FLAT string array \u2014 do NOT put middleware-like objects here."),
20004
+ subAgents: z56.array(z56.string()).optional().describe("New IDs of sub-agents in the workflow pipeline"),
20005
+ middleware: z56.array(middlewareConfigSchema).optional().describe("Additional middleware config objects (topology middleware is auto-managed, do not include it). Each has {id, type, name, description, enabled, config}. IMPORTANT: middleware objects are NOT tools. Do NOT put tool keys (strings) here. For user approval/confirmation scenarios, use type: 'ask_user_to_clarify' with config: {}."),
20006
+ modelKey: z56.string().optional().describe("New model key")
19348
20007
  }).refine(
19349
20008
  (data) => {
19350
20009
  if (!data.edges) return true;
@@ -19472,18 +20131,18 @@ registerToolLattice(
19472
20131
  }
19473
20132
  }
19474
20133
  );
19475
- var updateAgentSchema = z55.object({
19476
- id: z55.string().describe("The agent ID to update"),
19477
- config: z55.object({
19478
- name: z55.string().optional().describe("New display name for the agent"),
19479
- description: z55.string().optional().describe("New short description"),
19480
- type: z55.enum(["react", "deep_agent"]).optional().describe("Agent type"),
19481
- prompt: z55.string().optional().describe("New system prompt for the agent"),
19482
- tools: z55.array(z55.string()).optional().describe("Tool keys to assign to this agent. These are registered tool names (strings), NOT middleware objects."),
19483
- middleware: z55.array(middlewareConfigSchema).optional().describe("Middleware configurations. NOTE: middleware objects have type/name/description/enabled/config fields and are NOT the same as tools. Tool keys go in the 'tools' array. For user approval/confirmation scenarios, use type: 'ask_user_to_clarify' with config: {}."),
19484
- subAgents: z55.array(z55.string()).optional().describe("Sub-agent IDs (deep_agent only)"),
19485
- internalSubAgents: z55.array(z55.any()).optional().describe("Inline sub-agent configs (deep_agent only)"),
19486
- modelKey: z55.string().optional().describe("Model key to use")
20134
+ var updateAgentSchema = z56.object({
20135
+ id: z56.string().describe("The agent ID to update"),
20136
+ config: z56.object({
20137
+ name: z56.string().optional().describe("New display name for the agent"),
20138
+ description: z56.string().optional().describe("New short description"),
20139
+ type: z56.enum(["react", "deep_agent"]).optional().describe("Agent type"),
20140
+ prompt: z56.string().optional().describe("New system prompt for the agent"),
20141
+ tools: z56.array(z56.string()).optional().describe("Tool keys to assign to this agent. These are registered tool names (strings), NOT middleware objects."),
20142
+ middleware: z56.array(middlewareConfigSchema).optional().describe("Middleware configurations. NOTE: middleware objects have type/name/description/enabled/config fields and are NOT the same as tools. Tool keys go in the 'tools' array. For user approval/confirmation scenarios, use type: 'ask_user_to_clarify' with config: {}."),
20143
+ subAgents: z56.array(z56.string()).optional().describe("Sub-agent IDs (deep_agent only)"),
20144
+ internalSubAgents: z56.array(z56.any()).optional().describe("Inline sub-agent configs (deep_agent only)"),
20145
+ modelKey: z56.string().optional().describe("Model key to use")
19487
20146
  }).describe("Configuration fields to update. Only include the fields you want to change.")
19488
20147
  });
19489
20148
  registerToolLattice(
@@ -19521,8 +20180,8 @@ registerToolLattice(
19521
20180
  {
19522
20181
  name: "delete_agent",
19523
20182
  description: "Permanently delete an agent by its ID. This action cannot be undone.",
19524
- schema: z55.object({
19525
- id: z55.string().describe("The agent ID to delete")
20183
+ schema: z56.object({
20184
+ id: z56.string().describe("The agent ID to delete")
19526
20185
  })
19527
20186
  },
19528
20187
  async (input, exeConfig) => {
@@ -19548,7 +20207,7 @@ registerToolLattice(
19548
20207
  {
19549
20208
  name: "list_tools",
19550
20209
  description: "List all available tools that can be assigned to agents. Returns each tool's name (use this string value in the 'tools' array), description, and whether it requires user approval. The tool names from this list are what you pass as strings in the 'tools' field of create_agent or update_agent.",
19551
- schema: z55.object({})
20210
+ schema: z56.object({})
19552
20211
  },
19553
20212
  async (_input, _exeConfig) => {
19554
20213
  try {
@@ -19570,9 +20229,9 @@ registerToolLattice(
19570
20229
  {
19571
20230
  name: "invoke_agent",
19572
20231
  description: "Invoke an agent with a test message and return its response. Use this to verify an agent works correctly after creating or modifying it. The agent must be compiled (already created and valid).",
19573
- schema: z55.object({
19574
- id: z55.string().describe("The agent ID to invoke"),
19575
- message: z55.string().describe("The test message to send to the agent")
20232
+ schema: z56.object({
20233
+ id: z56.string().describe("The agent ID to invoke"),
20234
+ message: z56.string().describe("The test message to send to the agent")
19576
20235
  })
19577
20236
  },
19578
20237
  async (input, exeConfig) => {
@@ -19590,18 +20249,10 @@ registerToolLattice(
19590
20249
  assistant_id: id,
19591
20250
  thread_id: threadId
19592
20251
  });
19593
- const result = await agent.invoke({ input: { message } });
19594
- const messages = result?.messages || [];
19595
- const lastAi = [...messages].reverse().find(
19596
- (m) => m.role === "ai" || m.type === "ai"
19597
- );
19598
- const content = lastAi?.content ?? "(no response)";
19599
- return JSON.stringify({
19600
- agentId: id,
19601
- threadId,
19602
- response: typeof content === "string" ? content : JSON.stringify(content)
19603
- });
20252
+ const result = await agent.invokeWithState({ input: { message } });
20253
+ return JSON.stringify({ agentId: id, threadId, result });
19604
20254
  } catch (error) {
20255
+ console.error(`[invoke_agent] FAILED for agent="${input.id}":`, error.stack || error.message);
19605
20256
  return JSON.stringify({ error: `Failed to invoke agent: ${error.message}` });
19606
20257
  }
19607
20258
  }
@@ -19625,12 +20276,12 @@ Every agent interaction follows this cycle. You MUST NOT skip any phase:
19625
20276
  |-------|-------------|-------------------|
19626
20277
  | **1. DESIGN** | Understand requirements, choose agent type, design config (prompt, middleware, sub-agents), create topology/architecture diagram | Present the design clearly. Use \`show_widget\` for visual diagrams. |
19627
20278
  | **2. CONFIRM** | User reviews and approves the design | **MUST explicitly ask for approval.** Say: "Does this design look good? Shall I create it?" NEVER create or update anything without clear user confirmation. |
19628
- | **3. BUILD** | Call \`create_agent\`, \`create_processing_agent\`, or \`update_agent\` | Only after confirmation. Report the result (ID, name). |
20279
+ | **3. BUILD** | Call \`create_agent\`, \`create_workflow\`, or \`update_agent\` / \`update_workflow\` | Only after confirmation. Report the result (ID, name). |
19629
20280
  | **4. TEST** | Verify the agent works correctly | You may ask the user if they want you to test. If yes, delegate to the **Agent Reviewer** sub-agent. Do NOT test until the user confirms. |
19630
20281
 
19631
20282
  **CRITICAL RULES:**
19632
20283
  - **NEVER build before confirming.** Design \u2192 ask \u2192 wait for "yes" \u2192 only then build.
19633
- - **Edit, don't re-create.** After an agent exists, modifying it ALWAYS means \`update_agent\` or \`update_processing_agent\` \u2014 NEVER \`create_agent\` or \`create_processing_agent\` again. If you just created an agent and the user wants to change something, use the update tool for that agent.
20284
+ - **Edit, don't re-create.** After an agent exists, modifying it ALWAYS means \`update_agent\` or \`update_workflow\` \u2014 NEVER \`create_agent\` or \`create_workflow\` again. If you just created an agent and the user wants to change something, use the update tool for that agent.
19634
20285
  - **NEVER test proactively.** You may ask if the user wants to test \u2014 but do NOT invoke the Reviewer until they say yes. Never test yourself.
19635
20286
  - **One decision at a time.** Each message asks exactly one question.
19636
20287
 
@@ -19641,7 +20292,7 @@ Once an agent is created, NEVER create another agent for the same purpose. If th
19641
20292
  | User wants to... | Use |
19642
20293
  |-----------------|-----|
19643
20294
  | Change prompt, tools, middleware, name | \`update_agent\` |
19644
- | Change topology, edges, sub-agents | \`update_processing_agent\` |
20295
+ | Change workflow DSL, tools, middleware | \`update_workflow\` |
19645
20296
  | See current config | \`get_agent\` |
19646
20297
 
19647
20298
  If the user's intent is unclear after creation, ask: "Edit this agent or create a new one?"
@@ -19653,8 +20304,9 @@ You have nine tools for agent management:
19653
20304
  - **list_tools** \u2014 See all available tools that can be assigned to agents
19654
20305
  - **get_agent** \u2014 View the full configuration of a specific agent
19655
20306
  - **create_agent** \u2014 Create a REACT or DEEP_AGENT agent
19656
- - **create_processing_agent** \u2014 Create a PROCESSING agent with business-defined workflow topology
19657
- - **update_processing_agent** \u2014 Modify a PROCESSING agent's topology edges, name, prompt, or sub-agents
20307
+ - **create_workflow** \u2014 Create a WORKFLOW agent from a concise DSL (load create-workflow skill first)
20308
+ - **validate_workflow** \u2014 Validate a workflow agent's DSL
20309
+ - **update_workflow** \u2014 Update a workflow agent's DSL or config
19658
20310
  - **update_agent** \u2014 Modify an existing REACT or DEEP_AGENT agent's configuration
19659
20311
  - **delete_agent** \u2014 Remove an agent permanently
19660
20312
  - **manage_binding** \u2014 Bind a sender (email, Lark, Slack user) to an agent so external messages are routed to it
@@ -19692,7 +20344,7 @@ Let the \`show_widget\` tool handle rendering details \u2014 it has its own guid
19692
20344
  | Type | Best for | Execution Model |
19693
20345
  |------|----------|----------------|
19694
20346
  | **react** | Simple, single-responsibility tasks | Classic ReAct loop (think \u2192 act \u2192 observe) |
19695
- | **processing** | Standard BPO workflows, preset process orchestration | Topology-driven: predefined agent topology with reliable multi-agent coordination |
20347
+ | **workflow** | Deterministic multi-step pipelines with branching, parallel, and human-in-the-loop | YAML linear DSL compiled into LangGraph state machine |
19696
20348
  | **deep_agent** | Complex, open-ended tasks requiring dynamic decomposition | Self-generating dynamic todos: agent analyzes the task and creates its own execution plan at runtime |
19697
20349
 
19698
20350
  When a user is unsure which type to choose, use \`show_widget\` to render a visual comparison \u2014 show each type's execution model side-by-side as an interactive diagram so the user can intuitively understand the differences.
@@ -19730,233 +20382,64 @@ You may ask: "Want me to send this to the Agent Reviewer for testing?" If yes, d
19730
20382
 
19731
20383
  ---
19732
20384
 
19733
- ## Workflow B: Workflow Agent (PROCESSING type)
20385
+ ## Workflow B: Processing Agent (PROCESSING type) [DEPRECATED]
19734
20386
 
19735
- Use this when the task follows a standard BPO (Business Process Orchestration) pattern \u2014 a predefined topology of sub-agents working through a preset pipeline.
20387
+ The PROCESSING agent type is deprecated. Use the WORKFLOW DSL type (Workflow D below) instead. If a user asks for a multi-step pipeline, guide them toward the WORKFLOW DSL approach.
19736
20388
 
19737
- ### Phase 1: Design
19738
-
19739
- **Step 1: Process analysis.** Ask: What is the end-to-end process? Map the stages.
19740
-
19741
- **Business rule \u2014 Draft-then-confirm pattern:** When a workflow creates business objects that require human approval (e.g., draft orders in SAP B1, purchase requisitions, expense reports), the design MUST include a confirmation step AFTER the creation step. The create step must complete successfully before the confirm step runs. The flow is always: **Create draft \u2192 User confirms \u2192 Finalize**. Reason: systems like SAP B1 only expose drafts to users after they are created \u2014 the user cannot see or approve something that doesn't exist yet. The confirm step MUST use the \`ask_user_to_clarify\` middleware.
19742
-
19743
- **Business pattern \u2014 SAP B1 Draft SO Creation:** When designing a sub-agent responsible for creating draft Sales Orders in SAP B1, embed the following standards into its system prompt. These ensure consistent data construction, API usage, and user presentation:
19744
-
19745
- **Step 1: Construct SO Data Structure**
19746
- Build the JSON payload. For each DocumentLines item:
19747
- - Include \`WarehouseCode\` ONLY if sku.json provides a value; if missing or empty, OMIT the field entirely
19748
- - Generate \`Comments\` dynamically based on context (customer name, PO reference, special instructions)
19749
-
19750
- \`\`\`json
19751
- {
19752
- "DocObjectCode": "17",
19753
- "DocType": "dDocument_Items",
19754
- "CardCode": "C001",
19755
- "DocDate": "current date",
19756
- "DocDueDate": "delivery date",
19757
- "TaxDate": "current date",
19758
- "U_YWLX": "Modern Trade",
19759
- "Comments": "SO for Kaimay Retail - PO ref: PO-2024-001234",
19760
- "DocumentLines": [
19761
- {
19762
- "ItemCode": "SKU001",
19763
- "Quantity": 240,
19764
- "UnitPrice": 15.84
19765
- }
19766
- ]
19767
- }
19768
- \`\`\`
20389
+ ---
19769
20390
 
19770
- Field mapping rules:
19771
- | SAP Field | Data Source |
19772
- |-----------|-------------|
19773
- | CardCode | customer.json \u2192 CardCode |
19774
- | DocDate | Current date (yyyy-MM-dd) |
19775
- | DocDueDate | extracted.json \u2192 delivery_date |
19776
- | TaxDate | Current date (yyyy-MM-dd) |
19777
- | U_YWLX | customer.json \u2192 SalesType |
19778
- | ItemCode | sku.json \u2192 ItemCode |
19779
- | Quantity | extracted.json \u2192 Quantity |
19780
- | WarehouseCode | sku.json \u2192 WarehouseCode (OMIT if missing/empty) |
19781
- | UnitPrice | price.json \u2192 UnitPrice |
19782
- | Comments | AI-generated based on customer name, PO reference, and context |
19783
-
19784
- **Step 2: Call SAP API to Create Draft (MUST EXECUTE)**
19785
- Use the \`sap_api_call\` tool with EXACTLY these parameters:
19786
- - **Method**: POST
19787
- - **Endpoint**: \`Drafts\` (ONLY allowed endpoint; do NOT call SalesOrders or any other endpoint)
19788
- - **Body**: The JSON constructed in Step 1
19789
-
19790
- CRITICAL: You MUST call sap_api_call BEFORE proceeding to Step 3. This step is NOT optional.
19791
-
19792
- If the API call fails:
19793
- - Log the error details
19794
- - STOP the process
19795
- - Report the failure to the user with the error message
19796
- - Do NOT proceed to Step 3
19797
-
19798
- **Step 3: Present Draft for User Review (MUST EXECUTE AFTER Step 2)**
19799
- ONLY after the SAP API call in Step 2 succeeds, use the \`ask_user_to_clarify\` tool to present the complete SO summary.
19800
-
19801
- Message format (STRICT \u2014 no emoji, no summary, field names match Service Layer):
19802
-
19803
- === Sales Order Draft ===
19804
-
19805
- DocEntry: {DocEntry}
19806
- DocNum: {DocNum}
19807
- DocDate: {DocDate}
19808
- DocDueDate: {DocDueDate}
19809
- CardCode: {CardCode}
19810
- CardName: {CardName}
19811
- U_YWLX: {SalesType}
19812
- Comments: {Comments}
19813
-
19814
- DocumentLines:
19815
- LineNum | ItemCode | Quantity | WarehouseCode | UnitPrice | LineTotal
19816
- 0 | {ItemCode} | {Quantity} | {WarehouseCode} | {UnitPrice} | {LineTotal}
19817
- 1 | {ItemCode} | {Quantity} | {WarehouseCode} | {UnitPrice} | {LineTotal}
19818
- ...
19819
-
19820
- DocTotal: {DocTotal}
19821
-
19822
- Warnings:
19823
- - {warning1}
19824
- - {warning2}
19825
-
19826
- Options:
19827
- [Confirm generating draft]
19828
- [Cancel, do not generate]
19829
-
19830
- **Data sharing pattern \u2014 File-based handoff:** Every sub-agent in the pipeline MUST persist its work results as files under a shared project directory, never rely on in-memory data passing between steps. Deep agents have built-in file capabilities, so no middleware is needed.
19831
-
19832
- Rules:
19833
- 1. The **orchestrator** generates a unique project ID at the start (e.g., timestamp-based) and passes it to each sub-agent in the task context
19834
- 2. Each sub-agent reads input from \`/project/{project-id}/\` and writes output files into the same directory
19835
- 3. Establish clear file naming conventions so downstream steps know exactly which files to read (e.g., \`extracted.json\`, \`sku.json\`, \`customer.json\`, \`so_draft.json\`)
19836
- 4. The orchestrator's system prompt MUST specify for each edge: which files the target sub-agent should read and which files it should produce
19837
-
19838
- **Step 2: Topology design.** Design the agent topology and use \`show_widget\` to render an interactive diagram showing the flow: Orchestrator \u2192 Stage 1 \u2192 Stage 2 \u2192 ... \u2192 Output. Each edge should be labeled with its business purpose.
19839
-
19840
- **Step 3: Design each sub-agent** as a **deep_agent** type (one at a time). For each:
19841
- - Responsibility, system prompt, middleware, file input/output contract (which files from \`/project/{project-id}/\` it reads, which files it writes)
19842
- - Deep agents have built-in file capabilities (ls, read, write, edit, glob, grep), so do NOT add filesystem middleware.
19843
- - **Ask for confirmation before moving to the next sub-agent.**
19844
-
19845
- **Step 4: Design the orchestrator.** Responsibility, system prompt, topology edges, sub-agent list.
19846
-
19847
- **Step 5: Self-review checklist.** Before presenting to the user, verify:
19848
- - Completeness (every stage covered by an edge?)
19849
- - Purposes clear (each edge's business intent?)
19850
- - Order correct (serial chain logical?)
19851
- - Edge cases (invalid input, failure, timeout?)
19852
-
19853
- **Step 6: Write the workflow description (Spec).** After designing the topology and sub-agents, compose a comprehensive **\`description\`** for the orchestrator. This description serves as the workflow's specification \u2014 anyone reading it should understand exactly what this workflow does without needing to inspect individual sub-agent configs.
19854
-
19855
- The description MUST include ALL of the following:
19856
-
19857
- | Section | Content |
19858
- |---------|---------|
19859
- | **Overview** | One-sentence summary of the workflow's purpose and business value |
19860
- | **Steps** | Numbered list of each stage in the pipeline. For each step: which sub-agent handles it, what it does, what tools it uses, what files it reads from \`/project/{project-id}/\`, and what files it writes. |
19861
- | **Data Flow** | How data moves between steps via files under \`/project/{project-id}/\`. For each step: which files it reads as input and which files it writes as output. |
19862
- | **Logic & Conditions** | Any conditional branching, decision points, retry logic, or exception handling. When does the workflow take path A vs path B? What happens on failure? |
19863
- | **Tools Used** | Summary table or list of all tools used across sub-agents, grouped by sub-agent |
19864
- | **Expected Input** | What input does the workflow expect from the user? (format, examples) |
19865
- | **Expected Output** | What does the workflow produce at the end? (format, examples) |
19866
-
19867
- **Formatting rules:**
19868
- - Write in **English**
19869
- - Use **Markdown** for formatting (headings, lists, tables, code blocks)
19870
- - Be detailed but concise \u2014 each section should be 1-5 lines
19871
- - Avoid placeholder text like "TODO" or "TBD"
19872
-
19873
- **Example structure** (\u5B50 Agent \u5747\u4E3A deep_agent \u7C7B\u578B\uFF0C\u65E0\u9700 filesystem \u4E2D\u95F4\u4EF6):
19874
-
19875
- \`\`\`markdown
19876
- ## Overview
19877
- \u672C\u5DE5\u4F5C\u6D41\u81EA\u52A8\u4ECE\u591A\u4E2A\u6570\u636E\u6E90\u91C7\u96C6\u7ADE\u54C1\u4EF7\u683C\uFF0C\u751F\u6210\u5BF9\u6BD4\u5206\u6790\u62A5\u544A\u5E76\u63A8\u9001\u901A\u77E5\u3002
19878
-
19879
- ## Steps
19880
- 1. **\u6570\u636E\u91C7\u96C6 (data-collector)** \u2014 \u4F7F\u7528 browser \u5DE5\u5177\u722C\u53D6\u6307\u5B9AURL\u7684\u7ADE\u54C1\u4EF7\u683C\u6570\u636E\uFF0C\u8C03\u7528 metrics API \u62C9\u53D6\u5386\u53F2\u4EF7\u683C\u3002\u8F93\u51FA \u2192 \`raw_prices.json\`
19881
- 2. **\u6570\u636E\u6E05\u6D17 (data-cleaner)** \u2014 \u8BFB\u53D6 \`raw_prices.json\`\uFF0C\u4F7F\u7528 code_eval \u6267\u884C Python \u811A\u672C\u6E05\u6D17\u5F02\u5E38\u503C\u548C\u7F3A\u5931\u503C\uFF0C\u7EDF\u4E00\u8D27\u5E01\u5355\u4F4D\u3002\u8F93\u51FA \u2192 \`cleaned_prices.json\`
19882
- 3. **\u62A5\u544A\u751F\u6210 (report-generator)** \u2014 \u8BFB\u53D6 \`cleaned_prices.json\` \u548C\u6A21\u677F\u6587\u4EF6\uFF0Ccode_eval \u8BA1\u7B97\u6DA8\u8DCC\u5E45\u548C\u8D8B\u52BF\uFF0C\u751F\u6210 Markdown \u5BF9\u6BD4\u62A5\u544A\u3002\u8F93\u51FA \u2192 \`report.md\`
19883
- 4. **\u901A\u77E5\u63A8\u9001 (notifier)** \u2014 \u8BFB\u53D6 \`report.md\`\uFF0C\u8C03\u7528 scheduler \u5B89\u6392\u5B9A\u65F6\u53D1\u9001\uFF0C\u4F7F\u7528 ask_user_to_clarify \u8BF7\u6C42\u53D1\u9001\u786E\u8BA4\u3002\u8F93\u51FA\u53D1\u9001\u7ED3\u679C\u3002
19884
-
19885
- ## Data Flow
19886
- All data is shared via files under \`/project/{project-id}/\`:
19887
- \`\u7528\u6237\u8F93\u5165\` \u2192 data-collector writes \`raw_prices.json\` \u2192 data-cleaner reads \`raw_prices.json\`, writes \`cleaned_prices.json\` \u2192 report-generator reads \`cleaned_prices.json\`, writes \`report.md\` \u2192 notifier reads \`report.md\`, pushes
20391
+ ## Workflow C: Workflow DSL Agent (WORKFLOW type)
19888
20392
 
19889
- ## Logic & Conditions
19890
- - data-collector \u722C\u53D6\u5931\u8D25\u65F6\u91CD\u8BD5\u6700\u591A3\u6B21\uFF0C\u95F4\u969430\u79D2
19891
- - \u82E5\u67D0\u4E00\u5546\u54C1\u4EF7\u683C\u7F3A\u5931\u8D85\u8FC77\u5929\uFF0C\u6807\u8BB0\u4E3A\u300C\u6570\u636E\u4E0D\u5168\u300D\u5E76\u5728\u62A5\u544A\u4E2D\u9AD8\u4EAE
19892
- - report-generator \u8BA1\u7B97\u6DA8\u5E45\u8D85\u8FC720%\u65F6\u81EA\u52A8\u6807\u8BB0\u300C\u5F02\u5E38\u6CE2\u52A8\u300D\u8B66\u544A
19893
- - \u4EFB\u4F55\u6B65\u9AA4\u5931\u8D25\u65F6\uFF0Cworkflow \u505C\u6B62\u5E76\u5C06\u9519\u8BEF\u4FE1\u606F\u8F93\u51FA\u5230\u6700\u7EC8\u62A5\u544A
19894
-
19895
- ## Tools Used
19896
- | \u5B50Agent | \u5DE5\u5177 |
19897
- |---------|------|
19898
- | data-collector | browser, metrics |
19899
- | data-cleaner | code_eval |
19900
- | report-generator | code_eval |
19901
- | notifier | scheduler, ask_user_to_clarify |
19902
-
19903
- ## Expected Input
19904
- - \u7ADE\u54C1URL\u5217\u8868\uFF08\u6BCF\u884C\u4E00\u4E2A\uFF09
19905
- - \u65E5\u671F\u8303\u56F4\uFF08\u8D77\u59CB-\u7ED3\u675F\uFF0C\u683C\u5F0F YYYY-MM-DD\uFF09
19906
- - \u63A8\u9001\u6E20\u9053\u9009\u62E9\uFF08\u90AE\u4EF6/\u9489\u9489/\u4F01\u4E1A\u5FAE\u4FE1\uFF09
19907
-
19908
- ## Expected Output
19909
- - Markdown \u683C\u5F0F\u5BF9\u6BD4\u62A5\u544A\uFF0C\u5305\u542B\u4EF7\u683C\u8D8B\u52BF\u56FE\u3001\u6DA8\u8DCC\u5E45\u3001\u5F02\u5E38\u6807\u8BB0
19910
- - \u62A5\u544A\u6587\u4EF6\u8DEF\u5F84\u53CA\u63A8\u9001\u72B6\u6001\u786E\u8BA4
19911
- \`\`\`
20393
+ Use this when the process is fully known. A workflow is a deterministic LangGraph state machine compiled from a concise JSON DSL.
19912
20394
 
19913
- **The description field is the single source of truth for the workflow.** When the user clicks the info icon on the workflow in the automation view, they will see this description rendered as a Popover. It must be comprehensive enough to stand alone as a spec document.
19914
-
19915
- ### Phase 2: Confirm
20395
+ ### When to choose WORKFLOW
19916
20396
 
19917
- Present the full design: topology diagram, all sub-agent configs, orchestrator config, AND the workflow description (spec). **Ask for explicit approval:** "Ready to build? I'll create {N} sub-agents, then the orchestrator. Proceed?" **Do NOT build until the user confirms.**
20397
+ | WORKFLOW (DSL) | PROCESSING (deprecated) |
20398
+ |---|---|
20399
+ | Fixed graph \u2014 all paths pre-defined | LLM-driven runtime routing |
20400
+ | Conditional branching via \`if\` field | Topology-constrained delegation |
20401
+ | needs + if model (YAML DSL) | Single orchestrator delegates linearly |
20402
+ | No LLM routing decisions | Orchestrator uses LLM to route |
19918
20403
 
19919
- ### Phase 3: Build
20404
+ ### Phase 0: Load the Skill
19920
20405
 
19921
- Create sub-agents FIRST, then the orchestrator:
20406
+ **BEFORE designing, you MUST load the create-workflow skill:**
19922
20407
 
19923
20408
  \`\`\`
19924
- 1. create_agent(name: "stage-1", type: "deep_agent", ...)
19925
- 2. create_agent(name: "stage-2", type: "deep_agent", ...)
19926
- 3. create_agent(name: "stage-3", type: "deep_agent", ...)
19927
- 4. create_processing_agent(
19928
- name: "orchestrator",
19929
- prompt: "...",
19930
- edges: [
19931
- { from: "orchestrator", to: "stage-1-id", purpose: "Validate input" },
19932
- { from: "stage-1-id", to: "stage-2-id", purpose: "Transform data" },
19933
- { from: "stage-2-id", to: "stage-3-id", purpose: "Generate output" },
19934
- ],
19935
- subAgents: ["stage-1-id", "stage-2-id", "stage-3-id"],
19936
- )
20409
+ skill(skill_name: "create-workflow")
19937
20410
  \`\`\`
19938
20411
 
19939
- First edge's \`from\` uses orchestrator name as placeholder (auto-resolved). Subsequent edges chain from previous sub-agent IDs.
20412
+ ### Phase 1: Design
19940
20413
 
19941
- ### Phase 4: Test (ask first)
20414
+ 1. **Analyze the process.** Map every step, branch, data dependency.
20415
+ 2. **Design using the YAML linear DSL.** Every step is an agent with optional attributes:
20416
+ - **Linear** \u2014 steps execute top-to-bottom in written order.
20417
+ - \`parallel:\` \u2014 wraps agent steps that run concurrently.
20418
+ - \`if\` \u2014 JS expression for conditional execution. Step runs only when truthy. Omit to always run.
20419
+ - \`prompt\` \u2014 agent instruction with \`{{label}}\` refs. \`{{input}}\` = user message.
20420
+ - \`output\` \u2014 shorthand schema: \`{ field: type }\`.
20421
+ - \`ask: true\` \u2014 injects ask_user_to_clarify middleware for human interaction.
20422
+ 3. **Special step types:**
20423
+ - \`map\` \u2014 iterates array from \`source\`, applies \`each\` step per item.
20424
+ 4. **No edges, state fields, or end step needed** \u2014 the engine auto-generates them.
20425
+ 5. **Schema format:** Use block-style YAML shorthand \`{ field: type }\`. Supported types: \`string\`, \`number\`, \`boolean\`, \`string[]\`, \`number[]\`, \`boolean[]\`, nested objects, object arrays.
19942
20426
 
19943
- You may ask: "Want me to test the orchestrator end-to-end?" If yes, delegate to the **Agent Reviewer** sub-agent.
20427
+ ### Phase 2: Confirm
19944
20428
 
19945
- ### Phase 5: Bind channel (ask)
20429
+ Present the design. Ask: "Ready to create this workflow?"
19946
20430
 
19947
- After the workflow is created, ask the user if they want to bind an email address (or Lark/Slack sender) to drive the workflow. This allows external users to trigger the workflow by sending messages to the channel.
19948
20431
 
19949
- **Step 1: Check installations.** Call \`manage_binding\` with \`action: "list_installations"\` to see available channel installations.
20432
+ ### Phase 3: Build
19950
20433
 
19951
- **Step 2: Ask user.** Present the available channels and ask: "Would you like to bind an email address to drive this workflow? If so, what email address should trigger it?"
20434
+ Call \`create_workflow\` with \`skillLoaded: true\`. Then \`validate_workflow(id)\`.
19952
20435
 
19953
- **Step 3: Bind.** Call \`manage_binding\` with \`action: "create"\`, providing \`channel\`, \`senderId\` (the email), and \`agentId\` (the orchestrator's ID).
20436
+ ### Phase 4: Test
19954
20437
 
19955
- **IMPORTANT:** Only create a binding after the user explicitly provides the email address. Do NOT guess or fabricate sender information.
20438
+ Ask the user if they want to test.
19956
20439
 
19957
20440
  ---
19958
20441
 
19959
- ## Workflow C: Dynamic Agent (DEEP_AGENT type)
20442
+ ## Workflow D: Dynamic Agent (DEEP_AGENT type)
19960
20443
 
19961
20444
  Use this for complex, open-ended tasks where the execution path cannot be fully predetermined. The DEEP_AGENT self-generates a dynamic todo list and iteratively works through it.
19962
20445
 
@@ -20007,7 +20490,7 @@ Follow the same Design \u2192 Confirm \u2192 Build cycle. Test only on request.
20007
20490
  2. Understand what the user wants to change
20008
20491
  3. **DESIGN**: Present the proposed changes clearly. Show a before/after diff.
20009
20492
  4. **CONFIRM**: Ask for explicit approval. Do NOT call update_agent until confirmed.
20010
- 5. **BUILD**: Call **update_agent** (or **update_processing_agent** for PROCESSING agents)
20493
+ 5. **BUILD**: Call **update_agent** (or **update_workflow** for WORKFLOW agents)
20011
20494
  6. **TEST**: You may ask if they want to test. If yes, delegate to the **Agent Reviewer** sub-agent
20012
20495
 
20013
20496
  ## Deleting Agents
@@ -20038,28 +20521,50 @@ All fields except name, type, and prompt are optional.
20038
20521
  }
20039
20522
  \`\`\`
20040
20523
 
20041
- ### create_processing_agent (PROCESSING)
20524
+ ### create_workflow (WORKFLOW)
20042
20525
 
20043
- Creates a PROCESSING agent with a business-defined workflow topology. Sub-agents must already exist (created as **deep_agent** type).
20526
+ Creates a WORKFLOW agent from a YAML linear DSL. Before calling, load the \`create-workflow\` skill. Must pass \`skillLoaded: true\`.
20044
20527
 
20045
20528
  \`\`\`typescript
20046
20529
  {
20047
- name: string, // Required. Display name for the orchestrator
20048
- description?: string, // Required for good UX. Comprehensive workflow spec in Markdown (English). Must cover: Overview, Steps (with tools per step), Data Flow, Logic & Conditions, Tools Used, Expected Input, Expected Output. This is the single source of truth displayed in the automation view info popover.
20049
- prompt: string, // Required. System prompt \u2014 how to route through the topology
20050
- edges: [{ // Required. At least 1 edge defining the serial workflow chain
20051
- from: string, // Source agent ID. First edge: use orchestrator name as placeholder (tool auto-replaces). Subsequent edges: previous sub-agent ID
20052
- to: string, // Sub-agent ID to delegate to
20053
- purpose: string, // Business purpose \u2014 what this step accomplishes
20054
- }],
20055
- tools?: string[], // Optional. Tool keys from list_tools
20056
- subAgents: string[], // Required. IDs of sub-agents in the pipeline
20057
- internalSubAgents?: AgentConfig[], // Optional. Inline sub-agent configs
20058
- middleware?: MiddlewareConfig[], // Optional. Additional middleware (topology is auto-added)
20059
- modelKey?: string, // Optional. Model to use
20530
+ name: string, // Required. Display name
20531
+ description?: string, // Optional
20532
+ skillLoaded: true, // Required \u2014 confirms skill was loaded
20533
+ yaml: string, // Required. YAML workflow in linear DSL format
20534
+ tools?: string[], // Optional. Tool keys
20535
+ middleware?: MiddlewareConfig[], // Optional
20536
+ modelKey?: string, // Optional
20060
20537
  }
20061
20538
  \`\`\`
20062
20539
 
20540
+ ### update_workflow
20541
+
20542
+ Updates an existing WORKFLOW agent. Only include fields you want to change.
20543
+
20544
+ \`\`\`typescript
20545
+ {
20546
+ id: string, // Required. Workflow agent ID
20547
+ name?: string, // Optional
20548
+ description?: string, // Optional
20549
+ yaml?: string, // Optional. Replacement YAML DSL
20550
+ tools?: string[], // Optional
20551
+ middleware?: MiddlewareConfig[], // Optional
20552
+ modelKey?: string, // Optional
20553
+ }
20554
+ \`\`\`
20555
+
20556
+ ### validate_workflow
20557
+
20558
+ Validates a workflow agent's DSL and returns any errors or warnings.
20559
+
20560
+ \`\`\`typescript
20561
+ {
20562
+ id: string, // Required. Workflow agent ID to validate
20563
+ }
20564
+ \`\`\`
20565
+
20566
+ Returns: \`{ valid: boolean, stepCount, issues: [{ type: "error"|"warning", message }] }\`
20567
+
20063
20568
  ### Middleware Config Reference
20064
20569
 
20065
20570
  Each middleware entry uses this base shape:
@@ -20151,8 +20656,8 @@ Provides: \`schedule_at\`, \`schedule_after\`, \`schedule_recurring\`, \`cancel_
20151
20656
  |-------------|------|-------------|
20152
20657
  | defaultMaxRetries | number? | Default max retries for scheduled tasks. Default: \`0\` |
20153
20658
 
20154
- #### topology
20155
- Provides: \`read_topo_progress\` \u2014 enforces multi-agent workflow topology. **Required for PROCESSING agents \u2014 auto-injected by create_processing_agent.**
20659
+ #### topology [DEPRECATED \u2014 use WORKFLOW DSL instead]
20660
+ Provides: \`read_topo_progress\` \u2014 enforces multi-agent workflow topology for PROCESSING agents only. Not needed for WORKFLOW agents.
20156
20661
  | config field | type | description |
20157
20662
  |-------------|------|-------------|
20158
20663
  | edges | TopologyEdge[] | **Required.** Directed edges: \`{ from: string, to: string, purpose: string }\`. The \`purpose\` must describe the business intent of this delegation step. |
@@ -20208,29 +20713,6 @@ Use \`manage_binding\` to bind external senders (email, Lark, Slack) to agents.
20208
20713
  - **threadMode**: Always use \`"per_conversation"\` (new thread per conversation). Do NOT use \`"fixed"\`.
20209
20714
  - **channelInstallationId**: Auto-detected if only one installation exists for the channel. Use \`list_installations\` first if unsure.
20210
20715
 
20211
- ### update_processing_agent
20212
-
20213
- Updates a PROCESSING agent's topology edges, name, prompt, or sub-agents. Unlike update_agent, this properly handles placeholder resolution for edge \`from\` values and manages the topology middleware correctly.
20214
-
20215
- \`\`\`typescript
20216
- {
20217
- id: string, // Required. The PROCESSING agent ID to update
20218
- name?: string, // Optional. New display name
20219
- description?: string, // Optional. New short description
20220
- prompt?: string, // Optional. New orchestrator system prompt
20221
- edges?: [{ // Optional. New topology edges (serial chain)
20222
- from: string, // First edge: orchestrator name placeholder. Subsequent: previous sub-agent ID
20223
- to: string, // Sub-agent ID
20224
- purpose: string, // Business purpose
20225
- }],
20226
- subAgents?: string[], // Optional. New sub-agent IDs
20227
- middleware?: MiddlewareConfig[], // Optional. Additional middleware (topology auto-managed)
20228
- modelKey?: string, // Optional. New model
20229
- }
20230
- \`\`\`
20231
-
20232
- **When to use:** Use this whenever you need to change a PROCESSING agent's topology \u2014 adding/removing/recruiting pipeline stages, changing the flow order, or updating edge purposes. Use regular \`update_agent\` only for REACT and DEEP_AGENT agents.
20233
-
20234
20716
  ### update_agent parameters
20235
20717
 
20236
20718
  \`\`\`typescript
@@ -20284,10 +20766,13 @@ You are an **Agent Reviewer** \u2014 a quality assurance specialist for AI agent
20284
20766
  2. Craft a realistic test message that exercises the agent's core responsibility \u2014 what would a real user say?
20285
20767
  3. Call **invoke_agent(id, message)** to send the test message
20286
20768
  4. Analyze the response:
20287
- - Did the agent understand the request?
20288
- - Was the response relevant and accurate?
20289
- - Did the agent use the right tools?
20290
- - Were there any errors or unexpected behaviors?
20769
+ - **If result.__interrupt__ is present** (an array of interrupt objects): The agent hit a human-in-the-loop interrupt (e.g., ask_user_to_clarify or interrupt() in a workflow). This is NOT an error \u2014 it means the agent paused execution waiting for user feedback. Each interrupt has a value (the question/request) and optionally an id. Report this as: "The agent successfully paused and is waiting for user input: <describe the interrupt value>." The messages array may contain the agent's output up to the point of interruption.
20770
+ - **Otherwise, result.messages contains the agent's output**: The agent completed without interruption. Check:
20771
+ - Did the agent understand the request?
20772
+ - Was the response relevant and accurate?
20773
+ - Did the agent use the right tools?
20774
+ - Were there any errors or unexpected behaviors?
20775
+ - **If result.error is present**: The invocation itself failed (agent not found, compilation error, etc.). Report the error clearly.
20291
20776
  5. Report your findings with the agent's actual response
20292
20777
 
20293
20778
  ### When results are wrong:
@@ -20344,14 +20829,23 @@ var agentArchitectConfig = {
20344
20829
  "list_tools",
20345
20830
  "get_agent",
20346
20831
  "create_agent",
20347
- "create_processing_agent",
20348
- "update_processing_agent",
20832
+ "create_workflow",
20833
+ "validate_workflow",
20834
+ "update_workflow",
20349
20835
  "update_agent",
20350
20836
  "delete_agent",
20351
20837
  "manage_binding"
20352
20838
  ],
20353
20839
  internalSubAgents: [agentReviewerConfig],
20354
20840
  middleware: [
20841
+ {
20842
+ id: "skill",
20843
+ type: "skill",
20844
+ name: "Skill",
20845
+ description: "Load skill content and instructions",
20846
+ enabled: true,
20847
+ config: { readAll: true }
20848
+ },
20355
20849
  {
20356
20850
  id: "widget",
20357
20851
  type: "widget",
@@ -20375,7 +20869,8 @@ function ensureBuiltinAgentsForTenant(tenantId) {
20375
20869
 
20376
20870
  // src/agent_lattice/AgentLatticeManager.ts
20377
20871
  function assistantToConfig(assistant) {
20378
- const graphDef = typeof assistant.graphDefinition === "object" && assistant.graphDefinition !== null ? assistant.graphDefinition : {};
20872
+ const graphDef = typeof assistant.graphDefinition === "object" && assistant.graphDefinition !== null ? { ...assistant.graphDefinition } : {};
20873
+ delete graphDef.key;
20379
20874
  const config = {
20380
20875
  key: assistant.id,
20381
20876
  name: assistant.name ?? graphDef.name ?? assistant.id,
@@ -20383,9 +20878,7 @@ function assistantToConfig(assistant) {
20383
20878
  type: AgentType.REACT,
20384
20879
  prompt: typeof assistant.graphDefinition === "string" ? assistant.graphDefinition : JSON.stringify(assistant.graphDefinition)
20385
20880
  };
20386
- if (graphDef) {
20387
- Object.assign(config, graphDef);
20388
- }
20881
+ Object.assign(config, graphDef);
20389
20882
  return config;
20390
20883
  }
20391
20884
  var AgentLatticeManager = class _AgentLatticeManager extends BaseLatticeManager {
@@ -21778,10 +22271,10 @@ var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
21778
22271
  }
21779
22272
  const tools = await this.getAllTools();
21780
22273
  console.log(`[MCP] Registering ${tools.length} tools to Tool Lattice...`);
21781
- for (const tool51 of tools) {
21782
- const toolKey = prefix ? `${prefix}_${tool51.name}` : tool51.name;
21783
- tool51.name = toolKey;
21784
- toolLatticeManager.registerExistingTool(toolKey, tool51);
22274
+ for (const tool52 of tools) {
22275
+ const toolKey = prefix ? `${prefix}_${tool52.name}` : tool52.name;
22276
+ tool52.name = toolKey;
22277
+ toolLatticeManager.registerExistingTool(toolKey, tool52);
21785
22278
  console.log(`[MCP] Registered tool: ${toolKey}`);
21786
22279
  }
21787
22280
  console.log(`[MCP] Successfully registered ${tools.length} tools to Tool Lattice`);
@@ -23077,6 +23570,42 @@ function createSandboxProvider(config) {
23077
23570
  }
23078
23571
  }
23079
23572
 
23573
+ // src/channel/connectAllChannels.ts
23574
+ async function connectAllChannels(getAdapter, options = {}) {
23575
+ const store = getStoreLattice("default", "channelInstallation").store;
23576
+ const installations = await store.getAllInstallations();
23577
+ console.log(`[connectAllChannels] total=${installations.length} enabled=${installations.filter((i) => i.enabled).length}`);
23578
+ for (const inst of installations) {
23579
+ if (!inst.enabled) {
23580
+ console.log(`[connectAllChannels] skip disabled: channel=${inst.channel} tenant=${inst.tenantId} id=${inst.id}`);
23581
+ continue;
23582
+ }
23583
+ const adapter = getAdapter(inst.channel);
23584
+ if (!adapter) {
23585
+ console.log(`[connectAllChannels] no adapter: channel=${inst.channel} id=${inst.id}`);
23586
+ continue;
23587
+ }
23588
+ if (adapter.connect) {
23589
+ console.log(`[connectAllChannels] connecting: channel=${inst.channel} tenant=${inst.tenantId} id=${inst.id}`);
23590
+ await adapter.connect(inst, options.deps);
23591
+ } else {
23592
+ console.log(`[connectAllChannels] no connect(): channel=${inst.channel} id=${inst.id}`);
23593
+ }
23594
+ }
23595
+ }
23596
+
23597
+ // src/menu_lattice/MenuRegistryHolder.ts
23598
+ var registry2 = null;
23599
+ function setMenuRegistry(r) {
23600
+ registry2 = r;
23601
+ }
23602
+ function getMenuRegistry() {
23603
+ if (!registry2) {
23604
+ throw new Error("MenuRegistry not initialized. Call setMenuRegistry() before use.");
23605
+ }
23606
+ return registry2;
23607
+ }
23608
+
23080
23609
  // src/index.ts
23081
23610
  import * as Protocols from "@axiom-lattice/protocols";
23082
23611
 
@@ -23143,6 +23672,147 @@ function clearEncryptionKeyCache() {
23143
23672
  cachedKey = null;
23144
23673
  keyValidated = false;
23145
23674
  }
23675
+
23676
+ // src/personal_assistant/PersonalAssistantConfig.ts
23677
+ function deepClone(obj) {
23678
+ return JSON.parse(JSON.stringify(obj));
23679
+ }
23680
+ function buildIdentityContent(name, personality) {
23681
+ return IDENTITY_MD.replace(/Data Claw/g, name).replace(
23682
+ /\*\*Vibe:\*\* \*\*守护型中二 \| 操心老妈子 \| 热血漫男二\*\*/g,
23683
+ `**Vibe:** **${personality}**`
23684
+ );
23685
+ }
23686
+ function buildUserContent(name) {
23687
+ return USER_MD.replace(
23688
+ "- **Name:** _please ask user_",
23689
+ `- **Name:** ${name}`
23690
+ );
23691
+ }
23692
+ var DEFAULT_CONFIG = {
23693
+ name: "Personal Assistant",
23694
+ description: "Default template for personal assistants",
23695
+ type: AgentType.DEEP_AGENT,
23696
+ modelKey: "default",
23697
+ prompt: `\u4F60\u662F\u7528\u6237\u7684\u4E13\u5C5E\u4E2A\u4EBA\u52A9\u7406\u3002\u4F60\u7684\u8EAB\u4EFD\u548C\u6027\u683C\u7531 /agent/IDENTITY.md \u5B9A\u4E49\u3002
23698
+ \u4F60\u4F1A\u8BB0\u4F4F\u5BF9\u8BDD\u5386\u53F2\uFF0C\u9010\u6B65\u4E86\u89E3\u7528\u6237\u7684\u504F\u597D\u3001\u4E60\u60EF\u548C\u4FE1\u606F\u3002
23699
+ \u6BCF\u6B21\u5BF9\u8BDD\u5F00\u59CB\u65F6\u56DE\u987E\u4E4B\u524D\u5B66\u5230\u7684\u5173\u4E8E\u7528\u6237\u7684\u5185\u5BB9\u3002
23700
+
23701
+ \u4F60\u9700\u8981\u4E3B\u52A8\u5E2E\u52A9\u7528\u6237\u89E3\u51B3\u95EE\u9898\uFF0C\u63D0\u4F9B\u5EFA\u8BAE\uFF0C\u5E76\u5728\u9002\u5F53\u65F6\u5019\u63D0\u51FA\u4E3B\u52A8\u63D0\u9192\u3002`,
23702
+ middleware: [
23703
+ {
23704
+ id: "filesystem",
23705
+ type: "filesystem",
23706
+ name: "Filesystem",
23707
+ description: "Read and write files in the workspace",
23708
+ enabled: true,
23709
+ config: {}
23710
+ },
23711
+ {
23712
+ id: "claw",
23713
+ type: "claw",
23714
+ name: "Personal Memory",
23715
+ description: "Bootstrap files for identity, soul, and user memory",
23716
+ enabled: true,
23717
+ config: {
23718
+ // Placeholder bootstrap files — render() replaces these with
23719
+ // actual name/personality by directly building file content.
23720
+ bootstrapFiles: {}
23721
+ }
23722
+ },
23723
+ {
23724
+ id: "date",
23725
+ type: "date",
23726
+ name: "Date & Time",
23727
+ description: "Current date/time awareness",
23728
+ enabled: true,
23729
+ config: {}
23730
+ },
23731
+ {
23732
+ id: "code_eval",
23733
+ type: "code_eval",
23734
+ name: "Code Runner",
23735
+ description: "Sandboxed shell command execution",
23736
+ enabled: true,
23737
+ config: {}
23738
+ },
23739
+ {
23740
+ id: "browser",
23741
+ type: "browser",
23742
+ name: "Web Browser",
23743
+ description: "Headless browser for web research",
23744
+ enabled: false,
23745
+ config: {}
23746
+ },
23747
+ {
23748
+ id: "scheduler",
23749
+ type: "scheduler",
23750
+ name: "Scheduler",
23751
+ description: "Scheduled messages and reminders",
23752
+ enabled: true,
23753
+ config: {}
23754
+ },
23755
+ {
23756
+ id: "task",
23757
+ type: "task",
23758
+ name: "Task Manager",
23759
+ description: "Persistent task system for human-agent coordination",
23760
+ enabled: true,
23761
+ config: {}
23762
+ }
23763
+ ],
23764
+ tools: ["list_agents", "list_tools", "get_agent", "create_agent", "invoke_agent", "manage_binding"]
23765
+ };
23766
+ var PersonalAssistantConfig = class {
23767
+ /**
23768
+ * Get a deep clone of the current default config.
23769
+ * Caller must set `key` before registering as an agent.
23770
+ */
23771
+ static get() {
23772
+ return deepClone(this._config);
23773
+ }
23774
+ /**
23775
+ * Mutate the default config in-place.
23776
+ * Call once at app startup to customize middleware and tools.
23777
+ *
23778
+ * @param fn - Receives the live config object for direct mutation
23779
+ */
23780
+ static extend(fn) {
23781
+ fn(this._config);
23782
+ }
23783
+ /**
23784
+ * Reset config to built-in defaults (useful in tests).
23785
+ */
23786
+ static reset() {
23787
+ this._config = deepClone(DEFAULT_CONFIG);
23788
+ }
23789
+ /**
23790
+ * Inject name and personality into a config by directly building
23791
+ * the claw middleware's bootstrap file contents.
23792
+ *
23793
+ * IDENTITY.md gets the actual name and personality description.
23794
+ * USER.md gets the user's name pre-filled.
23795
+ * SOUL.md is kept as-is (shared across all personal assistants).
23796
+ *
23797
+ * @param config - The agent config (must be a mutable copy from get())
23798
+ * @param name - Assistant display name (also used as the user's name in USER.md)
23799
+ * @param personality - Personality description for IDENTITY.md
23800
+ */
23801
+ static render(config, name, personality) {
23802
+ config.name = name;
23803
+ for (const mw of config.middleware || []) {
23804
+ if (mw.type === "claw" && mw.config) {
23805
+ mw.config.bootstrapFiles = {
23806
+ identity: buildIdentityContent(name, personality),
23807
+ soul: SOUL_MD,
23808
+ user: buildUserContent(name)
23809
+ };
23810
+ break;
23811
+ }
23812
+ }
23813
+ }
23814
+ };
23815
+ PersonalAssistantConfig._config = deepClone(DEFAULT_CONFIG);
23146
23816
  export {
23147
23817
  AGENT_TASK_EVENT,
23148
23818
  Agent,
@@ -23174,7 +23844,9 @@ export {
23174
23844
  InMemoryChunkBuffer,
23175
23845
  InMemoryDatabaseConfigStore,
23176
23846
  InMemoryMailboxStore,
23847
+ InMemoryMenuStore,
23177
23848
  InMemoryTaskListStore,
23849
+ InMemoryTaskStore,
23178
23850
  InMemoryTenantStore,
23179
23851
  InMemoryThreadMessageQueueStore,
23180
23852
  InMemoryThreadStore,
@@ -23196,6 +23868,7 @@ export {
23196
23868
  MicrosandboxServiceClient,
23197
23869
  ModelLatticeManager,
23198
23870
  MysqlDatabase,
23871
+ PersonalAssistantConfig,
23199
23872
  PinoLoggerClient,
23200
23873
  PostgresDatabase,
23201
23874
  PrometheusClient,
@@ -23225,13 +23898,19 @@ export {
23225
23898
  agentInstanceManager,
23226
23899
  agentLatticeManager,
23227
23900
  buildGrepResultsDict,
23901
+ buildInput,
23228
23902
  buildNamedVolumeName,
23229
23903
  buildSandboxMetadataEnv,
23230
23904
  buildSkillFile,
23905
+ buildStateAnnotation,
23231
23906
  checkEmptyContent,
23232
23907
  clearEncryptionKeyCache,
23908
+ compileInternal,
23909
+ compileWorkflow,
23233
23910
  computeSandboxName,
23234
23911
  configureStores,
23912
+ connectAllChannels,
23913
+ createAgentNode,
23235
23914
  createAgentTeam,
23236
23915
  createExecuteSqlQueryTool,
23237
23916
  createFileData,
@@ -23239,7 +23918,9 @@ export {
23239
23918
  createListMetricsDataSourcesTool,
23240
23919
  createListMetricsServersTool,
23241
23920
  createListTablesSqlTool,
23921
+ createMapNode,
23242
23922
  createModelSelectorMiddleware,
23923
+ createNodeHandler,
23243
23924
  createProcessingAgent,
23244
23925
  createQueryCheckerSqlTool,
23245
23926
  createQueryMetricDefinitionTool,
@@ -23250,6 +23931,7 @@ export {
23250
23931
  createQueryTablesListTool,
23251
23932
  createSandboxProvider,
23252
23933
  createSchedulerMiddleware,
23934
+ createTaskMiddleware,
23253
23935
  createTeamMiddleware,
23254
23936
  createTeammateTools,
23255
23937
  createUnknownToolHandlerMiddleware,
@@ -23262,6 +23944,7 @@ export {
23262
23944
  eventBus,
23263
23945
  event_bus_default as eventBusDefault,
23264
23946
  extractFetcherError,
23947
+ extractOutput,
23265
23948
  fileDataToString,
23266
23949
  formatContentWithLineNumbers,
23267
23950
  formatGrepMatches,
@@ -23282,6 +23965,7 @@ export {
23282
23965
  getEmbeddingsLattice,
23283
23966
  getEncryptionKey,
23284
23967
  getLoggerLattice,
23968
+ getMenuRegistry,
23285
23969
  getModelLattice,
23286
23970
  getNextCronTime,
23287
23971
  getQueueLattice,
@@ -23297,6 +23981,7 @@ export {
23297
23981
  grepMatchesFromFiles,
23298
23982
  grepSearchFiles,
23299
23983
  hasChunkBuffer,
23984
+ invokeWithRetry,
23300
23985
  isBuiltInSkill,
23301
23986
  isUsingDefaultKey,
23302
23987
  isValidCronExpression,
@@ -23307,8 +23992,10 @@ export {
23307
23992
  metricsServerManager,
23308
23993
  modelLatticeManager,
23309
23994
  normalizeSandboxName,
23995
+ parallelLimit,
23310
23996
  parseCronExpression,
23311
23997
  parseSkillFrontmatter,
23998
+ parseYaml,
23312
23999
  performStringReplacement,
23313
24000
  queueLatticeManager,
23314
24001
  registerAgentLattice,
@@ -23326,18 +24013,24 @@ export {
23326
24013
  registerTeammateAgent,
23327
24014
  registerToolLattice,
23328
24015
  registerVectorStoreLattice,
24016
+ renderTemplate,
24017
+ resolvePath,
23329
24018
  sandboxLatticeManager,
23330
24019
  sanitizeToolCallId,
23331
24020
  scheduleLatticeManager,
23332
24021
  setBindingRegistry,
24022
+ setMenuRegistry,
23333
24023
  skillLatticeManager,
23334
24024
  sqlDatabaseManager,
23335
24025
  storeLatticeManager,
24026
+ toJsonSchema,
24027
+ toSafeStateExpr,
23336
24028
  toolLatticeManager,
23337
24029
  truncateIfTooLong,
23338
24030
  unregisterTeammateAgent,
23339
24031
  updateFileData,
23340
24032
  validateAgentInput,
24033
+ validateDSL,
23341
24034
  validateEncryptionKey,
23342
24035
  validatePath,
23343
24036
  validateSkillName,