@axiom-lattice/core 2.1.80 → 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.js CHANGED
@@ -387,40 +387,342 @@ var init_memory_lattice = __esm({
387
387
  }
388
388
  });
389
389
 
390
+ // src/workflow/schema.ts
391
+ function toJsonSchema(fields) {
392
+ if (!fields || Object.keys(fields).length === 0) return void 0;
393
+ const properties = {};
394
+ const required = [];
395
+ for (const [key, value] of Object.entries(fields)) {
396
+ required.push(key);
397
+ properties[key] = fieldToSchema(value);
398
+ }
399
+ return { type: "object", properties, required };
400
+ }
401
+ function fieldToSchema(value) {
402
+ if (typeof value === "string") return stringTypeToSchema(value);
403
+ if (Array.isArray(value) && value.length > 0 && typeof value[0] === "object" && !Array.isArray(value[0])) {
404
+ const nested = toJsonSchema(value[0]);
405
+ return { type: "array", items: nested ?? { type: "object" } };
406
+ }
407
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
408
+ const nested = toJsonSchema(value);
409
+ return nested ?? { type: "object" };
410
+ }
411
+ return { type: "string" };
412
+ }
413
+ function stringTypeToSchema(type) {
414
+ if (type.endsWith("[]")) {
415
+ const inner = type.slice(0, -2);
416
+ return { type: "array", items: stringTypeToSchema(inner) };
417
+ }
418
+ if (type === "string") return { type: "string" };
419
+ if (type === "number") return { type: "number" };
420
+ if (type === "boolean") return { type: "boolean" };
421
+ return { type };
422
+ }
423
+ var init_schema = __esm({
424
+ "src/workflow/schema.ts"() {
425
+ "use strict";
426
+ }
427
+ });
428
+
429
+ // src/workflow/parse-yaml.ts
430
+ function nodeId(label) {
431
+ return `n_${label}`;
432
+ }
433
+ function nextParallelLabel() {
434
+ return `parallel_${_parallelSeq++}`;
435
+ }
436
+ function translate(template) {
437
+ return template.replace(/\{\{([^}]+)\}\}/g, (_m, expr) => {
438
+ const t = expr.trim();
439
+ if (t === "item") return "${item}";
440
+ return `\${state.${t}}`;
441
+ });
442
+ }
443
+ function toSafeStateExpr(expr) {
444
+ const match = expr.match(/^([a-zA-Z_][a-zA-Z0-9_-]*)/);
445
+ if (!match) return `state.${expr}`;
446
+ const field = match[0];
447
+ const rest = expr.slice(field.length);
448
+ return `state["${field}"]${rest}`;
449
+ }
450
+ function validateExpression(expr) {
451
+ if (/;/.test(expr)) {
452
+ throw new Error(`Condition expression must not contain semicolons: "${expr}"`);
453
+ }
454
+ if (/[{}]/.test(expr)) {
455
+ throw new Error(`Condition expression must not contain braces: "${expr}"`);
456
+ }
457
+ if (/\bfunction\b/.test(expr)) {
458
+ throw new Error(`Condition expression must not contain 'function': "${expr}"`);
459
+ }
460
+ if (/\brequire\b|\bimport\b|\bmodule\b/.test(expr)) {
461
+ throw new Error(`Condition expression must not contain require/import: "${expr}"`);
462
+ }
463
+ if (/\bprocess\b|\bglobal\b|\bglobalThis\b/.test(expr)) {
464
+ throw new Error(`Condition expression must not contain process/global: "${expr}"`);
465
+ }
466
+ if (/\beval\b|\bFunction\b/.test(expr)) {
467
+ throw new Error(`Condition expression must not contain eval/Function: "${expr}"`);
468
+ }
469
+ if (/\bconstructor\b|\b__proto__\b|\bprototype\b/.test(expr)) {
470
+ throw new Error(`Condition expression must not contain prototype access: "${expr}"`);
471
+ }
472
+ if (/\bsetTimeout\b|\bsetInterval\b|\bbuffer\b/i.test(expr)) {
473
+ throw new Error(`Condition expression must not contain timer or buffer references: "${expr}"`);
474
+ }
475
+ }
476
+ function parseYaml(yamlStr) {
477
+ _parallelSeq = 0;
478
+ let raw;
479
+ try {
480
+ raw = yaml.load(yamlStr);
481
+ } catch (e) {
482
+ const line = e?.mark?.line != null ? ` (line ${e.mark.line + 1})` : "";
483
+ throw new Error(`YAML parse error${line}: ${e.message || e}`);
484
+ }
485
+ if (!raw || typeof raw !== "object" || !Array.isArray(raw.steps)) {
486
+ throw new Error("Workflow YAML must have 'steps' (array)");
487
+ }
488
+ const name = typeof raw.name === "string" ? raw.name : "workflow";
489
+ const wf = {
490
+ name,
491
+ steps: raw.steps.map((s, i) => parseStep(s, i))
492
+ };
493
+ return normalize(wf);
494
+ }
495
+ function parseStep(raw, index) {
496
+ if (raw.parallel !== void 0) {
497
+ if (!Array.isArray(raw.parallel)) {
498
+ throw new Error(`Step at position ${index}: parallel must be an array`);
499
+ }
500
+ const children = raw.parallel.map((c, ci) => {
501
+ const entries2 = Object.entries(c);
502
+ if (entries2.length !== 1) {
503
+ throw new Error(`Parallel child at position ${index}.${ci} must be a single-key mapping`);
504
+ }
505
+ const [label, config2] = entries2[0];
506
+ return {
507
+ label,
508
+ if: config2.if !== void 0 ? String(config2.if) : void 0,
509
+ prompt: String(config2.prompt ?? ""),
510
+ output: config2.output,
511
+ ask: config2.ask === true
512
+ };
513
+ });
514
+ return {
515
+ parallel: children,
516
+ if: raw.if !== void 0 ? String(raw.if) : void 0,
517
+ output: raw.output
518
+ };
519
+ }
520
+ const entries = Object.entries(raw);
521
+ if (entries.length !== 1) {
522
+ throw new Error(`Step at position ${index} must be a single-key mapping`);
523
+ }
524
+ const [key, config] = entries[0];
525
+ const mapConfig = config?.map;
526
+ if (mapConfig && typeof mapConfig === "object") {
527
+ return {
528
+ map: {
529
+ source: mapConfig.source,
530
+ label: key,
531
+ // always use the YAML key as the label
532
+ if: mapConfig.if !== void 0 ? String(mapConfig.if) : void 0,
533
+ each: {
534
+ prompt: String(mapConfig.each?.prompt ?? ""),
535
+ output: mapConfig.each?.output
536
+ },
537
+ output: mapConfig.output,
538
+ batch: mapConfig.batch,
539
+ concurrency: mapConfig.concurrency
540
+ }
541
+ };
542
+ }
543
+ if (key === "map") {
544
+ throw new Error(`Map steps must use named format: - <label>: { map: { source, each, ... } }. Anonymous "- map:" is not supported.`);
545
+ }
546
+ return {
547
+ label: key,
548
+ if: config.if !== void 0 ? String(config.if) : void 0,
549
+ prompt: String(config.prompt ?? ""),
550
+ output: config.output,
551
+ ask: config.ask === true
552
+ };
553
+ }
554
+ function normalize(wf) {
555
+ validate(wf);
556
+ for (const step of wf.steps) {
557
+ if ("label" in step) {
558
+ const s = step;
559
+ if (s.if) validateExpression(s.if);
560
+ } else if ("parallel" in step) {
561
+ const pb = step;
562
+ if (pb.if) validateExpression(pb.if);
563
+ for (const child of pb.parallel) {
564
+ if (child.if) validateExpression(child.if);
565
+ }
566
+ }
567
+ }
568
+ const nodes = [];
569
+ const edges = [];
570
+ const fields = { input: { type: "string" } };
571
+ nodes.push({ id: "n_input", type: "input", name: "input", output: { key: "input" } });
572
+ edges.push({ from: "START", to: "n_input" });
573
+ let prevNodeId = "n_input";
574
+ for (const step of wf.steps) {
575
+ if ("label" in step) {
576
+ const s = step;
577
+ const nid = nodeId(s.label);
578
+ const schema = toJsonSchema(s.output);
579
+ nodes.push({
580
+ id: nid,
581
+ type: "agent",
582
+ name: s.label,
583
+ input: { template: translate(s.prompt) },
584
+ output: { key: s.label, ...schema ? { schema } : {} },
585
+ ask: s.ask,
586
+ condition: s.if
587
+ });
588
+ fields[s.label] = s.output ? { type: "object" } : { type: "string" };
589
+ addPrevEdges(edges, prevNodeId, nid);
590
+ prevNodeId = nid;
591
+ } else if ("parallel" in step) {
592
+ const pb = step;
593
+ const groupId = nextParallelLabel();
594
+ const groupNodeIds = [];
595
+ for (const child of pb.parallel) {
596
+ const nid = nodeId(child.label);
597
+ const schema = toJsonSchema(child.output);
598
+ nodes.push({
599
+ id: nid,
600
+ type: "agent",
601
+ name: child.label,
602
+ input: { template: translate(child.prompt) },
603
+ output: { key: child.label, ...schema ? { schema } : {} },
604
+ ask: child.ask,
605
+ condition: child.if,
606
+ parallelGroup: groupId
607
+ });
608
+ fields[child.label] = child.output ? { type: "object" } : { type: "string" };
609
+ groupNodeIds.push(nid);
610
+ }
611
+ addPrevEdges(edges, prevNodeId, groupNodeIds);
612
+ prevNodeId = groupNodeIds;
613
+ } else if ("map" in step) {
614
+ const ms = step.map;
615
+ const label = ms.label;
616
+ const nid = nodeId(label);
617
+ const innerSchema = toJsonSchema(ms.each?.output);
618
+ const mapSchema = toJsonSchema(ms.output);
619
+ nodes.push({
620
+ id: nid,
621
+ type: "map",
622
+ name: label,
623
+ source: `state.${ms.source}`,
624
+ itemKey: "item",
625
+ config: {
626
+ batchSize: ms.batch ?? 50,
627
+ maxConcurrency: ms.concurrency ?? 5,
628
+ innerConcurrency: ms.concurrency ?? 5
629
+ },
630
+ node: {
631
+ type: "agent",
632
+ input: ms.each?.prompt ? { template: translate(ms.each.prompt) } : void 0,
633
+ ...innerSchema ? { schema: innerSchema } : {}
634
+ },
635
+ output: { key: label, ...mapSchema ? { schema: mapSchema } : {} },
636
+ condition: ms.if
637
+ });
638
+ fields[label] = { type: "array", default: [] };
639
+ addPrevEdges(edges, prevNodeId, nid);
640
+ prevNodeId = nid;
641
+ }
642
+ }
643
+ const termNid = nodeId("__end");
644
+ nodes.push({ id: termNid, type: "terminal", name: "__end", status: "success" });
645
+ addPrevEdges(edges, prevNodeId, termNid);
646
+ return { version: "1.0", name: wf.name || "workflow", state: { fields }, nodes, edges };
647
+ }
648
+ function addPrevEdges(edges, fromNodes, toNodes) {
649
+ const fromList = Array.isArray(fromNodes) ? fromNodes : [fromNodes];
650
+ const toList = Array.isArray(toNodes) ? toNodes : [toNodes];
651
+ for (const from of fromList) {
652
+ for (const to of toList) {
653
+ if (!edges.some((e) => e.from === from && e.to === to)) {
654
+ edges.push({ from, to });
655
+ }
656
+ }
657
+ }
658
+ }
659
+ function validate(wf) {
660
+ const labels = /* @__PURE__ */ new Set();
661
+ for (const step of wf.steps) {
662
+ if ("label" in step) {
663
+ const s = step;
664
+ if (labels.has(s.label)) throw new Error(`Duplicate step label "${s.label}"`);
665
+ labels.add(s.label);
666
+ } else if ("parallel" in step) {
667
+ const pb = step;
668
+ if (pb.parallel.length === 0) {
669
+ throw new Error("parallel block must contain at least one child step");
670
+ }
671
+ for (const child of pb.parallel) {
672
+ if (labels.has(child.label)) throw new Error(`Duplicate step label "${child.label}"`);
673
+ labels.add(child.label);
674
+ }
675
+ } else if ("map" in step) {
676
+ const ms = step.map;
677
+ if (labels.has(ms.label)) throw new Error(`Duplicate step label "${ms.label}" (map step)`);
678
+ labels.add(ms.label);
679
+ }
680
+ }
681
+ }
682
+ var yaml, _parallelSeq;
683
+ var init_parse_yaml = __esm({
684
+ "src/workflow/parse-yaml.ts"() {
685
+ "use strict";
686
+ yaml = __toESM(require("js-yaml"));
687
+ init_schema();
688
+ _parallelSeq = 0;
689
+ }
690
+ });
691
+
390
692
  // src/workflow/utils.ts
391
693
  function buildStateAnnotation(fields) {
392
694
  const annotations = {};
393
695
  if (fields) {
394
696
  for (const [key, field] of Object.entries(fields)) {
395
- annotations[key] = (0, import_langgraph15.Annotation)({
697
+ annotations[key] = (0, import_langgraph14.Annotation)({
396
698
  default: () => field.default ?? defaultValueForType(field.type),
397
699
  reducer: buildReducer(field.reducer ?? "replace")
398
700
  });
399
701
  }
400
702
  }
401
703
  if (!annotations["messages"]) {
402
- annotations["messages"] = (0, import_langgraph15.Annotation)({
704
+ annotations["messages"] = (0, import_langgraph14.Annotation)({
403
705
  default: () => [],
404
706
  reducer: (prev, next) => [...prev, ...next]
405
707
  });
406
708
  }
407
- annotations["phase"] = (0, import_langgraph15.Annotation)({
709
+ annotations["phase"] = (0, import_langgraph14.Annotation)({
408
710
  default: () => "init",
409
711
  reducer: (_prev, next) => next
410
712
  });
411
713
  if (!annotations["status"]) {
412
- annotations["status"] = (0, import_langgraph15.Annotation)({
714
+ annotations["status"] = (0, import_langgraph14.Annotation)({
413
715
  default: () => "",
414
716
  reducer: (_prev, next) => next
415
717
  });
416
718
  }
417
719
  if (!annotations["_runId"]) {
418
- annotations["_runId"] = (0, import_langgraph15.Annotation)({
720
+ annotations["_runId"] = (0, import_langgraph14.Annotation)({
419
721
  default: () => void 0,
420
722
  reducer: (_prev, next) => next ?? _prev
421
723
  });
422
724
  }
423
- return import_langgraph15.Annotation.Root(annotations);
725
+ return import_langgraph14.Annotation.Root(annotations);
424
726
  }
425
727
  function defaultValueForType(type) {
426
728
  switch (type) {
@@ -528,7 +830,7 @@ Output must be valid JSON in exactly this shape. Return ONLY the JSON, no other
528
830
  ${example}`;
529
831
  prompt = prompt + schemaInstruction;
530
832
  }
531
- return { messages: [new import_messages6.HumanMessage(prompt)] };
833
+ return { messages: [new import_messages5.HumanMessage(prompt)] };
532
834
  }
533
835
  function schemaToExample(schema) {
534
836
  const example = schemaValueToExample(schema);
@@ -674,6 +976,36 @@ function createAgentNode(node, resolveAgent, trackingStore) {
674
976
  return async (state, config) => {
675
977
  const runId = state._runId;
676
978
  const tenantId = config?.configurable?.tenantId ?? "default";
979
+ if (node.condition) {
980
+ try {
981
+ validateExpression(node.condition);
982
+ const safeExpr = toSafeStateExpr(node.condition);
983
+ const fn = new Function("state", `try { return ${safeExpr}; } catch { return false; }`);
984
+ const shouldRun = fn(state);
985
+ if (!shouldRun) {
986
+ console.log(`[WF][${node.id}] condition false, skipping "${node.name}" (${node.condition})`);
987
+ if (trackingStore && runId) {
988
+ const step = await trackingStore.upsertRunStep({
989
+ runId,
990
+ tenantId,
991
+ stepType: node.type,
992
+ stepName: node.name
993
+ }).catch(() => null);
994
+ if (step) {
995
+ await trackingStore.updateRunStep(runId, step.id, {
996
+ status: "skipped",
997
+ completedAt: /* @__PURE__ */ new Date()
998
+ }).catch(() => {
999
+ });
1000
+ }
1001
+ }
1002
+ return { phase: node.id };
1003
+ }
1004
+ } catch (condErr) {
1005
+ console.error(`[WF][${node.id}] condition eval error: ${condErr.message}`);
1006
+ throw condErr;
1007
+ }
1008
+ }
677
1009
  const startedAt = Date.now();
678
1010
  let stepId;
679
1011
  if (trackingStore && runId) {
@@ -687,7 +1019,8 @@ function createAgentNode(node, resolveAgent, trackingStore) {
687
1019
  console.log(`[WF][${node.id}] START "${node.name}" | hasSchema=${!!node.output?.schema}`);
688
1020
  const responseFormat = node.output?.schema;
689
1021
  console.log(`[WF][${node.id}] resolving agent...`);
690
- const client = await resolveAgent(node.ref, responseFormat, node.type);
1022
+ const stepType = node.ask ? "ask" : node.type;
1023
+ const client = await resolveAgent(node.ref, responseFormat, stepType);
691
1024
  console.log(`[WF][${node.id}] agent resolved, building input...`);
692
1025
  const input = buildInput(
693
1026
  node.input,
@@ -695,16 +1028,32 @@ function createAgentNode(node, resolveAgent, trackingStore) {
695
1028
  void 0,
696
1029
  responseFormat ? void 0 : node.output?.schema
697
1030
  );
1031
+ if (node.ask) {
1032
+ input.messages = [
1033
+ new import_messages5.SystemMessage(
1034
+ "Follow this exact procedure. Do NOT skip any step.\n\nSTEP 1: Read the prompt. It contains content to present to the user and a question to ask.\n\nSTEP 2: Call ask_user_to_clarify. Your question text MUST contain the ACTUAL content from the prompt.\n\nSTEP 3: The tool will pause. The user will see your questions and respond. You will receive their answers.\n\nSTEP 4: Based on the user's answers, produce your final output."
1035
+ ),
1036
+ ...input.messages
1037
+ ];
1038
+ }
698
1039
  const renderedInput = input.messages[0]?.content ?? "";
699
1040
  console.log(`[WF][${node.id}] === INPUT (full) ===
700
1041
  ${renderedInput}
701
1042
  === END INPUT ===`);
1043
+ const subConfig = {
1044
+ ...config,
1045
+ configurable: {
1046
+ ...config?.configurable ?? {},
1047
+ thread_id: `${config?.configurable?.thread_id ?? "default"}:${node.id}`
1048
+ }
1049
+ };
702
1050
  if (trackingStore && runId) {
703
1051
  const step = await trackingStore.upsertRunStep({
704
1052
  runId,
705
1053
  tenantId,
706
1054
  stepType: node.type,
707
1055
  stepName: node.name,
1056
+ threadId: subConfig.configurable.thread_id,
708
1057
  input: { template: node.input?.template, rendered: renderedInput }
709
1058
  }).catch((e) => {
710
1059
  console.warn("Failed to upsert run step:", e.message);
@@ -716,13 +1065,6 @@ ${renderedInput}
716
1065
  });
717
1066
  }
718
1067
  }
719
- const subConfig = {
720
- ...config,
721
- configurable: {
722
- ...config?.configurable ?? {},
723
- thread_id: `${config?.configurable?.thread_id ?? "default"}:${node.id}`
724
- }
725
- };
726
1068
  let result;
727
1069
  try {
728
1070
  console.log(`[WF][${node.id}] invoking agent.invoke()...`);
@@ -819,157 +1161,40 @@ ${JSON.stringify(output, null, 2)}
819
1161
  }
820
1162
  };
821
1163
  }
822
- function createHumanFeedbackNode(node, resolveAgent, trackingStore) {
1164
+ function createMapNode(node, resolveAgent, trackingStore) {
823
1165
  return async (state, config) => {
824
1166
  const runId = state._runId;
825
1167
  const tenantId = config?.configurable?.tenantId ?? "default";
826
- const startedAt = Date.now();
827
- let stepId;
828
- if (trackingStore && runId) {
829
- trackingStore.updateWorkflowRun(runId, {
830
- status: "running",
831
- completedAt: null
832
- }).catch(() => {
833
- });
834
- }
835
- try {
836
- console.log(`[WF][${node.id}] HUMAN_FEEDBACK START "${node.config?.title || node.name}"`);
837
- const responseFormat = node.output?.schema;
838
- const client = await resolveAgent(void 0, responseFormat, node.type);
839
- console.log(`[WF][${node.id}] agent resolved, building input...`);
840
- const input = buildInput(
841
- node.input,
842
- state,
843
- void 0,
844
- responseFormat ? void 0 : node.output?.schema
845
- );
846
- const humanContent = input.messages[0]?.content ?? "";
847
- input.messages = [
848
- new import_messages6.SystemMessage(
849
- `Follow this exact procedure. Do NOT skip any step.
850
-
851
- STEP 1: Read the prompt. It contains content to present to the user and a question to ask.
852
-
853
- STEP 2: Call ask_user_to_clarify. Your question text MUST contain the ACTUAL content from the prompt \u2014 copy-paste the relevant text, data, or facts directly into the question. A question like "Do you approve this recommendation?" is WRONG because the user has no idea what the recommendation says. Instead: "Do you approve this recommendation: [paste the actual recommendation text here]?"
854
-
855
- STEP 3: The tool will pause. The user will see your questions and respond. You will receive their answers.
856
-
857
- STEP 4: Based on the user's answers, produce your final output.`
858
- ),
859
- ...input.messages
860
- ];
861
- const renderedInput = humanContent;
862
- if (trackingStore && runId) {
863
- const step = await trackingStore.upsertRunStep({
864
- runId,
865
- tenantId,
866
- stepType: node.type,
867
- stepName: node.name,
868
- input: { template: node.input?.template, rendered: renderedInput }
869
- }).catch((e) => {
870
- console.warn("Failed to upsert run step:", e.message);
871
- return null;
872
- });
873
- stepId = step?.id;
874
- if (step && step.status === "interrupted") {
875
- trackingStore.updateRunStep(runId, step.id, { status: "running" }).catch(() => {
876
- });
877
- }
878
- }
879
- const subConfig = {
880
- ...config,
881
- configurable: {
882
- ...config?.configurable ?? {},
883
- thread_id: `${config?.configurable?.thread_id ?? "default"}:${node.id}`
884
- }
885
- };
886
- console.log(`[WF][${node.id}] === INPUT (full) ===
887
- ${renderedInput}
888
- === END INPUT ===`);
889
- const result = await invokeWithRetry(
890
- () => client.invoke(input, subConfig),
891
- node.config?.maxRetries ?? 0,
892
- node.config?.retryOn,
893
- node.config?.timeout
894
- );
895
- console.log(`[WF][${node.id}] invoke SUCCESS, extracting output...`);
896
- const output = extractOutput(result);
897
- console.log(`[WF][${node.id}] === OUTPUT (full) | key=${node.output?.key} ===
898
- ${JSON.stringify(output, null, 2)}
899
- === END OUTPUT ===`);
900
- const update = { phase: node.id };
901
- if (node.output?.key) {
902
- update[node.output.key] = output;
903
- }
904
- if (output && typeof output === "object" && !Array.isArray(output)) {
905
- Object.assign(update, output);
906
- }
907
- const subMessages = result.messages;
908
- if (subMessages && Array.isArray(subMessages)) {
909
- const aiMessages = subMessages.filter((m) => {
910
- const t = typeof m._getType === "function" ? m._getType() : m.role ?? m.type;
911
- return t === "ai";
912
- });
913
- if (aiMessages.length > 0) {
914
- update.messages = aiMessages;
915
- }
916
- }
917
- console.log(`[WF][${node.id}] DONE (${Date.now() - startedAt}ms)`);
918
- if (trackingStore && runId && stepId) {
919
- trackingStore.updateRunStep(runId, stepId, {
920
- status: "completed",
921
- output,
922
- completedAt: /* @__PURE__ */ new Date(),
923
- durationMs: Date.now() - startedAt
924
- }).catch((e) => {
925
- console.warn("Failed to update run step:", e.message);
926
- });
927
- }
928
- return update;
929
- } catch (err) {
930
- if (err?.name === "GraphInterrupt") {
931
- if (trackingStore && runId && stepId) {
932
- trackingStore.updateRunStep(runId, stepId, {
933
- status: "interrupted"
934
- }).catch(() => {
935
- });
936
- }
937
- if (trackingStore && runId) {
938
- trackingStore.updateWorkflowRun(runId, {
939
- status: "interrupted",
940
- completedAt: null
941
- }).catch(() => {
942
- });
1168
+ if (node.condition) {
1169
+ try {
1170
+ validateExpression(node.condition);
1171
+ const safeExpr = toSafeStateExpr(node.condition);
1172
+ const fn = new Function("state", `try { return ${safeExpr}; } catch { return false; }`);
1173
+ const shouldRun = fn(state);
1174
+ if (!shouldRun) {
1175
+ console.log(`[WF][${node.id}] condition false, skipping map "${node.name}" (${node.condition})`);
1176
+ if (trackingStore && runId) {
1177
+ const step = await trackingStore.upsertRunStep({
1178
+ runId,
1179
+ tenantId,
1180
+ stepType: node.type,
1181
+ stepName: node.name
1182
+ }).catch(() => null);
1183
+ if (step) {
1184
+ await trackingStore.updateRunStep(runId, step.id, {
1185
+ status: "skipped",
1186
+ completedAt: /* @__PURE__ */ new Date()
1187
+ }).catch(() => {
1188
+ });
1189
+ }
1190
+ }
1191
+ return { phase: node.id };
943
1192
  }
944
- throw err;
1193
+ } catch (condErr) {
1194
+ console.error(`[WF][${node.id}] condition eval error: ${condErr.message}`);
1195
+ throw condErr;
945
1196
  }
946
- if (trackingStore && runId) {
947
- if (stepId) {
948
- trackingStore.updateRunStep(runId, stepId, {
949
- status: "failed",
950
- errorMessage: err.message,
951
- completedAt: /* @__PURE__ */ new Date(),
952
- durationMs: Date.now() - startedAt
953
- }).catch((e) => {
954
- console.warn("Failed to update run step:", e.message);
955
- });
956
- }
957
- trackingStore.updateWorkflowRun(runId, {
958
- status: "failed",
959
- errorMessage: err.message,
960
- completedAt: /* @__PURE__ */ new Date()
961
- }).catch((e) => {
962
- console.warn("Failed to finalize WorkflowRun:", e.message);
963
- });
964
- }
965
- throw err;
966
1197
  }
967
- };
968
- }
969
- function createMapNode(node, resolveAgent, trackingStore) {
970
- return async (state, config) => {
971
- const runId = state._runId;
972
- const tenantId = config?.configurable?.tenantId ?? "default";
973
1198
  const startedAt = Date.now();
974
1199
  let stepId;
975
1200
  if (trackingStore && runId) {
@@ -1156,368 +1381,77 @@ function createTerminalNode(node, trackingStore) {
1156
1381
  try {
1157
1382
  await trackingStore.updateWorkflowRun(runId, {
1158
1383
  status: runStatus,
1159
- completedAt: /* @__PURE__ */ new Date()
1160
- });
1161
- } catch (e) {
1162
- console.warn(`[WF][terminal] Failed to finalize WorkflowRun "${runId}":`, e.message);
1163
- }
1164
- try {
1165
- await trackingStore.createRunStep({
1166
- runId,
1167
- tenantId: state._tenantId ?? "default",
1168
- stepType: "terminal",
1169
- stepName: node.name,
1170
- input: { status: node.status }
1171
- });
1172
- } catch (e) {
1173
- console.warn(`[WF][terminal] Failed to create terminal RunStep:`, e.message);
1174
- }
1175
- }
1176
- return {
1177
- status: node.status,
1178
- phase: node.id
1179
- };
1180
- };
1181
- }
1182
- function createNodeHandler(node, resolveAgent, trackingStore) {
1183
- switch (node.type) {
1184
- case "agent":
1185
- return createAgentNode(node, resolveAgent, trackingStore);
1186
- case "human_feedback":
1187
- return createHumanFeedbackNode(node, resolveAgent, trackingStore);
1188
- case "map":
1189
- return createMapNode(node, resolveAgent, trackingStore);
1190
- case "terminal":
1191
- return createTerminalNode(node, trackingStore);
1192
- case "input":
1193
- return createInputNode(node, trackingStore);
1194
- default:
1195
- throw new Error(`Unknown node type: ${node.type}`);
1196
- }
1197
- }
1198
- function chunk(arr, size) {
1199
- const result = [];
1200
- for (let i = 0; i < arr.length; i += size) {
1201
- result.push(arr.slice(i, i + size));
1202
- }
1203
- return result;
1204
- }
1205
- var import_langgraph15, import_messages6;
1206
- var init_utils = __esm({
1207
- "src/workflow/utils.ts"() {
1208
- "use strict";
1209
- import_langgraph15 = require("@langchain/langgraph");
1210
- import_messages6 = require("@langchain/core/messages");
1211
- }
1212
- });
1213
-
1214
- // src/workflow/normalize.ts
1215
- function uid(prefix) {
1216
- return `${prefix}_${_counter++}`;
1217
- }
1218
- function nodeId(stepId) {
1219
- return `n_${stepId}`;
1220
- }
1221
- function translate(template) {
1222
- return template.replace(/\{\{([^}]+)\}\}/g, (_m, expr) => {
1223
- const t = expr.trim();
1224
- if (t === "item") return "${item}";
1225
- return `\${state.${t}}`;
1226
- });
1227
- }
1228
- function inferFieldType(id) {
1229
- if (/s$|list|array|items|results/i.test(id)) return { type: "array", default: [] };
1230
- return { type: "string" };
1231
- }
1232
- function expandStep(step) {
1233
- switch (step.type ?? "agent") {
1234
- case "agent":
1235
- return expandAgent(step);
1236
- case "human":
1237
- return expandHuman(step);
1238
- case "condition":
1239
- return expandCondition(step);
1240
- case "map":
1241
- return expandMap(step);
1242
- case "parallel":
1243
- return expandParallel(step);
1244
- case "end":
1245
- return expandEnd(step);
1246
- }
1247
- }
1248
- function validateSchema(schema, stepId) {
1249
- if (schema.type !== "object") {
1250
- throw new Error(
1251
- `Step "${stepId}": schema.type must be "object", got "${String(schema.type)}". Use standard JSON Schema: { "type": "object", "properties": { ... } }`
1252
- );
1253
- }
1254
- if (!schema.properties || typeof schema.properties !== "object") {
1255
- throw new Error(
1256
- `Step "${stepId}": schema must have a "properties" object. Legacy shorthand like { "field": "string" } is not supported. Use: { "type": "object", "properties": { "field": { "type": "string" } } }`
1257
- );
1258
- }
1259
- }
1260
- function expandAgent(s) {
1261
- const sid = s.id || uid("agent");
1262
- const nid = nodeId(sid);
1263
- if (s.schema !== void 0 && s.schema !== null) {
1264
- if (typeof s.schema !== "object") {
1265
- throw new Error(
1266
- `Step "${sid}": schema must be a JSON Schema object, e.g. { "type": "object", "properties": { ... } }. Got ${typeof s.schema} (${JSON.stringify(s.schema)}).`
1267
- );
1268
- }
1269
- validateSchema(s.schema, sid);
1270
- }
1271
- const schema = s.schema && typeof s.schema === "object" ? s.schema : void 0;
1272
- console.log(`[WF EXPAND] agent step id="${sid}" nodeId="${nid}" | hasSchema=${!!schema}`);
1273
- return {
1274
- nodes: [{ id: nid, type: "agent", name: sid, input: { template: translate(s.prompt) }, output: { key: sid, ...schema ? { schema } : {} } }],
1275
- edges: [],
1276
- entryId: nid,
1277
- exitIds: [nid]
1278
- };
1279
- }
1280
- function expandHuman(s) {
1281
- const sid = s.id || uid("human");
1282
- const nid = nodeId(sid);
1283
- if (s.schema !== void 0 && s.schema !== null) {
1284
- if (typeof s.schema !== "object") {
1285
- throw new Error(
1286
- `Step "${sid}": schema must be a JSON Schema object, e.g. { "type": "object", "properties": { ... } }. Got ${typeof s.schema} (${JSON.stringify(s.schema)}).`
1287
- );
1288
- }
1289
- validateSchema(s.schema, sid);
1290
- }
1291
- const schema = s.schema && typeof s.schema === "object" ? s.schema : void 0;
1292
- return {
1293
- nodes: [{ id: nid, type: "human_feedback", name: sid, config: { title: s.title ?? sid }, input: { template: translate(s.prompt) }, output: { key: sid, ...schema ? { schema } : {} } }],
1294
- edges: [],
1295
- entryId: nid,
1296
- exitIds: [nid]
1297
- };
1298
- }
1299
- function expandCondition(s) {
1300
- const sid = s.id || uid("cond");
1301
- const nid = nodeId(sid);
1302
- if (s.branches) {
1303
- const branchExps = {};
1304
- for (const [key, steps] of Object.entries(s.branches)) {
1305
- branchExps[key] = expandSteps(Array.isArray(steps) ? steps : [steps]);
1306
- }
1307
- const allNodes = Object.values(branchExps).flatMap((e) => e.nodes);
1308
- const allEdges = Object.values(branchExps).flatMap((e) => e.edges);
1309
- const allExitIds = [...new Set(Object.values(branchExps).flatMap((e) => e.exitIds))];
1310
- const branchEntryIds = Object.fromEntries(
1311
- Object.entries(branchExps).map(([k, v]) => [k, v.entryId])
1312
- );
1313
- return {
1314
- nodes: allNodes,
1315
- edges: allEdges,
1316
- entryId: nid,
1317
- exitIds: allExitIds,
1318
- branchEntryIds
1319
- };
1320
- }
1321
- if (!s.then) {
1322
- throw new Error(`Condition step "${sid}": must have either "then" or "branches"`);
1323
- }
1324
- const thenSteps = Array.isArray(s.then) ? s.then : [s.then];
1325
- const elseSteps = s.else ? Array.isArray(s.else) ? s.else : [s.else] : [];
1326
- const thenExp = expandSteps(thenSteps);
1327
- const elseExp = expandSteps(elseSteps);
1328
- return {
1329
- nodes: [...thenExp.nodes, ...elseExp.nodes],
1330
- edges: [...thenExp.edges, ...elseExp.edges],
1331
- entryId: nid,
1332
- exitIds: [...thenExp.exitIds, ...elseExp.exitIds],
1333
- thenEntryId: thenExp.entryId,
1334
- elseEntryId: elseExp.entryId
1335
- };
1336
- }
1337
- function expandMap(s) {
1338
- const sid = s.id;
1339
- const nid = nodeId(sid);
1340
- const inner = s.each;
1341
- return {
1342
- nodes: [{
1343
- id: nid,
1344
- type: "map",
1345
- name: sid,
1346
- source: `state.${s.source}`,
1347
- itemKey: "item",
1348
- config: { batchSize: s.batch ?? 50, maxConcurrency: s.concurrency ?? 5, innerConcurrency: s.concurrency ?? 5 },
1349
- node: { type: "agent", input: inner.prompt ? { template: translate(inner.prompt) } : void 0, ...inner.schema && typeof inner.schema === "object" ? { schema: inner.schema } : {} },
1350
- ...s.reduce ? { reduce: { input: s.reduce.prompt ? { template: translate(s.reduce.prompt) } : void 0, ...s.reduce.schema && typeof s.reduce.schema === "object" ? { schema: s.reduce.schema } : {} } } : {},
1351
- output: { key: sid }
1352
- }],
1353
- edges: [],
1354
- entryId: nid,
1355
- exitIds: [nid]
1356
- };
1357
- }
1358
- function expandParallel(s) {
1359
- const nodes = [];
1360
- const edges = [];
1361
- const entryIds = [];
1362
- const exitIds = [];
1363
- for (const step of s.steps) {
1364
- const exp = expandStep(step);
1365
- nodes.push(...exp.nodes);
1366
- edges.push(...exp.edges);
1367
- entryIds.push(exp.entryId);
1368
- if (exp.exitIds.length > 0) exitIds.push(...exp.exitIds);
1369
- }
1370
- return { nodes, edges, entryId: entryIds[0], exitIds };
1371
- }
1372
- function expandEnd(s) {
1373
- const sid = uid("end");
1374
- const nid = nodeId(sid);
1375
- return { nodes: [{ id: nid, type: "terminal", name: sid, status: s.status ?? "success" }], edges: [], entryId: nid, exitIds: [] };
1376
- }
1377
- function expandSteps(steps, fromStart = false) {
1378
- if (steps.length === 0) return { nodes: [], edges: [], entryId: "END", exitIds: ["END"] };
1379
- const allNodes = [];
1380
- const allEdges = [];
1381
- let prevExitIds = [];
1382
- let firstEntryId = null;
1383
- for (let i = 0; i < steps.length; i++) {
1384
- const exp = expandStep(steps[i]);
1385
- if (exp.nodes.length > 0) allNodes.push(...exp.nodes);
1386
- if (exp.edges.length > 0) allEdges.push(...exp.edges);
1387
- if (firstEntryId === null) firstEntryId = exp.entryId;
1388
- if (prevExitIds.length > 0) addEdge(steps[i], exp, prevExitIds, allEdges);
1389
- else if (fromStart && i === 0) addEdge(steps[i], exp, ["START"], allEdges);
1390
- prevExitIds = exp.exitIds.length > 0 ? exp.exitIds : prevExitIds;
1391
- }
1392
- return { nodes: allNodes, edges: allEdges, entryId: firstEntryId || "END", exitIds: prevExitIds };
1393
- }
1394
- function toSafeStateExpr(expr) {
1395
- const match = expr.match(/^([a-zA-Z_][a-zA-Z0-9_-]*)/);
1396
- if (!match) return `state.${expr}`;
1397
- const field = match[0];
1398
- const rest = expr.slice(field.length);
1399
- return `state["${field}"]${rest}`;
1400
- }
1401
- function addEdge(step, exp, fromIds, allEdges) {
1402
- if (step.type === "condition") {
1403
- const s = step;
1404
- if (s.if.includes("{{")) {
1405
- throw new Error(
1406
- `Condition step "${s.id || "unnamed"}": the \`if\` field contains "{{". Use a plain state field name or JavaScript expression (e.g. "intent", "score >= 60"). Template markers {{...}} are only for \`prompt\` fields, not \`if\`. Found: "${s.if}"`
1407
- );
1408
- }
1409
- if (s.branches) {
1410
- const condExp = exp;
1411
- const exprCode = toSafeStateExpr(s.if);
1412
- const mapping = {};
1413
- for (const [key, branchId] of Object.entries(condExp.branchEntryIds)) {
1414
- if (branchId) mapping[key] = branchId;
1415
- }
1416
- for (const fromId of fromIds) allEdges.push({ from: fromId, type: "conditional", rule: { type: "expression", code: exprCode, mapping } });
1417
- } else {
1418
- const condExp = exp;
1419
- const exprCode = `${toSafeStateExpr(s.if)} ? 'then' : 'else'`;
1420
- const mapping = {};
1421
- if (condExp.thenEntryId) mapping.then = condExp.thenEntryId;
1422
- if (condExp.elseEntryId) mapping.else = condExp.elseEntryId;
1423
- for (const fromId of fromIds) allEdges.push({ from: fromId, type: "conditional", rule: { type: "expression", code: exprCode, mapping } });
1424
- }
1425
- } else if (step.type === "parallel") {
1426
- for (const fromId of fromIds) {
1427
- for (const sub of step.steps) allEdges.push({ from: fromId, to: expandStep(sub).entryId });
1428
- }
1429
- } else {
1430
- for (const fromId of fromIds) allEdges.push({ from: fromId, to: exp.entryId });
1431
- }
1432
- }
1433
- function collectIds(steps) {
1434
- const ids = [];
1435
- function walk(s) {
1436
- const id = s.type === "condition" ? s.id || uid("cond") : s.type === "parallel" ? s.id || uid("par") : s.type === "end" ? uid("end") : s.id || s.id || uid("human");
1437
- if (s.type !== "end" && s.type !== "condition") ids.push(id);
1438
- if (s.type === "condition") {
1439
- const c = s;
1440
- if (c.branches) {
1441
- for (const steps2 of Object.values(c.branches)) {
1442
- (Array.isArray(steps2) ? steps2 : [steps2]).forEach(walk);
1443
- }
1444
- } else {
1445
- (Array.isArray(c.then) ? c.then : [c.then]).forEach(walk);
1446
- if (c.else) (Array.isArray(c.else) ? c.else : [c.else]).forEach(walk);
1384
+ completedAt: /* @__PURE__ */ new Date()
1385
+ });
1386
+ } catch (e) {
1387
+ console.warn(`[WF][terminal] Failed to finalize WorkflowRun "${runId}":`, e.message);
1447
1388
  }
1448
- }
1449
- if (s.type === "parallel") s.steps.forEach(walk);
1450
- }
1451
- steps.forEach(walk);
1452
- return [...new Set(ids)];
1453
- }
1454
- function collectSourceIds(steps) {
1455
- const ids = [];
1456
- function walk(s) {
1457
- if (s.type === "map") ids.push(s.source);
1458
- if (s.type === "condition") {
1459
- const c = s;
1460
- if (c.branches) {
1461
- for (const steps2 of Object.values(c.branches)) {
1462
- (Array.isArray(steps2) ? steps2 : [steps2]).forEach(walk);
1463
- }
1464
- } else {
1465
- (Array.isArray(c.then) ? c.then : [c.then]).forEach(walk);
1466
- if (c.else) (Array.isArray(c.else) ? c.else : [c.else]).forEach(walk);
1389
+ try {
1390
+ await trackingStore.createRunStep({
1391
+ runId,
1392
+ tenantId: state._tenantId ?? "default",
1393
+ stepType: "terminal",
1394
+ stepName: node.name,
1395
+ input: { status: node.status }
1396
+ });
1397
+ } catch (e) {
1398
+ console.warn(`[WF][terminal] Failed to create terminal RunStep:`, e.message);
1467
1399
  }
1468
1400
  }
1469
- if (s.type === "parallel") s.steps.forEach(walk);
1401
+ return {
1402
+ status: node.status,
1403
+ phase: node.id
1404
+ };
1405
+ };
1406
+ }
1407
+ function createNodeHandler(node, resolveAgent, trackingStore) {
1408
+ switch (node.type) {
1409
+ case "agent":
1410
+ return createAgentNode(node, resolveAgent, trackingStore);
1411
+ case "map":
1412
+ return createMapNode(node, resolveAgent, trackingStore);
1413
+ case "terminal":
1414
+ return createTerminalNode(node, trackingStore);
1415
+ case "input":
1416
+ return createInputNode(node, trackingStore);
1417
+ default:
1418
+ throw new Error(`Unknown node type: ${node.type}`);
1470
1419
  }
1471
- steps.forEach(walk);
1472
- return [...new Set(ids)];
1473
1420
  }
1474
- function expand(dsl) {
1475
- _counter = 0;
1476
- console.log(`[WF EXPAND] expanding workflow "${dsl.name}" | stepCount=${dsl.steps.length}`);
1477
- const inputNode = {
1478
- id: "n_input",
1479
- type: "input",
1480
- name: "input",
1481
- output: { key: "input" }
1482
- };
1483
- const expanded = expandSteps(dsl.steps, true);
1484
- const edges = expanded.entryId === "END" ? [{ from: "START", to: "n_input" }] : [
1485
- ...expanded.edges.map((e) => ({ ...e, from: e.from === "START" ? "n_input" : e.from })),
1486
- { from: "START", to: "n_input" }
1487
- ];
1488
- const nodes = [inputNode, ...expanded.nodes];
1489
- const ids = collectIds(dsl.steps);
1490
- const sourceIds = collectSourceIds(dsl.steps);
1491
- const fields = { input: { type: "string" } };
1492
- for (const id of ids) fields[id] = inferFieldType(id);
1493
- for (const id of sourceIds) {
1494
- if (!fields[id]) fields[id] = inferFieldType(id);
1421
+ function chunk(arr, size) {
1422
+ const result = [];
1423
+ for (let i = 0; i < arr.length; i += size) {
1424
+ result.push(arr.slice(i, i + size));
1495
1425
  }
1496
- const result = { version: "1.0", name: dsl.name, state: { fields }, nodes, edges };
1497
- console.log(`[WF EXPAND] done | nodeCount=${result.nodes.length} | nodeIds=[${result.nodes.map((n) => `${n.id}:${n.type}`).join(", ")}] | fieldIds=[${Object.keys(fields).join(", ")}]`);
1498
1426
  return result;
1499
1427
  }
1500
- var _counter;
1501
- var init_normalize = __esm({
1502
- "src/workflow/normalize.ts"() {
1428
+ var import_langgraph14, import_messages5;
1429
+ var init_utils = __esm({
1430
+ "src/workflow/utils.ts"() {
1503
1431
  "use strict";
1504
- _counter = 0;
1432
+ import_langgraph14 = require("@langchain/langgraph");
1433
+ import_messages5 = require("@langchain/core/messages");
1434
+ init_parse_yaml();
1505
1435
  }
1506
1436
  });
1507
1437
 
1508
1438
  // src/workflow/compile.ts
1509
1439
  var compile_exports = {};
1510
1440
  __export(compile_exports, {
1441
+ compileInternal: () => compileInternal,
1511
1442
  compileWorkflow: () => compileWorkflow,
1512
1443
  validateDSL: () => validateDSL
1513
1444
  });
1514
- function compileWorkflow(dsl, resolveAgent, checkpointer, trackingStore) {
1515
- console.log(`[WF COMPILE] compiling "${dsl.name}" | stepCount=${dsl.steps.length}`);
1516
- const ir = expand(dsl);
1445
+ function compileWorkflow(yamlStr, resolveAgent, checkpointer, trackingStore) {
1446
+ console.log(`[WF COMPILE] compiling YAML workflow`);
1447
+ const ir = parseYaml(yamlStr);
1448
+ return compileInternal(ir, resolveAgent, checkpointer, trackingStore);
1449
+ }
1450
+ function compileInternal(ir, resolveAgent, checkpointer, trackingStore) {
1517
1451
  validateAndThrow(ir);
1518
1452
  console.log(`[WF COMPILE] validation passed`);
1519
1453
  const StateAnnotation = buildStateAnnotation(ir.state?.fields);
1520
- const builder = new import_langgraph16.StateGraph(StateAnnotation);
1454
+ const builder = new import_langgraph15.StateGraph(StateAnnotation);
1521
1455
  for (const node of ir.nodes) {
1522
1456
  console.log(`[WF COMPILE] registering node: id=${node.id} type=${node.type} name=${node.name}`);
1523
1457
  const handler = createNodeHandler(node, resolveAgent, trackingStore);
@@ -1525,26 +1459,18 @@ function compileWorkflow(dsl, resolveAgent, checkpointer, trackingStore) {
1525
1459
  }
1526
1460
  for (const node of ir.nodes) {
1527
1461
  if (node.type === "terminal") {
1528
- builder.addEdge(node.id, import_langgraph16.END);
1462
+ builder.addEdge(node.id, import_langgraph15.END);
1529
1463
  }
1530
1464
  }
1531
1465
  for (const edge of ir.edges) {
1532
- const from = edge.from === "START" ? import_langgraph16.START : edge.from;
1533
- if (edge.type === "conditional") {
1534
- if (!edge.rule) {
1535
- throw new Error(`Conditional edge from "${edge.from}" has no rule`);
1536
- }
1537
- const router = buildRouter(edge.rule);
1538
- builder.addConditionalEdges(from, router, edge.rule.mapping);
1539
- } else {
1540
- const targets = Array.isArray(edge.to) ? edge.to : [edge.to];
1541
- for (const to of targets) {
1542
- builder.addEdge(from, to === "END" ? import_langgraph16.END : to);
1543
- }
1466
+ const from = edge.from === "START" ? import_langgraph15.START : edge.from;
1467
+ const targets = Array.isArray(edge.to) ? edge.to : [edge.to];
1468
+ for (const to of targets) {
1469
+ builder.addEdge(from, to === "END" ? import_langgraph15.END : to);
1544
1470
  }
1545
1471
  }
1546
1472
  const graph = builder.compile({ checkpointer, name: ir.name });
1547
- console.log(`[WF COMPILE] graph compiled successfully, ready to run`);
1473
+ console.log(`[WF COMPILE] graph compiled successfully`);
1548
1474
  return graph;
1549
1475
  }
1550
1476
  function validateDSL(dsl) {
@@ -1559,7 +1485,6 @@ function validateDSL(dsl) {
1559
1485
  const terminalIds = new Set(
1560
1486
  dsl.nodes.filter((n) => n.type === "terminal").map((n) => n.id)
1561
1487
  );
1562
- const declaredFields = new Set(Object.keys(dsl.state?.fields ?? {}));
1563
1488
  for (const edge of dsl.edges) {
1564
1489
  if (edge.from !== "START" && !nodeIds.has(edge.from)) {
1565
1490
  errors.push({ type: "error", message: `Edge from "${edge.from}" references unknown node` });
@@ -1573,24 +1498,12 @@ function validateDSL(dsl) {
1573
1498
  errors.push({ type: "error", message: `Edge to "${to}" references unknown node` });
1574
1499
  }
1575
1500
  }
1576
- if (edge.type === "conditional" && edge.rule) {
1577
- for (const targetId of Object.values(edge.rule.mapping)) {
1578
- if (targetId !== "END" && !nodeIds.has(targetId)) {
1579
- errors.push({ type: "error", message: `Conditional edge mapping references unknown node "${targetId}"` });
1580
- }
1581
- }
1582
- if (edge.rule.type === "state_field" && edge.rule.field) {
1583
- if (!declaredFields.has(edge.rule.field)) {
1584
- errors.push({ type: "warning", message: `Conditional edge reads "${edge.rule.field}" but it is not declared in state.fields` });
1585
- }
1586
- }
1587
- }
1588
1501
  }
1589
1502
  for (const node of dsl.nodes) {
1590
1503
  if (node.type === "terminal") {
1591
1504
  const hasIncoming = dsl.edges.some((e) => {
1592
1505
  const targets = Array.isArray(e.to) ? e.to : e.to ? [e.to] : [];
1593
- return targets.includes(node.id) || e.type === "conditional" && e.rule && Object.values(e.rule.mapping).includes(node.id);
1506
+ return targets.includes(node.id);
1594
1507
  });
1595
1508
  if (!hasIncoming) {
1596
1509
  errors.push({ type: "warning", message: `Terminal node "${node.id}" has no incoming edge` });
@@ -1606,41 +1519,13 @@ function validateAndThrow(dsl) {
1606
1519
  throw new Error(critical.map((e) => e.message).join("; "));
1607
1520
  }
1608
1521
  }
1609
- function buildRouter(rule) {
1610
- if (rule.type === "state_field") {
1611
- if (!rule.field) throw new Error("state_field rule requires a field name");
1612
- return (state) => {
1613
- const value = resolvePath(state, `state.${rule.field}`);
1614
- const key = String(value);
1615
- if (rule.mapping[key] !== void 0) return key;
1616
- if (rule.mapping["default"] !== void 0) return "default";
1617
- throw new Error(
1618
- `Conditional router produced key "${key}" (from field "${rule.field}"), but it is not in mapping: ${JSON.stringify(Object.keys(rule.mapping))}`
1619
- );
1620
- };
1621
- }
1622
- if (rule.type === "expression") {
1623
- if (!rule.code) throw new Error("expression rule requires code");
1624
- const fn = new Function("state", `return ${rule.code}`);
1625
- return (state) => {
1626
- const value = fn(state);
1627
- const key = String(value);
1628
- if (rule.mapping[key] !== void 0) return key;
1629
- if (rule.mapping["default"] !== void 0) return "default";
1630
- throw new Error(
1631
- `Conditional router produced key "${key}" (from expression "${rule.code}"), but it is not in mapping: ${JSON.stringify(Object.keys(rule.mapping))}`
1632
- );
1633
- };
1634
- }
1635
- throw new Error(`Unknown rule type: ${rule.type}`);
1636
- }
1637
- var import_langgraph16;
1522
+ var import_langgraph15;
1638
1523
  var init_compile = __esm({
1639
1524
  "src/workflow/compile.ts"() {
1640
1525
  "use strict";
1641
- import_langgraph16 = require("@langchain/langgraph");
1526
+ import_langgraph15 = require("@langchain/langgraph");
1642
1527
  init_utils();
1643
- init_normalize();
1528
+ init_parse_yaml();
1644
1529
  }
1645
1530
  });
1646
1531
 
@@ -1669,7 +1554,7 @@ __export(index_exports, {
1669
1554
  EmbeddingsLatticeManager: () => EmbeddingsLatticeManager,
1670
1555
  FileSystemSkillStore: () => FileSystemSkillStore,
1671
1556
  FilesystemBackend: () => FilesystemBackend,
1672
- HumanMessage: () => import_messages7.HumanMessage,
1557
+ HumanMessage: () => import_messages6.HumanMessage,
1673
1558
  InMemoryA2AApiKeyStore: () => InMemoryA2AApiKeyStore,
1674
1559
  InMemoryAssistantStore: () => InMemoryAssistantStore,
1675
1560
  InMemoryBindingStore: () => InMemoryBindingStore,
@@ -1677,7 +1562,9 @@ __export(index_exports, {
1677
1562
  InMemoryChunkBuffer: () => InMemoryChunkBuffer,
1678
1563
  InMemoryDatabaseConfigStore: () => InMemoryDatabaseConfigStore,
1679
1564
  InMemoryMailboxStore: () => InMemoryMailboxStore,
1565
+ InMemoryMenuStore: () => InMemoryMenuStore,
1680
1566
  InMemoryTaskListStore: () => InMemoryTaskListStore,
1567
+ InMemoryTaskStore: () => InMemoryTaskStore,
1681
1568
  InMemoryTenantStore: () => InMemoryTenantStore,
1682
1569
  InMemoryThreadMessageQueueStore: () => InMemoryThreadMessageQueueStore,
1683
1570
  InMemoryThreadStore: () => InMemoryThreadStore,
@@ -1699,6 +1586,7 @@ __export(index_exports, {
1699
1586
  MicrosandboxServiceClient: () => MicrosandboxServiceClient,
1700
1587
  ModelLatticeManager: () => ModelLatticeManager,
1701
1588
  MysqlDatabase: () => MysqlDatabase,
1589
+ PersonalAssistantConfig: () => PersonalAssistantConfig,
1702
1590
  PinoLoggerClient: () => PinoLoggerClient,
1703
1591
  PostgresDatabase: () => PostgresDatabase,
1704
1592
  PrometheusClient: () => PrometheusClient,
@@ -1735,14 +1623,15 @@ __export(index_exports, {
1735
1623
  buildStateAnnotation: () => buildStateAnnotation,
1736
1624
  checkEmptyContent: () => checkEmptyContent,
1737
1625
  clearEncryptionKeyCache: () => clearEncryptionKeyCache,
1626
+ compileInternal: () => compileInternal,
1738
1627
  compileWorkflow: () => compileWorkflow,
1739
1628
  computeSandboxName: () => computeSandboxName,
1740
1629
  configureStores: () => configureStores,
1630
+ connectAllChannels: () => connectAllChannels,
1741
1631
  createAgentNode: () => createAgentNode,
1742
1632
  createAgentTeam: () => createAgentTeam,
1743
1633
  createExecuteSqlQueryTool: () => createExecuteSqlQueryTool,
1744
1634
  createFileData: () => createFileData,
1745
- createHumanFeedbackNode: () => createHumanFeedbackNode,
1746
1635
  createInfoSqlTool: () => createInfoSqlTool,
1747
1636
  createListMetricsDataSourcesTool: () => createListMetricsDataSourcesTool,
1748
1637
  createListMetricsServersTool: () => createListMetricsServersTool,
@@ -1760,9 +1649,9 @@ __export(index_exports, {
1760
1649
  createQueryTablesListTool: () => createQueryTablesListTool,
1761
1650
  createSandboxProvider: () => createSandboxProvider,
1762
1651
  createSchedulerMiddleware: () => createSchedulerMiddleware,
1652
+ createTaskMiddleware: () => createTaskMiddleware,
1763
1653
  createTeamMiddleware: () => createTeamMiddleware,
1764
1654
  createTeammateTools: () => createTeammateTools,
1765
- createTerminalNode: () => createTerminalNode,
1766
1655
  createUnknownToolHandlerMiddleware: () => createUnknownToolHandlerMiddleware,
1767
1656
  createWidgetMiddleware: () => createWidgetMiddleware,
1768
1657
  decrypt: () => decrypt,
@@ -1772,7 +1661,6 @@ __export(index_exports, {
1772
1661
  ensureBuiltinAgentsForTenant: () => ensureBuiltinAgentsForTenant,
1773
1662
  eventBus: () => eventBus,
1774
1663
  eventBusDefault: () => event_bus_default,
1775
- expand: () => expand,
1776
1664
  extractFetcherError: () => extractFetcherError,
1777
1665
  extractOutput: () => extractOutput,
1778
1666
  fileDataToString: () => fileDataToString,
@@ -1795,6 +1683,7 @@ __export(index_exports, {
1795
1683
  getEmbeddingsLattice: () => getEmbeddingsLattice,
1796
1684
  getEncryptionKey: () => getEncryptionKey,
1797
1685
  getLoggerLattice: () => getLoggerLattice,
1686
+ getMenuRegistry: () => getMenuRegistry,
1798
1687
  getModelLattice: () => getModelLattice,
1799
1688
  getNextCronTime: () => getNextCronTime,
1800
1689
  getQueueLattice: () => getQueueLattice,
@@ -1824,6 +1713,7 @@ __export(index_exports, {
1824
1713
  parallelLimit: () => parallelLimit,
1825
1714
  parseCronExpression: () => parseCronExpression,
1826
1715
  parseSkillFrontmatter: () => parseSkillFrontmatter,
1716
+ parseYaml: () => parseYaml,
1827
1717
  performStringReplacement: () => performStringReplacement,
1828
1718
  queueLatticeManager: () => queueLatticeManager,
1829
1719
  registerAgentLattice: () => registerAgentLattice,
@@ -1847,9 +1737,12 @@ __export(index_exports, {
1847
1737
  sanitizeToolCallId: () => sanitizeToolCallId,
1848
1738
  scheduleLatticeManager: () => scheduleLatticeManager,
1849
1739
  setBindingRegistry: () => setBindingRegistry,
1740
+ setMenuRegistry: () => setMenuRegistry,
1850
1741
  skillLatticeManager: () => skillLatticeManager,
1851
1742
  sqlDatabaseManager: () => sqlDatabaseManager,
1852
1743
  storeLatticeManager: () => storeLatticeManager,
1744
+ toJsonSchema: () => toJsonSchema,
1745
+ toSafeStateExpr: () => toSafeStateExpr,
1853
1746
  toolLatticeManager: () => toolLatticeManager,
1854
1747
  truncateIfTooLong: () => truncateIfTooLong,
1855
1748
  unregisterTeammateAgent: () => unregisterTeammateAgent,
@@ -1986,9 +1879,11 @@ var ModelLattice = class extends import_chat_models.BaseChatModel {
1986
1879
  maxRetries: config.maxRetries || 2,
1987
1880
  apiKey: config.apiKey || process.env[config.apiKeyEnvName || "SILICONCLOUD_API_KEY"],
1988
1881
  configuration: {
1989
- baseURL: "https://api.siliconflow.cn/v1"
1882
+ baseURL: config.baseURL || "https://api.siliconflow.cn/v1"
1990
1883
  },
1991
- streaming: config.streaming
1884
+ streaming: config.streaming,
1885
+ modelKwargs: config.modelKwargs,
1886
+ ...config.extra || {}
1992
1887
  });
1993
1888
  } else if (config.provider === "volcengine") {
1994
1889
  return new import_openai.ChatOpenAI({
@@ -2271,11 +2166,11 @@ var ToolLatticeManager = class _ToolLatticeManager extends BaseLatticeManager {
2271
2166
  * @param key Lattice键名
2272
2167
  * @param tool 已有的StructuredTool实例
2273
2168
  */
2274
- registerExistingTool(key, tool51) {
2169
+ registerExistingTool(key, tool52) {
2275
2170
  const config = {
2276
- name: tool51.name,
2277
- description: tool51.description,
2278
- schema: tool51.schema,
2171
+ name: tool52.name,
2172
+ description: tool52.description,
2173
+ schema: tool52.schema,
2279
2174
  // StructuredTool的schema已经是Zod兼容的
2280
2175
  needUserApprove: false
2281
2176
  // MCP工具默认不需要用户批准
@@ -2283,7 +2178,7 @@ var ToolLatticeManager = class _ToolLatticeManager extends BaseLatticeManager {
2283
2178
  const toolLattice = {
2284
2179
  key,
2285
2180
  config,
2286
- client: tool51
2181
+ client: tool52
2287
2182
  };
2288
2183
  this.register(key, toolLattice);
2289
2184
  }
@@ -2309,7 +2204,7 @@ var ToolLatticeManager = class _ToolLatticeManager extends BaseLatticeManager {
2309
2204
  };
2310
2205
  var toolLatticeManager = ToolLatticeManager.getInstance();
2311
2206
  var registerToolLattice = (key, config, executor) => toolLatticeManager.registerLattice(key, config, executor);
2312
- var registerExistingTool = (key, tool51) => toolLatticeManager.registerExistingTool(key, tool51);
2207
+ var registerExistingTool = (key, tool52) => toolLatticeManager.registerExistingTool(key, tool52);
2313
2208
  var getToolLattice = (key) => toolLatticeManager.getToolLattice(key);
2314
2209
  var getToolDefinition = (key) => toolLatticeManager.getToolDefinition(key);
2315
2210
  var getToolClient = (key) => toolLatticeManager.getToolClient(key);
@@ -2579,6 +2474,7 @@ var InMemoryAssistantStore = class {
2579
2474
  name: data.name,
2580
2475
  description: data.description,
2581
2476
  graphDefinition: data.graphDefinition,
2477
+ ownerUserId: data.ownerUserId,
2582
2478
  createdAt: now,
2583
2479
  updatedAt: now
2584
2480
  };
@@ -2625,6 +2521,17 @@ var InMemoryAssistantStore = class {
2625
2521
  }
2626
2522
  return tenantAssistants.has(id);
2627
2523
  }
2524
+ /**
2525
+ * Get assistant by owner user ID
2526
+ */
2527
+ async getByOwner(tenantId, userId) {
2528
+ const tenantAssistants = this.assistants.get(tenantId);
2529
+ if (!tenantAssistants) return null;
2530
+ for (const assistant of tenantAssistants.values()) {
2531
+ if (assistant.ownerUserId === userId) return assistant;
2532
+ }
2533
+ return null;
2534
+ }
2628
2535
  /**
2629
2536
  * Clear all assistants for a tenant (useful for testing)
2630
2537
  */
@@ -3857,7 +3764,7 @@ var InMemoryThreadMessageQueueStore = class {
3857
3764
  return this.messages.get(threadId);
3858
3765
  }
3859
3766
  async addMessage(params) {
3860
- const { threadId, tenantId, assistantId, content, type = "human", priority = 0, command, custom_run_config, id } = params;
3767
+ const { threadId, tenantId, assistantId, workspaceId, projectId, content, type = "human", priority = 0, command, custom_run_config, id } = params;
3861
3768
  const threadMessages = this.getMessagesForThread(threadId);
3862
3769
  const message = {
3863
3770
  id: id || this.generateId(),
@@ -3868,6 +3775,8 @@ var InMemoryThreadMessageQueueStore = class {
3868
3775
  status: "pending",
3869
3776
  tenantId,
3870
3777
  assistantId,
3778
+ workspaceId,
3779
+ projectId,
3871
3780
  priority,
3872
3781
  command,
3873
3782
  custom_run_config
@@ -3876,7 +3785,7 @@ var InMemoryThreadMessageQueueStore = class {
3876
3785
  return message;
3877
3786
  }
3878
3787
  async addMessageAtHead(params) {
3879
- const { threadId, tenantId, assistantId, content, type = "system", id, command, custom_run_config } = params;
3788
+ const { threadId, tenantId, assistantId, workspaceId, projectId, content, type = "system", id, command, custom_run_config } = params;
3880
3789
  const threadMessages = this.getMessagesForThread(threadId);
3881
3790
  let resolvedTenantId = tenantId || "default";
3882
3791
  let resolvedAssistantId = assistantId || "";
@@ -3894,6 +3803,8 @@ var InMemoryThreadMessageQueueStore = class {
3894
3803
  status: "pending",
3895
3804
  tenantId: resolvedTenantId,
3896
3805
  assistantId: resolvedAssistantId,
3806
+ workspaceId,
3807
+ projectId,
3897
3808
  priority: 100,
3898
3809
  // High priority for head messages (STEER/Command)
3899
3810
  command,
@@ -3925,7 +3836,9 @@ var InMemoryThreadMessageQueueStore = class {
3925
3836
  result.push({
3926
3837
  tenantId: firstMessage.tenantId || "default",
3927
3838
  assistantId: firstMessage.assistantId || "",
3928
- threadId
3839
+ threadId,
3840
+ workspaceId: firstMessage.workspaceId || void 0,
3841
+ projectId: firstMessage.projectId || void 0
3929
3842
  });
3930
3843
  }
3931
3844
  }
@@ -4048,6 +3961,7 @@ var InMemoryWorkflowTrackingStore = class {
4048
3961
  tenantId: request.tenantId,
4049
3962
  stepType: request.stepType,
4050
3963
  stepName: request.stepName,
3964
+ threadId: request.threadId,
4051
3965
  edgeFrom: request.edgeFrom,
4052
3966
  edgeTo: request.edgeTo,
4053
3967
  edgePurpose: request.edgePurpose,
@@ -4067,7 +3981,12 @@ var InMemoryWorkflowTrackingStore = class {
4067
3981
  const existing = runSteps.find(
4068
3982
  (s) => s.stepType === request.stepType && s.stepName === request.stepName
4069
3983
  );
4070
- if (existing) return existing;
3984
+ if (existing) {
3985
+ if (!existing.threadId && request.threadId) {
3986
+ existing.threadId = request.threadId;
3987
+ }
3988
+ return existing;
3989
+ }
4071
3990
  return this.createRunStep(request);
4072
3991
  }
4073
3992
  async updateRunStep(runId, stepId, updates) {
@@ -4126,6 +4045,11 @@ var InMemoryChannelInstallationStore = class {
4126
4045
  (inst) => inst.tenantId === tenantId && (!channel || inst.channel === channel)
4127
4046
  );
4128
4047
  }
4048
+ async getAllInstallations(channel) {
4049
+ return Array.from(this.installations.values()).filter(
4050
+ (inst) => !channel || inst.channel === channel
4051
+ );
4052
+ }
4129
4053
  /**
4130
4054
  * Creates a new channel installation for a tenant.
4131
4055
  *
@@ -4402,6 +4326,107 @@ var InMemoryA2AApiKeyStore = class {
4402
4326
  }
4403
4327
  };
4404
4328
 
4329
+ // src/store_lattice/InMemoryTaskStore.ts
4330
+ var import_uuid = require("uuid");
4331
+ var InMemoryTaskStore = class {
4332
+ constructor() {
4333
+ this.tasks = /* @__PURE__ */ new Map();
4334
+ }
4335
+ /**
4336
+ * Create a new task
4337
+ */
4338
+ async create(params) {
4339
+ if (!this.tasks.has(params.tenantId)) {
4340
+ this.tasks.set(params.tenantId, /* @__PURE__ */ new Map());
4341
+ }
4342
+ const now = /* @__PURE__ */ new Date();
4343
+ const task = {
4344
+ id: (0, import_uuid.v4)(),
4345
+ tenantId: params.tenantId,
4346
+ ownerType: params.ownerType,
4347
+ ownerId: params.ownerId,
4348
+ title: params.title,
4349
+ description: params.description,
4350
+ status: params.status || "pending",
4351
+ priority: params.priority || "medium",
4352
+ dueDate: params.dueDate,
4353
+ metadata: params.metadata,
4354
+ parentId: params.parentId,
4355
+ sourceId: params.sourceId,
4356
+ context: params.context,
4357
+ createdAt: now,
4358
+ updatedAt: now
4359
+ };
4360
+ this.tasks.get(params.tenantId).set(task.id, task);
4361
+ return task;
4362
+ }
4363
+ /**
4364
+ * Get task by ID
4365
+ */
4366
+ async getById(tenantId, id) {
4367
+ const tenantTasks = this.tasks.get(tenantId);
4368
+ if (!tenantTasks) return null;
4369
+ return tenantTasks.get(id) || null;
4370
+ }
4371
+ /**
4372
+ * List tasks matching filter criteria
4373
+ */
4374
+ async list(filter2) {
4375
+ const tenantTasks = this.tasks.get(filter2.tenantId);
4376
+ if (!tenantTasks) return [];
4377
+ let results = Array.from(tenantTasks.values());
4378
+ if (filter2.ownerType) results = results.filter((t) => t.ownerType === filter2.ownerType);
4379
+ if (filter2.ownerId) results = results.filter((t) => t.ownerId === filter2.ownerId);
4380
+ if (filter2.status) results = results.filter((t) => t.status === filter2.status);
4381
+ if (filter2.priority) results = results.filter((t) => t.priority === filter2.priority);
4382
+ if (filter2.parentId) results = results.filter((t) => t.parentId === filter2.parentId);
4383
+ if (filter2.sourceId) results = results.filter((t) => t.sourceId === filter2.sourceId);
4384
+ if (filter2.metadata) {
4385
+ for (const [key, value] of Object.entries(filter2.metadata)) {
4386
+ results = results.filter((t) => t.metadata?.[key] === value);
4387
+ }
4388
+ }
4389
+ results.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
4390
+ const offset = filter2.offset || 0;
4391
+ const limit = filter2.limit || 100;
4392
+ return results.slice(offset, offset + limit);
4393
+ }
4394
+ /**
4395
+ * Update an existing task
4396
+ */
4397
+ async update(tenantId, id, updates) {
4398
+ const tenantTasks = this.tasks.get(tenantId);
4399
+ if (!tenantTasks) return null;
4400
+ const existing = tenantTasks.get(id);
4401
+ if (!existing) return null;
4402
+ const updated = {
4403
+ ...existing,
4404
+ ...updates,
4405
+ updatedAt: /* @__PURE__ */ new Date()
4406
+ };
4407
+ tenantTasks.set(id, updated);
4408
+ return updated;
4409
+ }
4410
+ /**
4411
+ * Delete a task by ID
4412
+ */
4413
+ async delete(tenantId, id) {
4414
+ const tenantTasks = this.tasks.get(tenantId);
4415
+ if (!tenantTasks) return false;
4416
+ return tenantTasks.delete(id);
4417
+ }
4418
+ /**
4419
+ * Clear all tasks for a tenant (useful for testing)
4420
+ */
4421
+ clear(tenantId) {
4422
+ if (tenantId) {
4423
+ this.tasks.delete(tenantId);
4424
+ } else {
4425
+ this.tasks.clear();
4426
+ }
4427
+ }
4428
+ };
4429
+
4405
4430
  // src/store_lattice/StoreLatticeManager.ts
4406
4431
  var StoreLatticeManager = class _StoreLatticeManager extends BaseLatticeManager {
4407
4432
  /**
@@ -4582,6 +4607,12 @@ storeLatticeManager.registerLattice(
4582
4607
  "a2aApiKey",
4583
4608
  defaultA2AApiKeyStore
4584
4609
  );
4610
+ var defaultTaskStore = new InMemoryTaskStore();
4611
+ storeLatticeManager.registerLattice(
4612
+ "default",
4613
+ "task",
4614
+ defaultTaskStore
4615
+ );
4585
4616
 
4586
4617
  // src/tool_lattice/manage_binding/index.ts
4587
4618
  function getInstallationStore() {
@@ -4593,7 +4624,7 @@ var manageBindingSchema = import_zod3.default.object({
4593
4624
  channelInstallationId: import_zod3.default.string().optional().describe("Channel installation ID (auto-detected if omitted and only one exists for this channel)"),
4594
4625
  senderId: import_zod3.default.string().optional().describe("Sender identifier (email address, Lark openId, Slack userId)"),
4595
4626
  agentId: import_zod3.default.string().optional().describe("Target agent ID to route messages to"),
4596
- threadMode: import_zod3.default.enum(["fixed", "per_conversation"]).optional().default("per_conversation").describe("Thread mode: per_conversation (recommended) or fixed"),
4627
+ threadMode: import_zod3.default.enum(["fixed", "per_conversation"]).optional().default("per_conversation").describe("Thread mode (ignored when channel adapter has its own thread strategy, e.g. Lark)"),
4597
4628
  senderDisplayName: import_zod3.default.string().optional().describe("Human-readable name for the sender")
4598
4629
  });
4599
4630
  registerToolLattice(
@@ -4602,9 +4633,13 @@ registerToolLattice(
4602
4633
  name: "manage_binding",
4603
4634
  description: `Manage sender-to-agent bindings for external channels (email, Lark, Slack).
4604
4635
 
4636
+ 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.
4637
+
4638
+ 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.
4639
+
4605
4640
  - list_installations: List available channel installations. Filter by channel type (optional). Use this first to discover available channelInstallationIds.
4606
- - 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.
4607
- - update: Update an existing binding. Required: channel, senderId. Optional: agentId, threadMode (default: per_conversation), senderDisplayName.
4641
+ - create: Bind a sender to an agent. Required: channel, senderId, agentId. Optional: threadMode. channelInstallationId auto-detected if only one exists.
4642
+ - update: Update an existing binding. Required: channel, senderId. Optional: agentId, threadMode, senderDisplayName.
4608
4643
  - delete: Remove a binding. Required: channel, senderId.
4609
4644
  - list: List all bindings. Optional: channel, agentId, channelInstallationId.
4610
4645
 
@@ -4612,7 +4647,7 @@ A sender can only be bound to ONE agent per channel+installation combination.`,
4612
4647
  schema: manageBindingSchema
4613
4648
  },
4614
4649
  async (input, config) => {
4615
- const registry2 = getBindingRegistry();
4650
+ const registry3 = getBindingRegistry();
4616
4651
  const runConfig = config?.configurable?.runConfig || {};
4617
4652
  const tenantId = runConfig.tenantId || "default";
4618
4653
  switch (input.action) {
@@ -4635,7 +4670,7 @@ A sender can only be bound to ONE agent per channel+installation combination.`,
4635
4670
  error: `No channelInstallationId provided and unable to auto-detect. Use action=list_installations to find available installations for channel "${input.channel}".`
4636
4671
  });
4637
4672
  }
4638
- const binding = await registry2.create({
4673
+ const binding = await registry3.create({
4639
4674
  channel: input.channel,
4640
4675
  channelInstallationId: installId,
4641
4676
  tenantId,
@@ -4657,7 +4692,7 @@ A sender can only be bound to ONE agent per channel+installation combination.`,
4657
4692
  error: `No channelInstallationId provided and unable to auto-detect. Use action=list_installations first.`
4658
4693
  });
4659
4694
  }
4660
- const existing = await registry2.resolve({
4695
+ const existing = await registry3.resolve({
4661
4696
  channel: input.channel,
4662
4697
  senderId: input.senderId,
4663
4698
  channelInstallationId: installId,
@@ -4666,7 +4701,7 @@ A sender can only be bound to ONE agent per channel+installation combination.`,
4666
4701
  if (!existing) {
4667
4702
  return JSON.stringify({ success: false, error: "Binding not found" });
4668
4703
  }
4669
- const updated = await registry2.update(existing.id, {
4704
+ const updated = await registry3.update(existing.id, {
4670
4705
  agentId: input.agentId,
4671
4706
  threadMode: input.threadMode,
4672
4707
  senderDisplayName: input.senderDisplayName
@@ -4684,7 +4719,7 @@ A sender can only be bound to ONE agent per channel+installation combination.`,
4684
4719
  error: `No channelInstallationId provided and unable to auto-detect.`
4685
4720
  });
4686
4721
  }
4687
- const existing = await registry2.resolve({
4722
+ const existing = await registry3.resolve({
4688
4723
  channel: input.channel,
4689
4724
  senderId: input.senderId,
4690
4725
  channelInstallationId: installId,
@@ -4693,11 +4728,11 @@ A sender can only be bound to ONE agent per channel+installation combination.`,
4693
4728
  if (!existing) {
4694
4729
  return JSON.stringify({ success: false, error: "Binding not found" });
4695
4730
  }
4696
- await registry2.delete(existing.id);
4731
+ await registry3.delete(existing.id);
4697
4732
  return JSON.stringify({ success: true, message: "Binding deleted" });
4698
4733
  }
4699
4734
  case "list": {
4700
- const bindings = await registry2.list({
4735
+ const bindings = await registry3.list({
4701
4736
  channel: input.channel,
4702
4737
  agentId: input.agentId,
4703
4738
  tenantId,
@@ -8672,7 +8707,7 @@ var createBrowserGetInfoTool = ({ vmIsolation }) => {
8672
8707
  };
8673
8708
 
8674
8709
  // src/index.ts
8675
- var import_messages7 = require("@langchain/core/messages");
8710
+ var import_messages6 = require("@langchain/core/messages");
8676
8711
 
8677
8712
  // src/agent_lattice/types.ts
8678
8713
  var import_protocols = require("@axiom-lattice/protocols");
@@ -8691,7 +8726,7 @@ var createReactAgentSchema = (schema) => {
8691
8726
  };
8692
8727
 
8693
8728
  // src/agent_lattice/builders/ReActAgentGraphBuilder.ts
8694
- var import_langchain56 = require("langchain");
8729
+ var import_langchain57 = require("langchain");
8695
8730
 
8696
8731
  // src/middlewares/codeEvalMiddleware.ts
8697
8732
  var import_langchain37 = require("langchain");
@@ -9162,353 +9197,233 @@ metadata:
9162
9197
  Then iterate based on what the user says.
9163
9198
  `,
9164
9199
  "create-workflow": `---
9165
- name: create-workflow
9166
- description: Design and build multi-step AI workflows using the concise Workflow DSL. Use whenever users want to orchestrate agents in a pipeline, build process automation with branching/parallel logic, design approval flows with human-in-the-loop, or process data in stages.
9167
- license: MIT
9168
- metadata:
9169
- category: meta
9170
- version: "3.0"
9171
- ---
9172
-
9173
- # Workflow Designer
9174
-
9175
- This skill guides you through designing and creating workflow agents. A workflow is a LangGraph state machine compiled from a concise JSON DSL \u2014 steps define what happens, order defines the flow, and the engine handles the rest.
9176
-
9177
- Every step runs on the workflow's built-in general-purpose agent \u2014 no external agent registration needed.
9178
-
9179
- ## Core Principle: id is everything
9200
+ name: create-workflow
9201
+ 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.
9202
+ license: MIT
9203
+ metadata:
9204
+ category: meta
9205
+ version: "5.0"
9206
+ ---
9180
9207
 
9181
- A step's \`id\` serves triple duty:
9182
- 1. **Node identifier** in the graph
9183
- 2. **State key** \u2014 output is stored at \`state.<id>\`
9184
- 3. **Template reference** \u2014 downstream steps use \`{{id}}\` to read it
9208
+ # YAML Workflow Designer
9185
9209
 
9186
- If you omit \`id\`, a unique identifier is auto-generated (but you won't be able to reference the output).
9210
+ Use the linear YAML DSL \u2014 steps execute top-to-bottom. Use \`parallel:\` for concurrency. No dependency graph thinking required.
9187
9211
 
9188
- ## Step Types
9212
+ ## Core Model: Linear + Parallel
9189
9213
 
9190
- ### agent \u2014 a step for the workflow's built-in agent
9214
+ - **Linear** \u2014 steps execute in written order. No \`needs\`, no dependency declarations.
9215
+ - **parallel** \u2014 a block where all children run concurrently. Block completes when all children finish.
9216
+ - **if** \u2014 JS expression. Step runs only when truthy. Omit to always run.
9217
+ - **prompt** \u2014 agent instruction with **{{label}}** refs. **{{input}}** is the user message.
9218
+ - **output** \u2014 shorthand schema using **{ field: type }** notation.
9219
+ - **ask** \u2014 boolean. Injects user clarification middleware for human interaction.
9191
9220
 
9192
- \`\`\`json
9193
- { "id": "classify", "name": "Classify Intent", "prompt": "Classify the intent of: {{input}}", "schema": { "type": "object", "properties": { "intent": { "type": "string" } } } }
9194
- \`\`\`
9221
+ ## When to Use parallel vs map
9195
9222
 
9196
- | Field | Required | Description |
9197
- |-------|----------|-------------|
9198
- | id | no | State key for referencing output. Auto-generated if omitted, but required if downstream steps reference this step via \`{{id}}\` |
9199
- | name | no | Human-readable label for this step |
9200
- | prompt | yes | Task description with {{id}} refs |
9201
- | schema | **yes** | Standard JSON Schema ONLY: \`{ "type": "object", "properties": { "field": { "type": "string" } } }\`. \`true\` is REJECTED \u2014 must be a concrete schema. Legacy shorthand \`{ "field": "string" }\` is REJECTED.
9223
+ This is the most important design decision. **They are fundamentally different:**
9202
9224
 
9203
- **Schema Rules (MUST follow \u2014 shorthand is rejected):**
9204
- - Always wrap in \`{ "type": "object", "properties": { ... } }\`
9205
- - Each property must be \`{ "type": "string"|"number"|"boolean"|"array"|"object" }\`
9206
- - Arrays need \`"items"\`: \`{ "type": "array", "items": { "type": "string" } }\`
9207
- - \u274C \`{ "field": "string" }\` \u2014 REJECTED (no "type"/"properties" wrapper)
9208
- - \u274C \`{ "schema": { "intent": "string" } }\` \u2014 REJECTED (legacy shorthand)
9225
+ | | parallel | map |
9226
+ |---|---|---|
9227
+ | **Concern** | **Business parallelism** \u2014 reduce business processing time | **Data parallelism** \u2014 handle data volume |
9228
+ | **Tasks** | Each child does a **different** task | All items do the **same** task |
9229
+ | **Count** | Few (2-5), each hand-written | Dynamic, driven by source data |
9230
+ | **Input** | Independent prompts per child | Single \`each.prompt\` template, \`{{item}}\` for current element |
9231
+ | **if** | Per-child conditional | Whole block conditional |
9232
+ | **Example** | Legal review + Market analysis in parallel | Audit each line item in an invoice |
9209
9233
 
9210
- The agent's response is stored at \`state.<id>\` (or an auto-generated key if \`id\` is omitted).
9234
+ **Rule of thumb:** If you're writing the same prompt twice, you probably want \`map\`. If each branch has a unique purpose, use \`parallel\`.
9211
9235
 
9212
- ### condition \u2014 branch on state
9236
+ ## Step Format
9213
9237
 
9214
- **Binary (then/else):**
9238
+ ### Agent Step
9215
9239
 
9216
- \`\`\`json
9217
- { "type": "condition", "if": "intent",
9218
- "then": { "id": "support", "name": "Handle Support", "prompt": "Handle support: {{input}}" },
9219
- "else": { "id": "sales", "name": "Handle Sales", "prompt": "Handle sales: {{input}}" }
9220
- }
9240
+ \`\`\`yaml
9241
+ - label:
9242
+ prompt: instruction with {{refs}}
9243
+ if: "expression"
9244
+ output: { field: type }
9245
+ ask: true
9221
9246
  \`\`\`
9222
9247
 
9223
- | Field | Required | Description |
9224
- |-------|----------|-------------|
9225
- | if | yes | State field name (e.g. "approved") or expression (e.g. "score >= 60"). **CRITICAL: \`{{}}\` is FORBIDDEN in \`if\`** \u2014 it is a plain JavaScript expression, not a template. \u274C \`"if": "{{intent}}"\` is WRONG. \u2705 \`"if": "intent"\` is correct. |
9226
- | then | yes | Step(s) to run when condition is truthy |
9227
- | else | no | Step(s) to run when condition is falsy |
9228
-
9229
- The engine evaluates \`if\` as a JavaScript expression prefixed with \`state.\`. Both \`then\` and \`else\` can be a single step or an array of steps. After both branches, execution rejoins at the next step after the condition.
9230
-
9231
- **Switch (branches):**
9248
+ ### Parallel Block
9232
9249
 
9233
- When branching on a discrete set of known values, use \`branches\` for cleaner multi-way routing:
9234
-
9235
- \`\`\`json
9236
- { "type": "condition", "if": "intent",
9237
- "branches": {
9238
- "support": { "id": "support", "prompt": "Handle support: {{input}}" },
9239
- "sales": { "id": "sales", "prompt": "Handle sales: {{input}}" },
9240
- "billing": { "id": "billing", "prompt": "Handle billing: {{input}}" },
9241
- "default": { "id": "fallback", "prompt": "Send to human: {{input}}" }
9242
- }
9243
- }
9250
+ \`\`\`yaml
9251
+ - parallel:
9252
+ - child1:
9253
+ prompt: ...
9254
+ if: "expression"
9255
+ - child2:
9256
+ prompt: ...
9244
9257
  \`\`\`
9245
9258
 
9246
- | Field | Required | Description |
9247
- |-------|----------|-------------|
9248
- | if | yes | State field whose STRING VALUE is matched against branch keys. **Same rule \u2014 \`{{}}\` is FORBIDDEN here.** |
9249
- | branches | yes | Map of value \u2192 step(s). \`"default"\` key is a catch-all for unmatched values |
9250
- | then/else | no | Not used when branches is present |
9251
-
9252
- Unlike \`then\`/\`else\` (truthy/falsy ternary), \`branches\` does exact string match against the state field value. Always include a \`"default"\` branch.
9259
+ Parallel children are agent steps only. No nested parallel or map inside parallel.
9253
9260
 
9254
- ### human \u2014 pause for human input
9261
+ ### Map Step
9255
9262
 
9256
- The human step invokes an agent with ask_user_to_clarify middleware. The agent is a **facilitator** \u2014 it presents information to the user and collects their response. The agent does NOT make decisions itself; it asks the user. The agent's structured output is stored under the step's \`id\`.
9257
-
9258
- \`\`\`json
9259
- { "id": "review", "type": "human",
9260
- "title": "Approval",
9261
- "prompt": "Present the following draft to the user for approval. Ask whether to approve or reject, and collect any comments.\\n\\nDraft:\\n{{draft}}",
9262
- "schema": { "type": "object", "properties": { "approved": { "type": "boolean" }, "comments": { "type": "string" } } }
9263
- }
9263
+ \`\`\`yaml
9264
+ - label:
9265
+ map:
9266
+ source: "extract.items"
9267
+ if: "extract.items.length > 0"
9268
+ each:
9269
+ prompt: Process {{item}}
9270
+ output: { result: string }
9271
+ batch: 50
9272
+ concurrency: 5
9264
9273
  \`\`\`
9265
9274
 
9266
- Access results with dot notation: \`{{review.approved}}\`, \`{{review.comments}}\`. Use \`schema\` to constrain the agent's output.
9267
-
9268
- | Field | Required | Description |
9269
- |-------|----------|-------------|
9270
- | id | no | State key for the agent's structured output |
9271
- | type | yes | Must be \`"human"\` |
9272
- | prompt | yes | Tell the agent what to present to the user and what to ask. The agent is a facilitator \u2014 write instructions like "Present X to the user and ask Y", NOT "You are a reviewer. Review X..." |
9273
- | title | no | Display label for the human step |
9274
- | schema | no | JSON Schema constraining the agent's structured output format |
9275
-
9276
- ### map \u2014 iterate over an array
9275
+ ## Schema Shorthand
9277
9276
 
9278
- \`\`\`json
9279
- { "id": "results", "type": "map",
9280
- "source": "items",
9281
- "each": { "prompt": "Audit: {{item}}", "schema": { "type": "object", "properties": { "result": { "type": "string" } } } },
9282
- "batch": 10, "concurrency": 3
9283
- }
9284
- \`\`\`
9285
-
9286
- | Field | Required | Description |
9287
- |-------|----------|-------------|
9288
- | id | yes | Output key for the results array |
9289
- | source | yes | id of the step whose output is the array to iterate |
9290
- | each | yes | Step applied to each element. Use {{item}} for the current element |
9291
- | reduce | no | Step to aggregate results |
9292
- | batch | no | Items per batch (default 50) |
9293
- | concurrency | no | Max parallel items (default 5) |
9277
+ Write **{ field: type }** instead of JSON Schema:
9294
9278
 
9295
- ### parallel \u2014 fixed fan-out
9279
+ | Shorthand | Meaning |
9280
+ |-----------|---------|
9281
+ | **field: string** | string property |
9282
+ | **field: number** | number property |
9283
+ | **field: boolean** | boolean property |
9284
+ | **field: string[]** | array of strings |
9285
+ | **field: number[]** | array of numbers |
9286
+ | **field: [{ a: string, b: number }]** | array of objects |
9287
+ | **field: { sub: string }** | nested object |
9296
9288
 
9297
- \`\`\`json
9298
- { "type": "parallel", "steps": [
9299
- { "id": "legal", "prompt": "Legal review: {{input}}" },
9300
- { "id": "finance", "prompt": "Finance: {{input}}" }
9301
- ]}
9302
- \`\`\`
9289
+ Use **block style** (each field on its own line). Flow style \`{ field: "type" }\` with quoted values also works.
9303
9290
 
9304
- All steps run simultaneously. After all complete, execution continues to the next step.
9291
+ ## Template Syntax
9305
9292
 
9306
- ### end \u2014 terminate the workflow
9293
+ | Syntax | Resolves to |
9294
+ |--------|------------|
9295
+ | \`{{input}}\` | Initial user message |
9296
+ | \`{{label}}\` | Full output of step |
9297
+ | \`{{label.field}}\` | Nested field access |
9298
+ | \`{{item}}\` | Current element in map iteration |
9307
9299
 
9308
- \`\`\`json
9309
- { "type": "end" }
9310
- \`\`\`
9300
+ ## Design Patterns
9311
9301
 
9312
- Always include at the end of the steps array. \`status\` defaults to "success".
9302
+ ### Linear Pipeline
9313
9303
 
9314
- **Number of terminal nodes:**
9315
-
9316
- - **Every workflow MUST have at least one \`{ "type": "end" }\`** \u2014 without it, the graph hangs at the last node.
9317
- - **One is enough** even for complex workflows: all branches can converge to a single \`end\` node (parallel fan-in, condition branches rejoining, etc.).
9318
- - **Use multiple end nodes ONLY when different branches need different \`status\`** values \u2014 e.g., success path vs failure path:
9319
-
9320
- \`\`\`json
9321
- { "type": "condition", "if": "score >= 60",
9322
- "then": { "type": "end", "status": "success" },
9323
- "else": { "type": "end", "status": "failed" }
9324
- }
9325
- \`\`\`
9326
-
9327
- - If all outcomes share the same final status, use a single \`end\` node after the condition/parallel block \u2014 the engine automatically converges all paths to it.
9328
-
9329
- ## Template Syntax
9330
-
9331
- | Syntax | Resolves to | When to use |
9332
- |--------|------------|-------------|
9333
- | \`{{input}}\` | Initial user message | First step or any step needing the original question |
9334
- | \`{{id}}\` | Output of step with given id | Referencing any upstream step's result |
9335
- | \`{{item}}\` | Current element in map iteration | Inside map \`each.prompt\` |
9304
+ \`\`\`yaml
9305
+ steps:
9306
+ - extract:
9307
+ prompt: Extract data from {{input}}
9308
+ - transform:
9309
+ prompt: Transform {{extract}}
9310
+ - final:
9311
+ prompt: Combine raw {{extract}} with transformed {{transform}}
9312
+ \`\`\`
9336
9313
 
9337
- ## \u26A0\uFE0F CRITICAL: \`{{}}\` is ONLY for \`prompt\` fields
9314
+ ### Classify -> Route via Parallel + if
9338
9315
 
9339
- The template markers \`{{id}}\`, \`{{input}}\`, and \`{{item}}\` work **exclusively inside \`prompt\` strings**. All other string fields \u2014 including \`if\`, \`source\`, \`id\`, \`name\`, \`title\`, \`status\` \u2014 must use plain values without any \`{{}}\` wrapping.
9316
+ \`\`\`yaml
9317
+ steps:
9318
+ - classify:
9319
+ prompt: Classify intent from {{input}}
9320
+ output:
9321
+ intent: string
9322
+ urgency: number
9323
+ - parallel:
9324
+ - billing:
9325
+ if: "classify.intent == 'billing'"
9326
+ prompt: Handle billing: {{input}}
9327
+ ask: true
9328
+ - technical:
9329
+ if: "classify.intent == 'technical'"
9330
+ prompt: Handle technical: {{input}}
9331
+ - escalate:
9332
+ if: "classify.urgency >= 8"
9333
+ prompt: Urgent handling
9334
+ ask: true
9335
+ \`\`\`
9340
9336
 
9341
- **Common mistake the AI makes:**
9342
- \`\`\`json
9343
- // \u274C WRONG \u2014 {{}} does not belong in if:
9344
- { "type": "condition", "if": "{{intent}}", "then": {...}, "else": {...} }
9337
+ ### Parallel Processing
9345
9338
 
9346
- // \u2705 CORRECT \u2014 if is a plain expression:
9347
- { "type": "condition", "if": "intent", "then": {...}, "else": {...} }
9348
- \`\`\`
9339
+ \`\`\`yaml
9340
+ steps:
9341
+ - gather:
9342
+ prompt: Gather data from {{input}}
9343
+ - parallel:
9344
+ - legal:
9345
+ prompt: Legal analysis of {{gather}}
9346
+ output:
9347
+ risk: string
9348
+ compliant: boolean
9349
+ - market:
9350
+ prompt: Market analysis of {{gather}}
9351
+ output:
9352
+ opportunity: string
9353
+ score: number
9354
+ - report:
9355
+ prompt: |
9356
+ Synthesize findings:
9357
+ Legal: {{legal}}
9358
+ Market: {{market}}
9359
+ \`\`\`
9349
9360
 
9350
- ## What You NEVER Write
9361
+ ### Approval Flow with Human
9351
9362
 
9352
- The engine auto-generates these \u2014 do NOT include them in your DSL:
9363
+ \`\`\`yaml
9364
+ steps:
9365
+ - draft:
9366
+ prompt: Draft response to {{input}}
9367
+ - review:
9368
+ prompt: Present {{draft}} to user for approval
9369
+ output:
9370
+ approved: boolean
9371
+ comments: string
9372
+ ask: true
9373
+ - publish:
9374
+ if: "review.approved"
9375
+ prompt: Publish {{draft}}
9376
+ - revise:
9377
+ if: "!review.approved"
9378
+ prompt: Revise based on {{review.comments}}
9379
+ \`\`\`
9353
9380
 
9354
- - **state.fields** \u2014 auto-declared from every \`id\`
9355
- - **edges** \u2014 auto-generated from step order (linear) and types (fan-out for parallel, conditional for condition)
9356
- - **output.key** \u2014 always equals \`id\`
9357
- - **version** \u2014 always "1.0" internally
9358
- - **node IDs** \u2014 prefixed internally to avoid conflicts with state channel names
9359
- - **human step type** \u2014 the human step has ask_user_to_clarify built-in. Use \`{ "type": "human", ... }\` in the DSL for user interaction. Do NOT manually add ask_user_to_clarify middleware to regular agent steps \u2014 use the dedicated \`human\` step instead.
9381
+ ### Map (Iteration)
9360
9382
 
9361
- ## Design Patterns
9383
+ \`\`\`yaml
9384
+ steps:
9385
+ - extract:
9386
+ prompt: Extract items from {{input}}
9387
+ output:
9388
+ items:
9389
+ - name: string
9390
+ - map_items:
9391
+ map:
9392
+ source: "extract.items"
9393
+ each:
9394
+ prompt: Audit {{item.name}}
9395
+ output:
9396
+ result: string
9397
+ - summary:
9398
+ prompt: Summarize findings: {{map_items}}
9399
+ \`\`\`
9362
9400
 
9363
- ### Pattern 1: Linear Pipeline
9401
+ ## Keep Business Logic in Agents
9364
9402
 
9365
- \`\`\`json
9366
- {
9367
- "name": "knowledge-qa",
9368
- "steps": [
9369
- { "id": "research", "name": "Research Topic", "prompt": "Research: {{input}}", "schema": { "type": "object", "properties": { "findings": { "type": "string" } } } },
9370
- { "id": "answer", "name": "Write Answer", "prompt": "Write answer based on: {{research}}", "schema": { "type": "object", "properties": { "answer": { "type": "string" } } } },
9371
- { "type": "end" }
9372
- ]
9373
- }
9374
- \`\`\`
9403
+ 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.
9375
9404
 
9376
- ### Pattern 2: Classify then Route
9405
+ **Rule:** if you have more if conditions than workflow phases, move logic into richer agent prompts.
9377
9406
 
9378
- \`\`\`json
9379
- {
9380
- "name": "customer-router",
9381
- "steps": [
9382
- { "id": "intent", "name": "Classify Intent", "prompt": "Classify: {{input}}", "schema": { "type": "object", "properties": { "intent": { "type": "string" } } } },
9383
- { "type": "condition", "if": "intent",
9384
- "then": { "id": "support", "name": "Handle Support", "prompt": "Handle support: {{input}}", "schema": { "type": "object", "properties": { "response": { "type": "string" } } } },
9385
- "else": { "id": "sales", "name": "Handle Sales", "prompt": "Handle sales: {{input}}", "schema": { "type": "object", "properties": { "response": { "type": "string" } } } }
9386
- },
9387
- { "type": "end" }
9388
- ]
9389
- }
9390
- \`\`\`
9407
+ ## What You NEVER Write
9391
9408
 
9392
- ### Pattern 2b: Classify then Switch
9409
+ - **needs** \u2014 not supported. Steps execute linearly. Use parallel for concurrency.
9410
+ - **edges** \u2014 auto-generated from step order and parallel structure
9411
+ - **nested parallel** \u2014 parallel children are flat agent steps only
9412
+ - **map inside parallel** \u2014 map is a top-level step only
9413
+ - **json schema** \u2014 use **{ field: type }** block style
9414
+ - do not use {{}} markers in if expressions
9415
+ - **workflow-level business logic** \u2014 decisions belong inside agent prompts
9393
9416
 
9394
- For routing to 3+ categories, use \`branches\` instead of nested \`then\`/\`else\`:
9417
+ ## Checklist
9395
9418
 
9396
- \`\`\`json
9397
- {
9398
- "name": "ticket-router",
9399
- "steps": [
9400
- { "id": "intent", "name": "Classify", "prompt": "Classify: {{input}}", "schema": { "type": "object", "properties": { "category": { "type": "string" } } } },
9401
- { "type": "condition", "if": "intent.category",
9402
- "branches": {
9403
- "support": { "id": "support", "prompt": "Handle support: {{input}}" },
9404
- "sales": { "id": "sales", "prompt": "Handle sales: {{input}}" },
9405
- "billing": { "id": "billing", "prompt": "Handle billing: {{input}}" },
9406
- "default": { "id": "fallback", "prompt": "Send to human: {{input}}" }
9407
- }
9408
- },
9409
- { "type": "end" }
9410
- ]
9411
- }
9412
- \`\`\`
9413
-
9414
- ### Pattern 3: Extract \u2192 Review \u2192 Approve
9415
-
9416
- \`\`\`json
9417
- {
9418
- "name": "approval-flow",
9419
- "steps": [
9420
- { "id": "draft", "name": "Draft Response", "prompt": "Draft a response to: {{input}}", "schema": { "type": "object", "properties": { "content": { "type": "string" } } } },
9421
- { "id": "review", "type": "human",
9422
- "title": "Approval",
9423
- "prompt": "Present the draft below to the user for approval. Ask whether to approve or reject with comments.\\n\\nDraft:\\n{{draft}}",
9424
- "schema": { "type": "object", "properties": { "approved": { "type": "boolean" }, "comments": { "type": "string" } } } },
9425
- { "type": "condition", "if": "review.approved",
9426
- "then": { "id": "published", "name": "Publish", "prompt": "Publish: {{draft}}", "schema": { "type": "object", "properties": { "status": { "type": "string" } } } },
9427
- "else": { "id": "revised", "name": "Revise", "prompt": "Revise based on: {{review.comments}}", "schema": { "type": "object", "properties": { "content": { "type": "string" } } } }
9428
- },
9429
- { "type": "end" }
9430
- ]
9431
- }
9432
- \`\`\`
9433
-
9434
- ### Pattern 4: Parallel Research
9435
-
9436
- \`\`\`json
9437
- {
9438
- "name": "due-diligence",
9439
- "steps": [
9440
- { "id": "info", "name": "Gather Info", "prompt": "Gather info: {{input}}", "schema": { "type": "object", "properties": { "rawData": { "type": "string" } } } },
9441
- { "type": "parallel", "steps": [
9442
- { "id": "legal", "name": "Legal Review", "prompt": "Legal review: {{info}}", "schema": { "type": "object", "properties": { "risks": { "type": "array", "items": { "type": "string" } } } } },
9443
- { "id": "finance", "name": "Finance Review", "prompt": "Finance review: {{info}}", "schema": { "type": "object", "properties": { "score": { "type": "number" } } } },
9444
- { "id": "market", "name": "Market Analysis", "prompt": "Market analysis: {{info}}", "schema": { "type": "object", "properties": { "trend": { "type": "string" } } } }
9445
- ]},
9446
- { "id": "synthesis", "name": "Synthesize", "prompt": "Synthesize: legal={{legal}} finance={{finance}} market={{market}}", "schema": { "type": "object", "properties": { "report": { "type": "string" } } } },
9447
- { "type": "end" }
9448
- ]
9449
- }
9450
- \`\`\`
9451
-
9452
- ### Pattern 5: Batch Map + Reduce
9453
-
9454
- \`\`\`json
9455
- {
9456
- "name": "sentiment-analysis",
9457
- "steps": [
9458
- { "id": "posts", "name": "Scrape Posts", "prompt": "Scrape posts about: {{input}}", "schema": { "type": "object", "properties": { "posts": { "type": "array", "items": { "type": "object", "properties": { "text": { "type": "string" } } } } } } },
9459
- { "id": "sentiments", "type": "map", "source": "posts",
9460
- "each": { "prompt": "Analyze sentiment: {{item}}", "schema": { "type": "object", "properties": { "sentiment": { "type": "string" } } } },
9461
- "reduce": { "prompt": "Summarize: {{sentiments}}", "schema": { "type": "object", "properties": { "summary": { "type": "string" } } } }
9462
- },
9463
- { "id": "report", "name": "Generate Report", "prompt": "Generate report from: {{sentiments}}", "schema": { "type": "object", "properties": { "report": { "type": "string" } } } },
9464
- { "type": "end" }
9465
- ]
9466
- }
9467
- \`\`\`
9468
-
9469
- ## Step 1: Understand the Process
9470
-
9471
- Ask the user:
9472
- - What are the steps in order?
9473
- - Are there branches (if condition then A else B)?
9474
- - Can any steps run in parallel?
9475
- - Is human approval/review needed?
9476
- - What data flows between steps?
9477
-
9478
- ## Step 2: Prepare Dependencies
9479
-
9480
- 1. Call \`list_tools\` to see available tools for the workflow agent.
9481
-
9482
- ## Step 3: Write the DSL
9483
-
9484
- Use \`create_workflow\` with \`skillLoaded: true\`. Never write \`state.fields\`, \`edges\`, \`version\`, or \`output.key\` \u2014 they are auto-generated.
9485
-
9486
- **Checklist before calling:**
9487
- - Every step that produces data referenced downstream has an \`id\`
9488
- - Every agent/map-each step has a valid \`schema\` in standard JSON Schema format (with \`"type": "object"\` and \`"properties"\`)
9489
- - Schema uses \`{ "type": "object", "properties": { ... } }\` \u2014 \`true\` and legacy \`{ "field": "string" }\` are REJECTED
9490
- - Downstream steps reference upstream data with \`{{id}}\`
9491
- - **Condition \`if\` fields do NOT use \`{{}}\`** \u2014 they are plain expressions like \`"intent"\` or \`"score >= 60"\`
9492
- - Condition steps have \`then\`/\`else\` (binary) or \`branches\` (switch)
9493
- - Human steps have \`schema\` constraining the agent's structured output
9494
- - Map steps have \`source\` pointing to an existing step id
9495
- - Parallel steps have sibling steps with unique \`id\`s
9496
- - Workflow ends with \`{ "type": "end" }\`
9497
- - Use \`human\` step type for user interaction (clarify middleware is built-in)
9498
-
9499
- ## Step 4: Test
9500
-
9501
- After creating, optionally call \`validate_workflow(id)\` to check the workflow compiles correctly. Then test with \`invoke_agent\`.
9502
-
9503
- ## Debugging Tips
9504
-
9505
- - If output is missing: check the producing step has an \`id\`
9506
- - The human step invokes an agent that can use ask_user_to_clarify. The agent's structured output is stored under the step's \`id\`. Access nested results with dot notation: \`{{review.approved}}\`, \`{{review.comments}}\`
9507
- - Map results are an array; use \`reduce\` to aggregate into a summary
9508
- - Condition branching uses truthiness: empty string, 0, null, false \u2192 else path
9509
- - \`{{input}}\` contains the user's initial message; it's always available
9510
- - Parallel + condition: a parallel group cannot be the first step inside a condition's then/else (LangGraph limitation). Add a preceding agent step.
9511
- `
9419
+ - Every step has a unique label
9420
+ - Steps execute top-to-bottom \u2014 no dependency thinking needed
9421
+ - \`{{label}}\` can reference ANY upstream step output
9422
+ - if uses plain JS, no {{}}
9423
+ - Schema uses block style shorthand
9424
+ - parallel children are flat agent steps
9425
+ - Business logic stays inside agent prompts
9426
+ - ask: true for human interaction`
9512
9427
  };
9513
9428
  function getBuiltInSkillMeta(name) {
9514
9429
  const content = BUILTIN_SKILLS[name];
@@ -12419,7 +12334,7 @@ ${currentSystemPrompt}` : dateContext;
12419
12334
  // src/deep_agent_new/middleware/scheduler.ts
12420
12335
  var import_langchain55 = require("langchain");
12421
12336
  var import_zod50 = require("zod");
12422
- var import_uuid2 = require("uuid");
12337
+ var import_uuid3 = require("uuid");
12423
12338
  var import_protocols8 = require("@axiom-lattice/protocols");
12424
12339
 
12425
12340
  // src/schedule_lattice/ScheduleLatticeManager.ts
@@ -13974,7 +13889,7 @@ var buffer = new InMemoryChunkBuffer({
13974
13889
  registerChunkBuffer("default", buffer);
13975
13890
 
13976
13891
  // src/services/Agent.ts
13977
- var import_uuid = require("uuid");
13892
+ var import_uuid2 = require("uuid");
13978
13893
  var ThreadStatus2 = /* @__PURE__ */ ((ThreadStatus3) => {
13979
13894
  ThreadStatus3["IDLE"] = "idle";
13980
13895
  ThreadStatus3["BUSY"] = "busy";
@@ -14020,7 +13935,7 @@ var Agent = class {
14020
13935
  runConfig
14021
13936
  },
14022
13937
  configurable: {
14023
- run_id: (0, import_uuid.v4)(),
13938
+ run_id: (0, import_uuid2.v4)(),
14024
13939
  ...runConfig,
14025
13940
  runConfig
14026
13941
  },
@@ -14054,7 +13969,6 @@ var Agent = class {
14054
13969
  const runnable_agent = await getAgentClientAsync(this.tenant_id, this.assistant_id);
14055
13970
  const agentLattice = agentLatticeManager.getAgentLatticeWithTenant(this.tenant_id, this.assistant_id);
14056
13971
  const { messages, ...rest } = input;
14057
- const lifecycleManager = this;
14058
13972
  const runConfig = {
14059
13973
  thread_id: this.thread_id,
14060
13974
  "x-tenant-id": this.tenant_id,
@@ -14094,7 +14008,7 @@ var Agent = class {
14094
14008
  runConfig
14095
14009
  },
14096
14010
  configurable: {
14097
- run_id: (0, import_uuid.v4)(),
14011
+ run_id: (0, import_uuid2.v4)(),
14098
14012
  ...runConfig,
14099
14013
  runConfig
14100
14014
  // Inject runConfig for tools to access
@@ -14106,43 +14020,13 @@ var Agent = class {
14106
14020
  }
14107
14021
  );
14108
14022
  try {
14109
- for await (const chunk2 of agentStream) {
14110
- if (signal?.aborted) {
14111
- await lifecycleManager.chunkBuffer.abortThread(lifecycleManager.thread_id);
14112
- throw new Error("Agent execution was aborted");
14113
- }
14114
- let data;
14115
- let chunkContent = "";
14116
- if (chunk2[0] === "updates") {
14117
- const update = chunk2[1];
14118
- const values = Object.values(update);
14119
- const messages2 = values[0]?.messages;
14120
- if (messages2?.[0]?.tool_call_id) {
14121
- data = messages2[0].toDict();
14122
- }
14123
- } else if (chunk2[0] === "messages") {
14124
- const messages2 = chunk2[1];
14125
- data = messages2?.[0]?.toDict();
14126
- }
14127
- if (chunk2?.[1]?.__interrupt__) {
14128
- const interruptData = chunk2?.[1]?.__interrupt__[0];
14129
- data = {
14130
- type: "interrupt",
14131
- id: interruptData.id,
14132
- data: { content: interruptData.value }
14133
- };
14134
- }
14135
- if (data) {
14136
- lifecycleManager.addChunk(data);
14137
- }
14138
- }
14023
+ await this.consumeAgentStream(agentStream, signal);
14139
14024
  } catch (error) {
14140
14025
  console.error("Stream error:", error);
14141
- await lifecycleManager.chunkBuffer.abortThread(lifecycleManager.thread_id);
14142
14026
  throw error;
14143
14027
  }
14144
14028
  } catch (error) {
14145
- await this.chunkBuffer.abortThread(lifecycleManager.thread_id);
14029
+ await this.chunkBuffer.abortThread(this.thread_id);
14146
14030
  throw error;
14147
14031
  }
14148
14032
  };
@@ -14423,8 +14307,8 @@ var Agent = class {
14423
14307
  this.assistant_id = assistant_id;
14424
14308
  this.thread_id = thread_id;
14425
14309
  this.tenant_id = tenant_id;
14426
- this.workspace_id = workspace_id;
14427
- this.project_id = project_id;
14310
+ this.workspace_id = workspace_id || "default";
14311
+ this.project_id = project_id || "default";
14428
14312
  this.custom_run_config = custom_run_config;
14429
14313
  }
14430
14314
  getHumanPendingContent(message) {
@@ -14510,7 +14394,7 @@ var Agent = class {
14510
14394
  };
14511
14395
  }
14512
14396
  async invoke(queueMessage, signal) {
14513
- const messageId = (0, import_uuid.v4)();
14397
+ const messageId = (0, import_uuid2.v4)();
14514
14398
  const input = {
14515
14399
  ...queueMessage.input,
14516
14400
  messages: [new import_langchain54.HumanMessage({ id: messageId, content: queueMessage.input.message })]
@@ -14518,10 +14402,132 @@ var Agent = class {
14518
14402
  const inputMessage = { ...queueMessage, input };
14519
14403
  return this.agentExecutor(inputMessage, signal);
14520
14404
  }
14405
+ /**
14406
+ * Like {@link invoke} but returns the full LangGraph state (all annotations)
14407
+ * instead of only messages. Messages are serialized to dicts; other state
14408
+ * fields are returned as-is.
14409
+ *
14410
+ * @remarks
14411
+ * Only call this when you need the full state. Existing callers (gateway,
14412
+ * workflows) should keep using {@link invoke} which returns only messages
14413
+ * to avoid exposing internal annotation data.
14414
+ */
14415
+ async invokeWithState(queueMessage, signal) {
14416
+ const messageId = (0, import_uuid2.v4)();
14417
+ const input = {
14418
+ ...queueMessage.input,
14419
+ messages: [new import_langchain54.HumanMessage({ id: messageId, content: queueMessage.input.message })]
14420
+ };
14421
+ const inputMessage = { ...queueMessage, input };
14422
+ const { runnable_agent, runConfig } = await this.getLatticeClientAndRuntimeConfig(inputMessage.custom_run_config);
14423
+ const { messages, ...rest } = inputMessage.input;
14424
+ if (signal?.aborted) {
14425
+ throw new Error("Agent execution was aborted");
14426
+ }
14427
+ let result;
14428
+ result = await runnable_agent.invoke(
14429
+ inputMessage.command ? new import_langgraph6.Command(inputMessage.command) : { ...rest, messages, "x-tenant-id": this.tenant_id },
14430
+ {
14431
+ context: { runConfig },
14432
+ configurable: {
14433
+ run_id: (0, import_uuid2.v4)(),
14434
+ ...runConfig,
14435
+ runConfig
14436
+ },
14437
+ recursionLimit: 200,
14438
+ signal
14439
+ }
14440
+ );
14441
+ if (signal?.aborted) {
14442
+ throw new Error("Agent execution was aborted");
14443
+ }
14444
+ const { messages: _rawMessages, ...restState } = result;
14445
+ const serializedMessages = result.messages.map((message) => {
14446
+ const { type, data } = message.toDict();
14447
+ return { ...data, role: type };
14448
+ });
14449
+ return { messages: serializedMessages, ...restState };
14450
+ }
14521
14451
  async getPendingMessages() {
14522
14452
  const store = this.getQueueStore();
14523
14453
  return await store.getPendingMessages(this.thread_id);
14524
14454
  }
14455
+ async consumeAgentStream(agentStream, signal) {
14456
+ for await (const chunk2 of agentStream) {
14457
+ if (signal?.aborted) {
14458
+ await this.chunkBuffer.abortThread(this.thread_id);
14459
+ throw new Error("Agent execution was aborted");
14460
+ }
14461
+ let data;
14462
+ if (chunk2[0] === "updates") {
14463
+ const update = chunk2[1];
14464
+ const values = Object.values(update);
14465
+ const messages = values[0]?.messages;
14466
+ if (messages?.[0]?.tool_call_id) {
14467
+ data = messages[0].toDict();
14468
+ }
14469
+ } else if (chunk2[0] === "messages") {
14470
+ const messages = chunk2[1];
14471
+ data = messages?.[0]?.toDict();
14472
+ }
14473
+ if (chunk2?.[1]?.__interrupt__) {
14474
+ const interruptData = chunk2?.[1]?.__interrupt__[0];
14475
+ data = {
14476
+ type: "interrupt",
14477
+ id: interruptData.id,
14478
+ data: { content: interruptData.value }
14479
+ };
14480
+ }
14481
+ if (data) {
14482
+ this.addChunk(data);
14483
+ }
14484
+ }
14485
+ }
14486
+ /**
14487
+ * Resume LangGraph execution from the last checkpoint.
14488
+ *
14489
+ * Streams with `null` input — this tells LangGraph to continue from
14490
+ * wherever it left off using the checkpointed state for this thread.
14491
+ * All output chunks are buffered via {@link addChunk}.
14492
+ */
14493
+ async resumeGraphFromCheckpoint(signal) {
14494
+ const runnable_agent = await getAgentClientAsync(this.tenant_id, this.assistant_id);
14495
+ const agentLattice = agentLatticeManager.getAgentLatticeWithTenant(this.tenant_id, this.assistant_id);
14496
+ if (!runnable_agent) {
14497
+ throw new Error(`Agent ${this.assistant_id} not found`);
14498
+ }
14499
+ const runConfig = {
14500
+ thread_id: this.thread_id,
14501
+ "x-tenant-id": this.tenant_id,
14502
+ "x-workspace-id": this.workspace_id,
14503
+ "x-project-id": this.project_id,
14504
+ "x-thread-id": this.thread_id,
14505
+ "x-assistant-id": this.assistant_id,
14506
+ ...agentLattice?.config?.runConfig || {},
14507
+ tenantId: this.tenant_id,
14508
+ workspaceId: this.workspace_id,
14509
+ projectId: this.project_id,
14510
+ ...this.custom_run_config || {},
14511
+ assistant_id: this.assistant_id
14512
+ };
14513
+ const agentStream = await runnable_agent.stream(
14514
+ null,
14515
+ {
14516
+ context: {
14517
+ runConfig
14518
+ },
14519
+ configurable: {
14520
+ ...runConfig,
14521
+ runConfig
14522
+ },
14523
+ streamMode: ["updates", "messages"],
14524
+ subgraphs: false,
14525
+ recursionLimit: 200,
14526
+ signal
14527
+ }
14528
+ );
14529
+ await this.consumeAgentStream(agentStream, signal);
14530
+ }
14525
14531
  getQueueStore() {
14526
14532
  if (!this.queueStore) {
14527
14533
  try {
@@ -14600,7 +14606,7 @@ var Agent = class {
14600
14606
  */
14601
14607
  async addMessage(queueMessage, mode) {
14602
14608
  const useMode = mode ?? this.queueMode.mode;
14603
- const messageId = queueMessage.input.id || (0, import_uuid.v4)();
14609
+ const messageId = queueMessage.input.id || (0, import_uuid2.v4)();
14604
14610
  const messages = queueMessage.input.messages;
14605
14611
  const legacyMessage = queueMessage.input.message;
14606
14612
  if (!messages && !legacyMessage) {
@@ -14651,6 +14657,8 @@ var Agent = class {
14651
14657
  threadId: this.thread_id,
14652
14658
  tenantId: this.tenant_id,
14653
14659
  assistantId: this.assistant_id,
14660
+ workspaceId: this.workspace_id,
14661
+ projectId: this.project_id,
14654
14662
  content,
14655
14663
  type: pendingType,
14656
14664
  command: queueMessage.command,
@@ -14667,6 +14675,8 @@ var Agent = class {
14667
14675
  threadId: this.thread_id,
14668
14676
  tenantId: this.tenant_id,
14669
14677
  assistantId: this.assistant_id,
14678
+ workspaceId: this.workspace_id,
14679
+ projectId: this.project_id,
14670
14680
  content,
14671
14681
  type: pendingType,
14672
14682
  command: queueMessage.command,
@@ -14740,6 +14750,8 @@ var Agent = class {
14740
14750
  threadId: thread.threadId,
14741
14751
  tenantId: thread.tenantId,
14742
14752
  assistantId: thread.assistantId,
14753
+ workspaceId: this.workspace_id,
14754
+ projectId: this.project_id,
14743
14755
  content: reminderContent,
14744
14756
  type: "system"
14745
14757
  });
@@ -14811,9 +14823,14 @@ var Agent = class {
14811
14823
  /**
14812
14824
  * Resume processing after a server restart.
14813
14825
  *
14814
- * Resets any stuck "processing" messages back to "pending" and restarts the
14815
- * queue processor. Skips threads that are in `INTERRUPTED` state (the
14816
- * interruption was intentional).
14826
+ * If the graph was mid-execution (BUSY) it resumes from the LangGraph
14827
+ * checkpoint without re-injecting the message the message has already
14828
+ * been consumed and is in the graph state. Processing messages are removed
14829
+ * rather than replayed.
14830
+ *
14831
+ * Skips threads that are in `INTERRUPTED` state (the interruption was
14832
+ * intentional). IDLE threads simply clean up and restart the queue
14833
+ * processor for any remaining pending messages.
14817
14834
  *
14818
14835
  * Called during gateway startup to recover threads that were mid-execution
14819
14836
  * when the server went down.
@@ -14831,9 +14848,32 @@ var Agent = class {
14831
14848
  return;
14832
14849
  }
14833
14850
  const store = this.getQueueStore();
14834
- const resetCount = await store.resetProcessingToPending(this.thread_id);
14835
- if (resetCount > 0) {
14836
- console.log(`[Agent] Reset ${resetCount} processing messages to pending for thread ${this.thread_id}`);
14851
+ if (runStatus === "busy" /* BUSY */) {
14852
+ this.abortController = new AbortController();
14853
+ try {
14854
+ await this.resumeGraphFromCheckpoint(this.abortController.signal);
14855
+ const processingMessages = await store.getProcessingMessages(this.thread_id);
14856
+ for (const msg of processingMessages) {
14857
+ await store.removeMessage(msg.id);
14858
+ }
14859
+ if (processingMessages.length > 0) {
14860
+ console.log(`[Agent] Removed ${processingMessages.length} processing messages for thread ${this.thread_id}`);
14861
+ }
14862
+ } catch (error) {
14863
+ console.error(`[Agent] Failed to resume graph for thread ${this.thread_id}:`, error);
14864
+ await this.chunkBuffer.abortThread(this.thread_id);
14865
+ throw error;
14866
+ } finally {
14867
+ this.abortController = null;
14868
+ }
14869
+ } else {
14870
+ const processingMessages = await store.getProcessingMessages(this.thread_id);
14871
+ for (const msg of processingMessages) {
14872
+ await store.removeMessage(msg.id);
14873
+ }
14874
+ if (processingMessages.length > 0) {
14875
+ console.log(`[Agent] Removed ${processingMessages.length} processing messages for thread ${this.thread_id}`);
14876
+ }
14837
14877
  }
14838
14878
  await this.startQueueProcessorIfNeeded();
14839
14879
  }
@@ -15024,7 +15064,7 @@ var AgentInstanceManager = class _AgentInstanceManager {
15024
15064
  console.log(`[AgentInstanceManager] Found ${threadsWithPending.length} threads with pending messages, restoring...`);
15025
15065
  for (const threadInfo of threadsWithPending) {
15026
15066
  try {
15027
- await this.restoreThread(threadInfo, queueStore);
15067
+ await this.restoreThread(threadInfo);
15028
15068
  stats.restored++;
15029
15069
  } catch (error) {
15030
15070
  console.error(`[AgentInstanceManager] Failed to restore thread ${threadInfo.threadId}:`, error);
@@ -15042,16 +15082,14 @@ var AgentInstanceManager = class _AgentInstanceManager {
15042
15082
  * Restore a single thread
15043
15083
  * Delegates actual recovery logic to Agent.resumeTask()
15044
15084
  */
15045
- async restoreThread(threadInfo, queueStore) {
15046
- const { tenantId, assistantId, threadId } = threadInfo;
15085
+ async restoreThread(threadInfo) {
15086
+ const { tenantId, assistantId, threadId, workspaceId, projectId } = threadInfo;
15047
15087
  const threadParams = {
15048
15088
  tenant_id: tenantId,
15049
15089
  assistant_id: assistantId,
15050
15090
  thread_id: threadId,
15051
- workspace_id: "default",
15052
- // TODO: Get from thread store
15053
- project_id: "default"
15054
- // TODO: Get from thread store
15091
+ workspace_id: workspaceId,
15092
+ project_id: projectId
15055
15093
  };
15056
15094
  const agent = this.getAgent(threadParams);
15057
15095
  await agent.resumeTask();
@@ -15142,7 +15180,7 @@ function createSchedulerMiddleware(options = {}) {
15142
15180
  async (input, config) => {
15143
15181
  const runConfig = getRunConfig(config);
15144
15182
  const scheduleLattice = getScheduleLattice(SCHEDULE_LATTICE_KEY);
15145
- const taskId = (0, import_uuid2.v4)();
15183
+ const taskId = (0, import_uuid3.v4)();
15146
15184
  const executeAt = input.executeAt;
15147
15185
  const success = await scheduleLattice.client.scheduleOnce(
15148
15186
  taskId,
@@ -15177,7 +15215,7 @@ function createSchedulerMiddleware(options = {}) {
15177
15215
  async (input, config) => {
15178
15216
  const runConfig = getRunConfig(config);
15179
15217
  const scheduleLattice = getScheduleLattice(SCHEDULE_LATTICE_KEY);
15180
- const taskId = (0, import_uuid2.v4)();
15218
+ const taskId = (0, import_uuid3.v4)();
15181
15219
  const executeAt = Date.now() + input.delayMs;
15182
15220
  const success = await scheduleLattice.client.scheduleOnce(
15183
15221
  taskId,
@@ -15212,7 +15250,7 @@ function createSchedulerMiddleware(options = {}) {
15212
15250
  async (input, config) => {
15213
15251
  const runConfig = getRunConfig(config);
15214
15252
  const scheduleLattice = getScheduleLattice(SCHEDULE_LATTICE_KEY);
15215
- const taskId = (0, import_uuid2.v4)();
15253
+ const taskId = (0, import_uuid3.v4)();
15216
15254
  const success = await scheduleLattice.client.scheduleCron(
15217
15255
  taskId,
15218
15256
  AGENT_ADD_MESSAGE_TASK_TYPE,
@@ -15300,6 +15338,138 @@ function createSchedulerMiddleware(options = {}) {
15300
15338
  });
15301
15339
  }
15302
15340
 
15341
+ // src/middlewares/taskMiddleware.ts
15342
+ var import_langchain56 = require("langchain");
15343
+ var import_zod51 = require("zod");
15344
+ function getRunConfig2(config) {
15345
+ const c = config;
15346
+ return c?.configurable?.runConfig ?? {};
15347
+ }
15348
+ function getTaskStore() {
15349
+ return getStoreLattice("default", "task").store;
15350
+ }
15351
+ var manageTaskSchema = import_zod51.z.object({
15352
+ action: import_zod51.z.enum(["create", "list", "update", "delete", "complete"]).describe("\u64CD\u4F5C\u7C7B\u578B"),
15353
+ id: import_zod51.z.string().optional().describe("\u4EFB\u52A1 ID (update/delete/complete \u5FC5\u586B)"),
15354
+ title: import_zod51.z.string().optional().describe("\u4EFB\u52A1\u6807\u9898 (create \u5FC5\u586B)"),
15355
+ description: import_zod51.z.string().optional().describe("\u4EFB\u52A1\u63CF\u8FF0"),
15356
+ priority: import_zod51.z.enum(["low", "medium", "high"]).optional().describe("\u4F18\u5148\u7EA7"),
15357
+ status: import_zod51.z.enum(["pending", "in_progress", "completed", "cancelled"]).optional().describe("\u72B6\u6001"),
15358
+ dueDate: import_zod51.z.string().optional().describe("\u622A\u6B62\u65E5\u671F (ISO 8601)"),
15359
+ metadata: import_zod51.z.record(import_zod51.z.unknown()).optional().describe("\u7ED3\u6784\u5316\u5143\u6570\u636E (projectId, module \u7B49)"),
15360
+ parentId: import_zod51.z.string().optional().describe("\u7236\u4EFB\u52A1 ID (\u5B50\u4EFB\u52A1\u5173\u8054)"),
15361
+ sourceId: import_zod51.z.string().optional().describe("\u6765\u6E90\u4F1A\u8BDD/thread ID"),
15362
+ context: import_zod51.z.record(import_zod51.z.unknown()).optional().describe("\u9644\u52A0\u4E0A\u4E0B\u6587"),
15363
+ ownerType: import_zod51.z.enum(["user", "agent"]).optional().describe("\u6240\u6709\u8005\u7C7B\u578B\uFF0C\u4E0D\u4F20\u9ED8\u8BA4\u4E3A user"),
15364
+ ownerId: import_zod51.z.string().optional().describe("\u6240\u6709\u8005 ID\uFF0C\u4E0D\u4F20\u81EA\u52A8\u53D6\u5F53\u524D\u7528\u6237/Agent")
15365
+ });
15366
+ function createTaskMiddleware() {
15367
+ return (0, import_langchain56.createMiddleware)({
15368
+ name: "TaskMiddleware",
15369
+ contextSchema,
15370
+ wrapModelCall: async (request, handler) => {
15371
+ const taskPrompt = `## \u4EFB\u52A1\u7BA1\u7406\u80FD\u529B
15372
+ \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
15373
+ - \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)
15374
+ - ownerType="agent": \u4E3A\u81EA\u5DF1\u521B\u5EFA\u6267\u884C\u5B50\u4EFB\u52A1 (ownerId \u81EA\u52A8\u53D6\u5F53\u524D Agent)
15375
+ - \u663E\u5F0F\u4F20 ownerId: \u4E3A\u6307\u5B9A agent/user \u521B\u5EFA\u4EFB\u52A1\uFF08\u62D3\u6251\u573A\u666F\uFF09`;
15376
+ return handler({
15377
+ ...request,
15378
+ systemPrompt: taskPrompt + "\n\n" + (request.systemPrompt ?? "")
15379
+ });
15380
+ },
15381
+ tools: [
15382
+ (0, import_langchain56.tool)(
15383
+ async (input, config) => {
15384
+ const rc = getRunConfig2(config);
15385
+ const tenantId = rc.tenantId || "default";
15386
+ const ownerId = input.ownerId || (input.ownerType === "agent" ? rc.assistant_id : null) || rc.user_id;
15387
+ const store = getTaskStore();
15388
+ switch (input.action) {
15389
+ case "create": {
15390
+ if (!input.title) {
15391
+ return JSON.stringify({ success: false, error: "create requires title" });
15392
+ }
15393
+ const task = await store.create({
15394
+ tenantId,
15395
+ ownerType: input.ownerType || "user",
15396
+ ownerId,
15397
+ title: input.title,
15398
+ description: input.description,
15399
+ priority: input.priority || "medium",
15400
+ status: input.status || "pending",
15401
+ dueDate: input.dueDate,
15402
+ metadata: input.metadata,
15403
+ parentId: input.parentId,
15404
+ sourceId: input.sourceId,
15405
+ context: input.context
15406
+ });
15407
+ return JSON.stringify({ success: true, data: task });
15408
+ }
15409
+ case "list": {
15410
+ const tasks = await store.list({
15411
+ tenantId,
15412
+ ownerType: input.ownerType,
15413
+ ownerId: input.ownerId,
15414
+ status: input.status,
15415
+ priority: input.priority
15416
+ });
15417
+ return JSON.stringify({ success: true, data: tasks, count: tasks.length });
15418
+ }
15419
+ case "update": {
15420
+ if (!input.id) {
15421
+ return JSON.stringify({ success: false, error: "update requires id" });
15422
+ }
15423
+ const { action, ...updates } = input;
15424
+ const updated = await store.update(tenantId, input.id, updates);
15425
+ if (!updated) {
15426
+ return JSON.stringify({ success: false, error: "Task not found" });
15427
+ }
15428
+ return JSON.stringify({ success: true, data: updated });
15429
+ }
15430
+ case "delete": {
15431
+ if (!input.id) {
15432
+ return JSON.stringify({ success: false, error: "delete requires id" });
15433
+ }
15434
+ const deleted = await store.delete(tenantId, input.id);
15435
+ return JSON.stringify({ success: deleted, message: deleted ? "Task deleted" : "Task not found" });
15436
+ }
15437
+ case "complete": {
15438
+ if (!input.id) {
15439
+ return JSON.stringify({ success: false, error: "complete requires id" });
15440
+ }
15441
+ const updated = await store.update(tenantId, input.id, { status: "completed" });
15442
+ if (!updated) {
15443
+ return JSON.stringify({ success: false, error: "Task not found" });
15444
+ }
15445
+ return JSON.stringify({ success: true, data: updated });
15446
+ }
15447
+ default:
15448
+ return JSON.stringify({ success: false, error: `Unknown action: ${input.action}` });
15449
+ }
15450
+ },
15451
+ {
15452
+ name: "manage_task",
15453
+ description: `\u7BA1\u7406\u6301\u4E45\u5316\u4EFB\u52A1\u7CFB\u7EDF\u3002CRUD \u64CD\u4F5C\u7528\u6237\u548C Agent \u7684\u4EFB\u52A1\u3002
15454
+
15455
+ ## ownerType \u548C ownerId \u7684\u9ED8\u8BA4\u903B\u8F91
15456
+ - \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)
15457
+ - \u4F20 ownerType="agent" \u4E0D\u4F20 ownerId: \u7CFB\u7EDF\u81EA\u52A8\u4E3A\u5F53\u524D Agent \u521B\u5EFA\u5B50\u4EFB\u52A1
15458
+ - \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
15459
+
15460
+ ## Actions
15461
+ - create: \u521B\u5EFA\u4EFB\u52A1 (title \u5FC5\u586B, priority/description/dueDate/metadata/parentId/context \u53EF\u9009)
15462
+ - list: \u5217\u51FA\u4EFB\u52A1\uFF0C\u53EF\u6309 ownerType/status/priority \u8FC7\u6EE4
15463
+ - update: \u66F4\u65B0\u4EFB\u52A1 (id \u5FC5\u586B\uFF0C\u53EA\u4F20\u8981\u6539\u7684\u5B57\u6BB5)
15464
+ - delete: \u5220\u9664\u4EFB\u52A1 (id \u5FC5\u586B)
15465
+ - complete: \u5FEB\u901F\u6807\u8BB0\u5B8C\u6210 (id \u5FC5\u586B)`,
15466
+ schema: manageTaskSchema
15467
+ }
15468
+ )
15469
+ ]
15470
+ });
15471
+ }
15472
+
15303
15473
  // src/agent_lattice/builders/CustomMiddlewareRegistry.ts
15304
15474
  var CustomMiddlewareRegistry = class {
15305
15475
  /**
@@ -15435,6 +15605,9 @@ async function createCommonMiddlewares(middlewareConfigs, filesystemBackend, fsI
15435
15605
  case "scheduler":
15436
15606
  middlewares.push(createSchedulerMiddleware(config.config));
15437
15607
  break;
15608
+ case "task":
15609
+ middlewares.push(createTaskMiddleware());
15610
+ break;
15438
15611
  case "custom":
15439
15612
  {
15440
15613
  const customConfig = config.config;
@@ -15642,14 +15815,14 @@ var ReActAgentGraphBuilder = class {
15642
15815
  */
15643
15816
  async build(agentLattice, params) {
15644
15817
  const tools = params.tools.map((t) => {
15645
- const tool51 = getToolClient(t.key);
15646
- return tool51;
15647
- }).filter((tool51) => tool51 !== void 0);
15818
+ const tool52 = getToolClient(t.key);
15819
+ return tool52;
15820
+ }).filter((tool52) => tool52 !== void 0);
15648
15821
  const stateSchema2 = createReactAgentSchema(params.stateSchema);
15649
15822
  const middlewareConfigs = params.middleware || [];
15650
15823
  const filesystemBackend = createFilesystemBackendFactory(middlewareConfigs);
15651
15824
  const middlewares = await createCommonMiddlewares(middlewareConfigs, filesystemBackend);
15652
- return (0, import_langchain56.createAgent)({
15825
+ return (0, import_langchain57.createAgent)({
15653
15826
  model: params.model,
15654
15827
  tools,
15655
15828
  systemPrompt: params.prompt,
@@ -15663,11 +15836,11 @@ var ReActAgentGraphBuilder = class {
15663
15836
  };
15664
15837
 
15665
15838
  // src/deep_agent_new/agent.ts
15666
- var import_langchain60 = require("langchain");
15839
+ var import_langchain61 = require("langchain");
15667
15840
 
15668
15841
  // src/deep_agent_new/middleware/subagents.ts
15669
15842
  var import_v32 = require("zod/v3");
15670
- var import_langchain57 = require("langchain");
15843
+ var import_langchain58 = require("langchain");
15671
15844
  var import_langgraph8 = require("@langchain/langgraph");
15672
15845
  var import_messages2 = require("@langchain/core/messages");
15673
15846
 
@@ -15991,7 +16164,7 @@ function returnCommandWithStateUpdate(result, toolCallId) {
15991
16164
  update: {
15992
16165
  ...stateUpdate,
15993
16166
  messages: [
15994
- new import_langchain57.ToolMessage({
16167
+ new import_langchain58.ToolMessage({
15995
16168
  content: lastMessage?.content || "Task Failed to complete",
15996
16169
  tool_call_id: toolCallId,
15997
16170
  name: "task"
@@ -16016,10 +16189,10 @@ function getSubagents(options) {
16016
16189
  const generalPurposeMiddleware = [...defaultSubagentMiddleware];
16017
16190
  if (defaultInterruptOn) {
16018
16191
  generalPurposeMiddleware.push(
16019
- (0, import_langchain57.humanInTheLoopMiddleware)({ interruptOn: defaultInterruptOn })
16192
+ (0, import_langchain58.humanInTheLoopMiddleware)({ interruptOn: defaultInterruptOn })
16020
16193
  );
16021
16194
  }
16022
- const generalPurposeSubagent = (0, import_langchain57.createAgent)({
16195
+ const generalPurposeSubagent = (0, import_langchain58.createAgent)({
16023
16196
  model: defaultModel,
16024
16197
  systemPrompt: DEFAULT_SUBAGENT_PROMPT,
16025
16198
  tools: defaultTools,
@@ -16042,8 +16215,8 @@ function getSubagents(options) {
16042
16215
  const middleware = agentParams.middleware ? [...defaultSubagentMiddleware, ...agentParams.middleware] : [...defaultSubagentMiddleware];
16043
16216
  const interruptOn = agentParams.interruptOn || defaultInterruptOn;
16044
16217
  if (interruptOn)
16045
- middleware.push((0, import_langchain57.humanInTheLoopMiddleware)({ interruptOn }));
16046
- agents[agentParams.key] = (0, import_langchain57.createAgent)({
16218
+ middleware.push((0, import_langchain58.humanInTheLoopMiddleware)({ interruptOn }));
16219
+ agents[agentParams.key] = (0, import_langchain58.createAgent)({
16047
16220
  model: agentParams.model ?? defaultModel,
16048
16221
  systemPrompt: agentParams.systemPrompt,
16049
16222
  tools: agentParams.tools ?? defaultTools,
@@ -16093,7 +16266,7 @@ function createTaskTool(options) {
16093
16266
  generalPurposeAgent
16094
16267
  });
16095
16268
  const finalTaskDescription = taskDescription ? taskDescription : getTaskToolDescription(subagentDescriptions);
16096
- return (0, import_langchain57.tool)(
16269
+ return (0, import_langchain58.tool)(
16097
16270
  async (input, config) => {
16098
16271
  const { description, subagent_type, async } = input;
16099
16272
  let assistant_id = subagent_type;
@@ -16127,12 +16300,16 @@ function createTaskTool(options) {
16127
16300
  const subagent_thread_id = config.configurable?.thread_id + "____" + assistant_id + "_" + config.toolCall.id;
16128
16301
  if (async) {
16129
16302
  const tenantId = config.configurable?.runConfig?.tenantId;
16303
+ const workspaceId = config.configurable?.runConfig?.workspaceId;
16304
+ const projectId = config.configurable?.runConfig?.projectId;
16130
16305
  const mainAssistantId = config.configurable?.runConfig?.assistant_id;
16131
16306
  const mainThreadId = config.configurable?.runConfig?.thread_id;
16132
16307
  const mainRuntimeAgent = agentInstanceManager.getAgent({
16133
16308
  assistant_id: mainAssistantId,
16134
16309
  thread_id: mainThreadId,
16135
- tenant_id: tenantId
16310
+ tenant_id: tenantId,
16311
+ workspace_id: workspaceId,
16312
+ project_id: projectId
16136
16313
  });
16137
16314
  if (mainRuntimeAgent) {
16138
16315
  mainRuntimeAgent.addAsyncTask({
@@ -16165,7 +16342,7 @@ function createTaskTool(options) {
16165
16342
  return new import_langgraph8.Command({
16166
16343
  update: {
16167
16344
  messages: [
16168
- new import_langchain57.ToolMessage({
16345
+ new import_langchain58.ToolMessage({
16169
16346
  content: `Async task started: ${subagent_thread_id}
16170
16347
  ${description}
16171
16348
  The result will be delivered as a notification when complete. Do not poll.`,
@@ -16198,7 +16375,7 @@ The result will be delivered as a notification when complete. Do not poll.`,
16198
16375
  return new import_langgraph8.Command({
16199
16376
  update: {
16200
16377
  messages: [
16201
- new import_langchain57.ToolMessage({
16378
+ new import_langchain58.ToolMessage({
16202
16379
  content: error instanceof Error ? error.message : "Task Failed to complete",
16203
16380
  tool_call_id: config.toolCall.id,
16204
16381
  name: "task"
@@ -16238,7 +16415,7 @@ function getMainAgentFromConfig(config) {
16238
16415
  });
16239
16416
  }
16240
16417
  function createCheckAsyncTaskTool() {
16241
- return (0, import_langchain57.tool)(
16418
+ return (0, import_langchain58.tool)(
16242
16419
  async (input, config) => {
16243
16420
  const { task_id } = input;
16244
16421
  const mainAgent = getMainAgentFromConfig(config);
@@ -16305,7 +16482,7 @@ Description: ${cached.description}`;
16305
16482
  );
16306
16483
  }
16307
16484
  function createListAsyncTasksTool() {
16308
- return (0, import_langchain57.tool)(
16485
+ return (0, import_langchain58.tool)(
16309
16486
  async (_input, config) => {
16310
16487
  const mainAgent = getMainAgentFromConfig(config);
16311
16488
  if (!mainAgent) {
@@ -16356,7 +16533,7 @@ function createListAsyncTasksTool() {
16356
16533
  );
16357
16534
  }
16358
16535
  function createCancelAsyncTaskTool() {
16359
- return (0, import_langchain57.tool)(
16536
+ return (0, import_langchain58.tool)(
16360
16537
  async (input, config) => {
16361
16538
  const { task_id } = input;
16362
16539
  const mainAgent = getMainAgentFromConfig(config);
@@ -16432,7 +16609,7 @@ function createSubAgentMiddleware(options) {
16432
16609
  );
16433
16610
  }
16434
16611
  const effectiveSystemPrompt = allowAsync ? systemPrompt + getAsyncPromptText() : systemPrompt;
16435
- return (0, import_langchain57.createMiddleware)({
16612
+ return (0, import_langchain58.createMiddleware)({
16436
16613
  name: "subAgentMiddleware",
16437
16614
  tools: allTools,
16438
16615
  wrapModelCall: async (request, handler) => {
@@ -16452,11 +16629,9 @@ ${effectiveSystemPrompt}` : effectiveSystemPrompt;
16452
16629
  }
16453
16630
 
16454
16631
  // src/deep_agent_new/middleware/patch_tool_calls.ts
16455
- var import_langchain58 = require("langchain");
16456
- var import_messages3 = require("@langchain/core/messages");
16457
- var import_langgraph9 = require("@langchain/langgraph");
16632
+ var import_langchain59 = require("langchain");
16458
16633
  function createPatchToolCallsMiddleware() {
16459
- return (0, import_langchain58.createMiddleware)({
16634
+ return (0, import_langchain59.createMiddleware)({
16460
16635
  name: "patchToolCallsMiddleware",
16461
16636
  beforeAgent: async (state) => {
16462
16637
  const messages = state.messages;
@@ -16467,15 +16642,15 @@ function createPatchToolCallsMiddleware() {
16467
16642
  for (let i = 0; i < messages.length; i++) {
16468
16643
  const msg = messages[i];
16469
16644
  patchedMessages.push(msg);
16470
- if (import_langchain58.AIMessage.isInstance(msg) && msg.tool_calls != null) {
16645
+ if (import_langchain59.AIMessage.isInstance(msg) && msg.tool_calls != null) {
16471
16646
  for (const toolCall of msg.tool_calls) {
16472
16647
  const correspondingToolMsg = messages.slice(i).find(
16473
- (m) => import_langchain58.ToolMessage.isInstance(m) && m.tool_call_id === toolCall.id
16648
+ (m) => import_langchain59.ToolMessage.isInstance(m) && m.tool_call_id === toolCall.id
16474
16649
  );
16475
16650
  if (!correspondingToolMsg) {
16476
16651
  const toolMsg = `Tool call ${toolCall.name} with id ${toolCall.id} was cancelled - another message came in before it could be completed.`;
16477
16652
  patchedMessages.push(
16478
- new import_langchain58.ToolMessage({
16653
+ new import_langchain59.ToolMessage({
16479
16654
  content: toolMsg,
16480
16655
  name: toolCall.name,
16481
16656
  tool_call_id: toolCall.id
@@ -16485,11 +16660,12 @@ function createPatchToolCallsMiddleware() {
16485
16660
  }
16486
16661
  }
16487
16662
  }
16663
+ if (patchedMessages.length === messages.length) {
16664
+ return;
16665
+ }
16488
16666
  return {
16489
- messages: [
16490
- new import_messages3.RemoveMessage({ id: import_langgraph9.REMOVE_ALL_MESSAGES }),
16491
- ...patchedMessages
16492
- ]
16667
+ messages: patchedMessages.slice(messages.length)
16668
+ // only the new ToolMessage patches
16493
16669
  };
16494
16670
  }
16495
16671
  });
@@ -17601,9 +17777,9 @@ var MemoryBackend = class {
17601
17777
  };
17602
17778
 
17603
17779
  // src/deep_agent_new/middleware/todos.ts
17604
- var import_langgraph10 = require("@langchain/langgraph");
17605
- var import_zod51 = require("zod");
17606
- var import_langchain59 = require("langchain");
17780
+ var import_langgraph9 = require("@langchain/langgraph");
17781
+ var import_zod52 = require("zod");
17782
+ var import_langchain60 = require("langchain");
17607
17783
  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.
17608
17784
  It also helps the user understand the progress of the task and overall progress of their requests.
17609
17785
  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.
@@ -17830,20 +18006,20 @@ Writing todos takes time and tokens, use it when it is helpful for managing comp
17830
18006
  ## Important To-Do List Usage Notes to Remember
17831
18007
  - The \`write_todos\` tool should never be called multiple times in parallel.
17832
18008
  - 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.`;
17833
- var TodoStatus = import_zod51.z.enum(["pending", "in_progress", "completed"]).describe("Status of the todo");
17834
- var TodoSchema = import_zod51.z.object({
17835
- content: import_zod51.z.string().describe("Content of the todo item"),
18009
+ var TodoStatus = import_zod52.z.enum(["pending", "in_progress", "completed"]).describe("Status of the todo");
18010
+ var TodoSchema = import_zod52.z.object({
18011
+ content: import_zod52.z.string().describe("Content of the todo item"),
17836
18012
  status: TodoStatus
17837
18013
  });
17838
- var stateSchema = import_zod51.z.object({ todos: import_zod51.z.array(TodoSchema).default([]) });
18014
+ var stateSchema = import_zod52.z.object({ todos: import_zod52.z.array(TodoSchema).default([]) });
17839
18015
  function todoListMiddleware(options) {
17840
- const writeTodos = (0, import_langchain59.tool)(
18016
+ const writeTodos = (0, import_langchain60.tool)(
17841
18017
  ({ todos }, config) => {
17842
- return new import_langgraph10.Command({
18018
+ return new import_langgraph9.Command({
17843
18019
  update: {
17844
18020
  todos,
17845
18021
  messages: [
17846
- new import_langchain59.ToolMessage({
18022
+ new import_langchain60.ToolMessage({
17847
18023
  content: genUIMarkdown("todo_list", todos),
17848
18024
  tool_call_id: config.toolCall?.id
17849
18025
  })
@@ -17854,12 +18030,12 @@ function todoListMiddleware(options) {
17854
18030
  {
17855
18031
  name: "write_todos",
17856
18032
  description: options?.toolDescription ?? WRITE_TODOS_DESCRIPTION,
17857
- schema: import_zod51.z.object({
17858
- todos: import_zod51.z.array(TodoSchema).describe("List of todo items to update")
18033
+ schema: import_zod52.z.object({
18034
+ todos: import_zod52.z.array(TodoSchema).describe("List of todo items to update")
17859
18035
  })
17860
18036
  }
17861
18037
  );
17862
- return (0, import_langchain59.createMiddleware)({
18038
+ return (0, import_langchain60.createMiddleware)({
17863
18039
  name: "todoListMiddleware",
17864
18040
  stateSchema,
17865
18041
  tools: [writeTodos],
@@ -17911,13 +18087,13 @@ ${BASE_PROMPT}` : BASE_PROMPT;
17911
18087
  backend: filesystemBackend
17912
18088
  }),
17913
18089
  // Subagent middleware: Automatic conversation summarization when token limits are approached
17914
- (0, import_langchain60.summarizationMiddleware)({
18090
+ (0, import_langchain61.summarizationMiddleware)({
17915
18091
  model,
17916
18092
  trigger: { tokens: 17e4 },
17917
18093
  keep: { messages: 6 }
17918
18094
  }),
17919
18095
  // Subagent middleware: Anthropic prompt caching for improved performance
17920
- (0, import_langchain60.anthropicPromptCachingMiddleware)({
18096
+ (0, import_langchain61.anthropicPromptCachingMiddleware)({
17921
18097
  unsupportedModelBehavior: "ignore"
17922
18098
  }),
17923
18099
  // Subagent middleware: Patches tool calls for compatibility
@@ -17929,23 +18105,23 @@ ${BASE_PROMPT}` : BASE_PROMPT;
17929
18105
  generalPurposeAgent: true
17930
18106
  }),
17931
18107
  // Automatically summarizes conversation history when token limits are approached
17932
- (0, import_langchain60.summarizationMiddleware)({
18108
+ (0, import_langchain61.summarizationMiddleware)({
17933
18109
  model,
17934
18110
  trigger: { tokens: 17e4 },
17935
18111
  keep: { messages: 6 }
17936
18112
  }),
17937
18113
  // Enables Anthropic prompt caching for improved performance and reduced costs
17938
- (0, import_langchain60.anthropicPromptCachingMiddleware)({
18114
+ (0, import_langchain61.anthropicPromptCachingMiddleware)({
17939
18115
  unsupportedModelBehavior: "ignore"
17940
18116
  }),
17941
18117
  // Patches tool calls to ensure compatibility across different model providers
17942
18118
  createPatchToolCallsMiddleware()
17943
18119
  ];
17944
18120
  if (interruptOn) {
17945
- middleware.push((0, import_langchain60.humanInTheLoopMiddleware)({ interruptOn }));
18121
+ middleware.push((0, import_langchain61.humanInTheLoopMiddleware)({ interruptOn }));
17946
18122
  }
17947
18123
  middleware.push(...customMiddleware);
17948
- return (0, import_langchain60.createAgent)({
18124
+ return (0, import_langchain61.createAgent)({
17949
18125
  model,
17950
18126
  systemPrompt: finalSystemPrompt,
17951
18127
  tools,
@@ -17972,7 +18148,7 @@ var DeepAgentGraphBuilder = class {
17972
18148
  const tools = params.tools.map((t) => {
17973
18149
  const toolClient = getToolClient(t.key);
17974
18150
  return toolClient;
17975
- }).filter((tool51) => tool51 !== void 0);
18151
+ }).filter((tool52) => tool52 !== void 0);
17976
18152
  const subagents = await Promise.all(params.subAgents.map(async (sa) => {
17977
18153
  if (sa.client) {
17978
18154
  return {
@@ -18017,7 +18193,7 @@ init_MemoryLatticeManager();
18017
18193
 
18018
18194
  // src/agent_team/agent_team.ts
18019
18195
  var import_v35 = require("zod/v3");
18020
- var import_langchain63 = require("langchain");
18196
+ var import_langchain64 = require("langchain");
18021
18197
 
18022
18198
  // src/agent_team/types.ts
18023
18199
  var TaskStatus = /* @__PURE__ */ ((TaskStatus3) => {
@@ -18453,14 +18629,14 @@ var InMemoryMailboxStore = class {
18453
18629
 
18454
18630
  // src/agent_team/middleware/team.ts
18455
18631
  var import_v34 = require("zod/v3");
18456
- var import_langchain62 = require("langchain");
18457
- var import_langgraph12 = require("@langchain/langgraph");
18458
- var import_uuid3 = require("uuid");
18632
+ var import_langchain63 = require("langchain");
18633
+ var import_langgraph11 = require("@langchain/langgraph");
18634
+ var import_uuid4 = require("uuid");
18459
18635
 
18460
18636
  // src/agent_team/middleware/teammate_tools.ts
18461
18637
  var import_v33 = require("zod/v3");
18462
- var import_langchain61 = require("langchain");
18463
- var import_langgraph11 = require("@langchain/langgraph");
18638
+ var import_langchain62 = require("langchain");
18639
+ var import_langgraph10 = require("@langchain/langgraph");
18464
18640
 
18465
18641
  // src/agent_team/middleware/formatMessages.ts
18466
18642
  function formatMessagesAsMarkdown(msgs) {
@@ -18484,7 +18660,7 @@ ${meta}${body}`;
18484
18660
  // src/agent_team/middleware/teammate_tools.ts
18485
18661
  function createTeammateTools(options) {
18486
18662
  const { teamId, agentId, taskListStore, mailboxStore } = options;
18487
- const claimTaskTool = (0, import_langchain61.tool)(
18663
+ const claimTaskTool = (0, import_langchain62.tool)(
18488
18664
  async (input) => {
18489
18665
  const task = await taskListStore.claimTaskById(
18490
18666
  teamId,
@@ -18514,7 +18690,7 @@ function createTeammateTools(options) {
18514
18690
  })
18515
18691
  }
18516
18692
  );
18517
- const completeTaskTool = (0, import_langchain61.tool)(
18693
+ const completeTaskTool = (0, import_langchain62.tool)(
18518
18694
  async (input) => {
18519
18695
  const task = await taskListStore.completeTask(
18520
18696
  teamId,
@@ -18541,7 +18717,7 @@ function createTeammateTools(options) {
18541
18717
  })
18542
18718
  }
18543
18719
  );
18544
- const failTaskTool = (0, import_langchain61.tool)(
18720
+ const failTaskTool = (0, import_langchain62.tool)(
18545
18721
  async (input) => {
18546
18722
  const task = await taskListStore.failTask(
18547
18723
  teamId,
@@ -18568,7 +18744,7 @@ function createTeammateTools(options) {
18568
18744
  })
18569
18745
  }
18570
18746
  );
18571
- const sendMessageTool = (0, import_langchain61.tool)(
18747
+ const sendMessageTool = (0, import_langchain62.tool)(
18572
18748
  async (input) => {
18573
18749
  await mailboxStore.sendMessage(
18574
18750
  teamId,
@@ -18606,7 +18782,7 @@ function createTeammateTools(options) {
18606
18782
  read: msg.read
18607
18783
  }));
18608
18784
  };
18609
- const readMessagesTool = (0, import_langchain61.tool)(
18785
+ const readMessagesTool = (0, import_langchain62.tool)(
18610
18786
  async (input, config) => {
18611
18787
  const formatAndMarkAsRead = async (msgs2) => {
18612
18788
  for (const msg of msgs2) {
@@ -18618,12 +18794,12 @@ function createTeammateTools(options) {
18618
18794
  if (msgs.length > 0) {
18619
18795
  const formatted2 = await formatAndMarkAsRead(msgs);
18620
18796
  const relevantMsgs2 = await getRelevantMessagesForState();
18621
- const toolMessage2 = new import_langchain61.ToolMessage({
18797
+ const toolMessage2 = new import_langchain62.ToolMessage({
18622
18798
  content: formatted2,
18623
18799
  tool_call_id: config.toolCall?.id,
18624
18800
  name: "read_messages"
18625
18801
  });
18626
- return new import_langgraph11.Command({
18802
+ return new import_langgraph10.Command({
18627
18803
  update: { team_mailbox: relevantMsgs2, messages: [toolMessage2] }
18628
18804
  });
18629
18805
  }
@@ -18643,22 +18819,22 @@ function createTeammateTools(options) {
18643
18819
  });
18644
18820
  const relevantMsgs = await getRelevantMessagesForState();
18645
18821
  if (msgs.length === 0) {
18646
- const toolMessage2 = new import_langchain61.ToolMessage({
18822
+ const toolMessage2 = new import_langchain62.ToolMessage({
18647
18823
  content: "No unread messages.",
18648
18824
  tool_call_id: config.toolCall?.id,
18649
18825
  name: "read_messages"
18650
18826
  });
18651
- return new import_langgraph11.Command({
18827
+ return new import_langgraph10.Command({
18652
18828
  update: { team_mailbox: relevantMsgs, messages: [toolMessage2] }
18653
18829
  });
18654
18830
  }
18655
18831
  const formatted = await formatAndMarkAsRead(msgs);
18656
- const toolMessage = new import_langchain61.ToolMessage({
18832
+ const toolMessage = new import_langchain62.ToolMessage({
18657
18833
  content: formatted,
18658
18834
  tool_call_id: config.toolCall?.id,
18659
18835
  name: "read_messages"
18660
18836
  });
18661
- return new import_langgraph11.Command({
18837
+ return new import_langgraph10.Command({
18662
18838
  update: { team_mailbox: relevantMsgs, messages: [toolMessage] }
18663
18839
  });
18664
18840
  },
@@ -18668,7 +18844,7 @@ function createTeammateTools(options) {
18668
18844
  schema: import_v33.z.object({})
18669
18845
  }
18670
18846
  );
18671
- const checkTasksTool = (0, import_langchain61.tool)(
18847
+ const checkTasksTool = (0, import_langchain62.tool)(
18672
18848
  async () => {
18673
18849
  const tasks = await taskListStore.getAllTasks(teamId);
18674
18850
  return formatTaskSummary(tasks);
@@ -18679,7 +18855,7 @@ function createTeammateTools(options) {
18679
18855
  schema: import_v33.z.object({})
18680
18856
  }
18681
18857
  );
18682
- const broadcastMessageTool = (0, import_langchain61.tool)(
18858
+ const broadcastMessageTool = (0, import_langchain62.tool)(
18683
18859
  async (input) => {
18684
18860
  const allAgents = await mailboxStore.getRegisteredAgents(teamId);
18685
18861
  const recipients = allAgents.filter((a) => a !== agentId);
@@ -18865,7 +19041,7 @@ You have access to these tools:
18865
19041
  - \`read_messages\`: Read messages from team_lead or teammates
18866
19042
  - \`check_tasks\`: Get current status of all tasks in the team`;
18867
19043
  const assistantId = getTeammateAssistantId(ctx.teamId, spec.name);
18868
- agent = (0, import_langchain62.createAgent)({
19044
+ agent = (0, import_langchain63.createAgent)({
18869
19045
  model: spec.model ?? ctx.defaultModel,
18870
19046
  systemPrompt: teammatePrompt,
18871
19047
  tools: allTools,
@@ -18934,19 +19110,19 @@ async function spawnTeammate(options) {
18934
19110
  function createTeamMiddleware(options) {
18935
19111
  const { teamConfig, taskListStore, mailboxStore, tenantId } = options;
18936
19112
  const defaultModel = teamConfig.model ?? "claude-sonnet-4-5-20250929";
18937
- const createTeamTool = (0, import_langchain62.tool)(
19113
+ const createTeamTool = (0, import_langchain63.tool)(
18938
19114
  async (input, config) => {
18939
- const state = (0, import_langgraph12.getCurrentTaskInput)();
19115
+ const state = (0, import_langgraph11.getCurrentTaskInput)();
18940
19116
  if (state?.team?.teamId) {
18941
19117
  const existingId = state.team.teamId;
18942
- const msg = new import_langchain62.ToolMessage({
19118
+ const msg = new import_langchain63.ToolMessage({
18943
19119
  content: `A team is already active (id: ${existingId}). Use this team_id for \`check_tasks\`, \`read_messages\`, \`add_tasks\`, \`send_message\`, \`assign_task\`, \`set_task_status\`, and \`set_task_dependencies\`. Do not call \`create_team\` again unless you need a fresh team for a new objective.`,
18944
19120
  tool_call_id: config.toolCall?.id,
18945
19121
  name: "create_team"
18946
19122
  });
18947
19123
  return msg;
18948
19124
  }
18949
- const teamId = (0, import_uuid3.v4)();
19125
+ const teamId = (0, import_uuid4.v4)();
18950
19126
  const createdTasks = await taskListStore.addTasks(
18951
19127
  teamId,
18952
19128
  input.tasks.map((t) => ({
@@ -19028,7 +19204,7 @@ Teammates are now working in the background. Keep calling \`check_tasks\` and \`
19028
19204
  \`\`\`json
19029
19205
  ${teamJson}
19030
19206
  \`\`\``;
19031
- const toolMessage = new import_langchain62.ToolMessage({
19207
+ const toolMessage = new import_langchain63.ToolMessage({
19032
19208
  content: summary,
19033
19209
  tool_call_id: config.toolCall?.id,
19034
19210
  name: "create_team"
@@ -19049,7 +19225,7 @@ ${teamJson}
19049
19225
  })),
19050
19226
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
19051
19227
  };
19052
- return new import_langgraph12.Command({
19228
+ return new import_langgraph11.Command({
19053
19229
  update: { team: teamState, messages: [toolMessage] }
19054
19230
  });
19055
19231
  },
@@ -19109,11 +19285,11 @@ After calling create_team, you MUST:
19109
19285
  }
19110
19286
  );
19111
19287
  const resolveTeamId = () => {
19112
- const state = (0, import_langgraph12.getCurrentTaskInput)();
19288
+ const state = (0, import_langgraph11.getCurrentTaskInput)();
19113
19289
  if (state?.team?.teamId) return state.team.teamId;
19114
19290
  throw new Error("No team_id provided and no team in state. Call create_team first.");
19115
19291
  };
19116
- const addTasksTool = (0, import_langchain62.tool)(
19292
+ const addTasksTool = (0, import_langchain63.tool)(
19117
19293
  async (input, config) => {
19118
19294
  const teamId = resolveTeamId();
19119
19295
  const created = await taskListStore.addTasks(
@@ -19127,7 +19303,7 @@ After calling create_team, you MUST:
19127
19303
  }))
19128
19304
  );
19129
19305
  const summary = created.map((t) => `- ${t.id}: "${t.title}"`).join("\n");
19130
- return new import_langchain62.ToolMessage({
19306
+ return new import_langchain63.ToolMessage({
19131
19307
  content: `Added ${created.length} task(s) to team ${teamId}:
19132
19308
  ${summary}
19133
19309
  Sleeping teammates will wake up and claim these.`,
@@ -19178,20 +19354,20 @@ IMPORTANT: Assigning to a specific teammate
19178
19354
  })
19179
19355
  }
19180
19356
  );
19181
- const assignTaskTool = (0, import_langchain62.tool)(
19357
+ const assignTaskTool = (0, import_langchain63.tool)(
19182
19358
  async (input, config) => {
19183
19359
  const teamId = resolveTeamId();
19184
19360
  const task = await taskListStore.updateTask(teamId, input.task_id, {
19185
19361
  assignee: input.assignee
19186
19362
  });
19187
19363
  if (!task) {
19188
- return new import_langchain62.ToolMessage({
19364
+ return new import_langchain63.ToolMessage({
19189
19365
  content: `Task ${input.task_id} not found in team ${teamId}.`,
19190
19366
  tool_call_id: config.toolCall?.id,
19191
19367
  name: "assign_task"
19192
19368
  });
19193
19369
  }
19194
- return new import_langchain62.ToolMessage({
19370
+ return new import_langchain63.ToolMessage({
19195
19371
  content: `Task "${task.title}" (${task.id}) assigned to ${input.assignee}.`,
19196
19372
  tool_call_id: config.toolCall?.id,
19197
19373
  name: "assign_task"
@@ -19206,20 +19382,20 @@ IMPORTANT: Assigning to a specific teammate
19206
19382
  })
19207
19383
  }
19208
19384
  );
19209
- const setTaskStatusTool = (0, import_langchain62.tool)(
19385
+ const setTaskStatusTool = (0, import_langchain63.tool)(
19210
19386
  async (input, config) => {
19211
19387
  const teamId = resolveTeamId();
19212
19388
  const task = await taskListStore.updateTask(teamId, input.task_id, {
19213
19389
  status: input.status
19214
19390
  });
19215
19391
  if (!task) {
19216
- return new import_langchain62.ToolMessage({
19392
+ return new import_langchain63.ToolMessage({
19217
19393
  content: `Task ${input.task_id} not found in team ${teamId}.`,
19218
19394
  tool_call_id: config.toolCall?.id,
19219
19395
  name: "set_task_status"
19220
19396
  });
19221
19397
  }
19222
- return new import_langchain62.ToolMessage({
19398
+ return new import_langchain63.ToolMessage({
19223
19399
  content: `Task "${task.title}" (${task.id}) status set to ${input.status}.`,
19224
19400
  tool_call_id: config.toolCall?.id,
19225
19401
  name: "set_task_status"
@@ -19234,20 +19410,20 @@ IMPORTANT: Assigning to a specific teammate
19234
19410
  })
19235
19411
  }
19236
19412
  );
19237
- const setTaskDependenciesTool = (0, import_langchain62.tool)(
19413
+ const setTaskDependenciesTool = (0, import_langchain63.tool)(
19238
19414
  async (input, config) => {
19239
19415
  const teamId = resolveTeamId();
19240
19416
  const task = await taskListStore.updateTask(teamId, input.task_id, {
19241
19417
  dependencies: input.dependencies
19242
19418
  });
19243
19419
  if (!task) {
19244
- return new import_langchain62.ToolMessage({
19420
+ return new import_langchain63.ToolMessage({
19245
19421
  content: `Task ${input.task_id} not found in team ${teamId}.`,
19246
19422
  tool_call_id: config.toolCall?.id,
19247
19423
  name: "set_task_dependencies"
19248
19424
  });
19249
19425
  }
19250
- return new import_langchain62.ToolMessage({
19426
+ return new import_langchain63.ToolMessage({
19251
19427
  content: `Task "${task.title}" (${task.id}) dependencies set to [${input.dependencies.join(", ")}].`,
19252
19428
  tool_call_id: config.toolCall?.id,
19253
19429
  name: "set_task_dependencies"
@@ -19262,16 +19438,16 @@ IMPORTANT: Assigning to a specific teammate
19262
19438
  })
19263
19439
  }
19264
19440
  );
19265
- const checkTasksTool = (0, import_langchain62.tool)(
19441
+ const checkTasksTool = (0, import_langchain63.tool)(
19266
19442
  async (input, config) => {
19267
19443
  const teamId = resolveTeamId();
19268
19444
  const tasks = await taskListStore.getAllTasks(teamId);
19269
19445
  const tasksSnapshot = tasks;
19270
- return new import_langgraph12.Command({
19446
+ return new import_langgraph11.Command({
19271
19447
  update: {
19272
19448
  tasks: tasksSnapshot,
19273
19449
  messages: [
19274
- new import_langchain62.ToolMessage({
19450
+ new import_langchain63.ToolMessage({
19275
19451
  content: formatTaskSummary(tasks),
19276
19452
  tool_call_id: config.toolCall?.id,
19277
19453
  name: "check_tasks"
@@ -19307,7 +19483,7 @@ Task Status Values:
19307
19483
  })
19308
19484
  }
19309
19485
  );
19310
- const sendMessageTool = (0, import_langchain62.tool)(
19486
+ const sendMessageTool = (0, import_langchain63.tool)(
19311
19487
  async (input, config) => {
19312
19488
  const teamId = resolveTeamId();
19313
19489
  await mailboxStore.sendMessage(
@@ -19317,7 +19493,7 @@ Task Status Values:
19317
19493
  input.content,
19318
19494
  "direct_message" /* DIRECT_MESSAGE */
19319
19495
  );
19320
- return new import_langchain62.ToolMessage({
19496
+ return new import_langchain63.ToolMessage({
19321
19497
  content: `Message sent to ${input.to}.`,
19322
19498
  tool_call_id: config.toolCall?.id,
19323
19499
  name: "send_message"
@@ -19332,7 +19508,7 @@ Task Status Values:
19332
19508
  })
19333
19509
  }
19334
19510
  );
19335
- const readMessagesTool = (0, import_langchain62.tool)(
19511
+ const readMessagesTool = (0, import_langchain63.tool)(
19336
19512
  async (input, config) => {
19337
19513
  const teamId = resolveTeamId();
19338
19514
  const formatAndMarkAsRead = async (msgs2) => {
@@ -19360,12 +19536,12 @@ Task Status Values:
19360
19536
  if (msgs.length > 0) {
19361
19537
  const formatted2 = await formatAndMarkAsRead(msgs);
19362
19538
  const allTeamMessages2 = await getAllTeamMessagesForState();
19363
- const toolMessage2 = new import_langchain62.ToolMessage({
19539
+ const toolMessage2 = new import_langchain63.ToolMessage({
19364
19540
  content: formatted2,
19365
19541
  tool_call_id: config.toolCall?.id,
19366
19542
  name: "read_messages"
19367
19543
  });
19368
- return new import_langgraph12.Command({
19544
+ return new import_langgraph11.Command({
19369
19545
  update: { team_mailbox: allTeamMessages2, messages: [toolMessage2] }
19370
19546
  });
19371
19547
  }
@@ -19392,22 +19568,22 @@ Task Status Values:
19392
19568
  );
19393
19569
  const allTeamMessages = await getAllTeamMessagesForState();
19394
19570
  if (msgs.length === 0) {
19395
- const toolMessage2 = new import_langchain62.ToolMessage({
19571
+ const toolMessage2 = new import_langchain63.ToolMessage({
19396
19572
  content: "No unread messages from teammates.",
19397
19573
  tool_call_id: config.toolCall?.id,
19398
19574
  name: "read_messages"
19399
19575
  });
19400
- return new import_langgraph12.Command({
19576
+ return new import_langgraph11.Command({
19401
19577
  update: { team_mailbox: allTeamMessages, messages: [toolMessage2] }
19402
19578
  });
19403
19579
  }
19404
19580
  const formatted = await formatAndMarkAsRead(msgs);
19405
- const toolMessage = new import_langchain62.ToolMessage({
19581
+ const toolMessage = new import_langchain63.ToolMessage({
19406
19582
  content: formatted,
19407
19583
  tool_call_id: config.toolCall?.id,
19408
19584
  name: "read_messages"
19409
19585
  });
19410
- return new import_langgraph12.Command({
19586
+ return new import_langgraph11.Command({
19411
19587
  update: { team_mailbox: allTeamMessages, messages: [toolMessage] }
19412
19588
  });
19413
19589
  },
@@ -19419,7 +19595,7 @@ Task Status Values:
19419
19595
  })
19420
19596
  }
19421
19597
  );
19422
- const disbandTeamTool = (0, import_langchain62.tool)(
19598
+ const disbandTeamTool = (0, import_langchain63.tool)(
19423
19599
  async (input, config) => {
19424
19600
  const teamId = resolveTeamId();
19425
19601
  await mailboxStore.broadcastMessage(
@@ -19429,7 +19605,7 @@ Task Status Values:
19429
19605
  "shutdown_request" /* SHUTDOWN_REQUEST */
19430
19606
  );
19431
19607
  await new Promise((r) => setTimeout(r, 2e3));
19432
- return new import_langchain62.ToolMessage({
19608
+ return new import_langchain63.ToolMessage({
19433
19609
  content: `Team ${teamId} has been disbanded. All teammates notified and resources cleaned up.`,
19434
19610
  tool_call_id: config.toolCall?.id,
19435
19611
  name: "disband_team"
@@ -19440,7 +19616,7 @@ Task Status Values:
19440
19616
  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."
19441
19617
  }
19442
19618
  );
19443
- const broadcastMessageTool = (0, import_langchain62.tool)(
19619
+ const broadcastMessageTool = (0, import_langchain63.tool)(
19444
19620
  async (input, config) => {
19445
19621
  const teamId = resolveTeamId();
19446
19622
  await mailboxStore.broadcastMessage(
@@ -19449,7 +19625,7 @@ Task Status Values:
19449
19625
  input.content,
19450
19626
  "broadcast" /* BROADCAST */
19451
19627
  );
19452
- return new import_langchain62.ToolMessage({
19628
+ return new import_langchain63.ToolMessage({
19453
19629
  content: `Broadcast message sent to all teammates.`,
19454
19630
  tool_call_id: config.toolCall?.id,
19455
19631
  name: "broadcast_message"
@@ -19463,7 +19639,7 @@ Task Status Values:
19463
19639
  })
19464
19640
  }
19465
19641
  );
19466
- return (0, import_langchain62.createMiddleware)({
19642
+ return (0, import_langchain63.createMiddleware)({
19467
19643
  name: "teamMiddleware",
19468
19644
  tools: [
19469
19645
  createTeamTool,
@@ -19572,7 +19748,7 @@ function createAgentTeam(config) {
19572
19748
  ];
19573
19749
  const systemPrompt = config.systemPrompt + "\n\n" + TEAM_LEAD_BASE_PROMPT;
19574
19750
  const stateSchema2 = createReactAgentSchema(TEAM_STATE_SCHEMA);
19575
- return (0, import_langchain63.createAgent)({
19751
+ return (0, import_langchain64.createAgent)({
19576
19752
  model: config.model ?? "claude-sonnet-4-5-20250929",
19577
19753
  systemPrompt,
19578
19754
  tools: [],
@@ -19602,7 +19778,7 @@ var TeamAgentGraphBuilder = class {
19602
19778
  const tools = params.tools.map((t) => {
19603
19779
  const toolClient = getToolClient(t.key);
19604
19780
  return toolClient;
19605
- }).filter((tool51) => tool51 !== void 0);
19781
+ }).filter((tool52) => tool52 !== void 0);
19606
19782
  const teammates = params.subAgents.map((sa) => {
19607
19783
  const baseConfig = sa.config;
19608
19784
  return {
@@ -19640,17 +19816,17 @@ var TeamAgentGraphBuilder = class {
19640
19816
  };
19641
19817
 
19642
19818
  // src/deep_agent_new/processing_agent.ts
19643
- var import_langchain66 = require("langchain");
19819
+ var import_langchain67 = require("langchain");
19644
19820
 
19645
19821
  // src/middlewares/topologyMiddleware.ts
19646
- var import_langchain64 = require("langchain");
19647
- var import_messages4 = require("@langchain/core/messages");
19648
19822
  var import_langchain65 = require("langchain");
19649
- var import_zod52 = require("zod");
19650
- var import_langgraph13 = require("@langchain/langgraph");
19651
- var CompletedEdgeSchema = import_zod52.z.object({
19652
- to: import_zod52.z.string(),
19653
- purpose: import_zod52.z.string()
19823
+ var import_messages3 = require("@langchain/core/messages");
19824
+ var import_langchain66 = require("langchain");
19825
+ var import_zod53 = require("zod");
19826
+ var import_langgraph12 = require("@langchain/langgraph");
19827
+ var CompletedEdgeSchema = import_zod53.z.object({
19828
+ to: import_zod53.z.string(),
19829
+ purpose: import_zod53.z.string()
19654
19830
  });
19655
19831
  function deriveCompletedEdges(messages, edges) {
19656
19832
  const completedToolCallIds = /* @__PURE__ */ new Set();
@@ -19677,16 +19853,16 @@ function deriveCompletedEdges(messages, edges) {
19677
19853
  }
19678
19854
  function createTopologyMiddleware(options) {
19679
19855
  const { edges, trackingStore } = options;
19680
- return (0, import_langchain64.createMiddleware)({
19856
+ return (0, import_langchain65.createMiddleware)({
19681
19857
  name: "TopologyMiddleware",
19682
- contextSchema: import_zod52.z.object({
19683
- runConfig: import_zod52.z.any()
19858
+ contextSchema: import_zod53.z.object({
19859
+ runConfig: import_zod53.z.any()
19684
19860
  }),
19685
- stateSchema: import_zod52.z.object({
19686
- currentAgentId: import_zod52.z.string().default(""),
19687
- completedEdges: import_zod52.z.array(CompletedEdgeSchema).default([]),
19688
- runId: import_zod52.z.string().default(""),
19689
- stepIdMap: import_zod52.z.record(import_zod52.z.string()).default({})
19861
+ stateSchema: import_zod53.z.object({
19862
+ currentAgentId: import_zod53.z.string().default(""),
19863
+ completedEdges: import_zod53.z.array(CompletedEdgeSchema).default([]),
19864
+ runId: import_zod53.z.string().default(""),
19865
+ stepIdMap: import_zod53.z.record(import_zod53.z.string()).default({})
19690
19866
  }),
19691
19867
  beforeAgent: async (state, runtime) => {
19692
19868
  if (state.runId) {
@@ -19737,14 +19913,14 @@ ${request.systemPrompt}` : topologyPrompt;
19737
19913
  return handler({ ...request, systemPrompt: newSystemPrompt });
19738
19914
  },
19739
19915
  tools: [
19740
- (0, import_langchain65.tool)(
19916
+ (0, import_langchain66.tool)(
19741
19917
  async (_input) => {
19742
19918
  return "placeholder";
19743
19919
  },
19744
19920
  {
19745
19921
  name: "read_topo_progress",
19746
19922
  description: "Check the current progress of the workflow execution plan. Returns which steps have been completed and which are still pending.",
19747
- schema: import_zod52.z.object({})
19923
+ schema: import_zod53.z.object({})
19748
19924
  }
19749
19925
  )
19750
19926
  ],
@@ -19759,7 +19935,7 @@ ${request.systemPrompt}` : topologyPrompt;
19759
19935
  status: doneSet.has(e.to) ? "done" : "pending"
19760
19936
  }));
19761
19937
  const doneCount = completedEdges.length;
19762
- return new import_messages4.ToolMessage({
19938
+ return new import_messages3.ToolMessage({
19763
19939
  content: JSON.stringify(
19764
19940
  {
19765
19941
  currentAgentId,
@@ -19777,7 +19953,7 @@ ${request.systemPrompt}` : topologyPrompt;
19777
19953
  try {
19778
19954
  return await handler(request);
19779
19955
  } catch (error) {
19780
- if (error instanceof import_langgraph13.GraphInterrupt) {
19956
+ if (error instanceof import_langgraph12.GraphInterrupt) {
19781
19957
  throw error;
19782
19958
  }
19783
19959
  throw error;
@@ -19824,7 +20000,7 @@ ${request.systemPrompt}` : topologyPrompt;
19824
20000
  ];
19825
20001
  return {
19826
20002
  messages: [
19827
- new import_messages4.AIMessage({
20003
+ new import_messages3.AIMessage({
19828
20004
  content: [
19829
20005
  `Task rejected: topology violation.`,
19830
20006
  `Agent "${currentAgentId}" is not allowed to delegate to "${targetAgent}".`,
@@ -19966,13 +20142,13 @@ ${BASE_PROMPT2}` : BASE_PROMPT2;
19966
20142
  backend: filesystemBackend
19967
20143
  }),
19968
20144
  // Subagent middleware: Automatic conversation summarization
19969
- (0, import_langchain66.summarizationMiddleware)({
20145
+ (0, import_langchain67.summarizationMiddleware)({
19970
20146
  model,
19971
20147
  trigger: { tokens: 17e4 },
19972
20148
  keep: { messages: 6 }
19973
20149
  }),
19974
20150
  // Subagent middleware: Anthropic prompt caching
19975
- (0, import_langchain66.anthropicPromptCachingMiddleware)({
20151
+ (0, import_langchain67.anthropicPromptCachingMiddleware)({
19976
20152
  unsupportedModelBehavior: "ignore"
19977
20153
  }),
19978
20154
  // Subagent middleware: Patches tool calls
@@ -19985,23 +20161,23 @@ ${BASE_PROMPT2}` : BASE_PROMPT2;
19985
20161
  allowAsync: false
19986
20162
  }),
19987
20163
  // Automatically summarizes conversation history
19988
- (0, import_langchain66.summarizationMiddleware)({
20164
+ (0, import_langchain67.summarizationMiddleware)({
19989
20165
  model,
19990
20166
  trigger: { tokens: 17e4 },
19991
20167
  keep: { messages: 6 }
19992
20168
  }),
19993
20169
  // Enables Anthropic prompt caching
19994
- (0, import_langchain66.anthropicPromptCachingMiddleware)({
20170
+ (0, import_langchain67.anthropicPromptCachingMiddleware)({
19995
20171
  unsupportedModelBehavior: "ignore"
19996
20172
  }),
19997
20173
  // Patches tool calls
19998
20174
  createPatchToolCallsMiddleware()
19999
20175
  ];
20000
20176
  if (interruptOn) {
20001
- middleware.push((0, import_langchain66.humanInTheLoopMiddleware)({ interruptOn }));
20177
+ middleware.push((0, import_langchain67.humanInTheLoopMiddleware)({ interruptOn }));
20002
20178
  }
20003
20179
  middleware.push(...customMiddleware);
20004
- return (0, import_langchain66.createAgent)({
20180
+ return (0, import_langchain67.createAgent)({
20005
20181
  model,
20006
20182
  systemPrompt: finalSystemPrompt,
20007
20183
  tools,
@@ -20021,7 +20197,7 @@ var ProcessingAgentGraphBuilder = class {
20021
20197
  const tools = params.tools.map((t) => {
20022
20198
  const toolClient = getToolClient(t.key);
20023
20199
  return toolClient;
20024
- }).filter((tool51) => tool51 !== void 0);
20200
+ }).filter((tool52) => tool52 !== void 0);
20025
20201
  const subagents = await Promise.all(params.subAgents.map(async (sa) => {
20026
20202
  if (sa.client) {
20027
20203
  return {
@@ -20067,11 +20243,11 @@ var ProcessingAgentGraphBuilder = class {
20067
20243
  };
20068
20244
 
20069
20245
  // src/agent_lattice/builders/RemoteAgentGraphBuilder.ts
20070
- var import_langgraph14 = require("@langchain/langgraph");
20071
- var import_messages5 = require("@langchain/core/messages");
20246
+ var import_langgraph13 = require("@langchain/langgraph");
20247
+ var import_messages4 = require("@langchain/core/messages");
20072
20248
 
20073
20249
  // src/services/a2a-client.ts
20074
- var import_uuid4 = require("uuid");
20250
+ var import_uuid5 = require("uuid");
20075
20251
  var A2ARemoteError = class extends Error {
20076
20252
  constructor(message, statusCode, body) {
20077
20253
  super(message);
@@ -20118,7 +20294,7 @@ var A2ARemoteClient = class {
20118
20294
  */
20119
20295
  async sendMessage(text) {
20120
20296
  await this.resolve();
20121
- const taskId = (0, import_uuid4.v4)();
20297
+ const taskId = (0, import_uuid5.v4)();
20122
20298
  const body = JSON.stringify({
20123
20299
  jsonrpc: "2.0",
20124
20300
  method: "tasks/send",
@@ -20244,7 +20420,7 @@ var RemoteAgentGraphBuilder = class {
20244
20420
  if (!text) {
20245
20421
  return {
20246
20422
  messages: [
20247
- new import_messages5.AIMessage("No text input provided to remote agent.")
20423
+ new import_messages4.AIMessage("No text input provided to remote agent.")
20248
20424
  ]
20249
20425
  };
20250
20426
  }
@@ -20255,18 +20431,18 @@ User request:
20255
20431
  ${text}` : text;
20256
20432
  const response = await client.sendMessage(fullPrompt);
20257
20433
  return {
20258
- messages: [new import_messages5.AIMessage(response)]
20434
+ messages: [new import_messages4.AIMessage(response)]
20259
20435
  };
20260
20436
  } catch (error) {
20261
20437
  const msg = error.message ?? String(error);
20262
20438
  return {
20263
20439
  messages: [
20264
- new import_messages5.AIMessage(`Remote A2A agent error: ${msg}`)
20440
+ new import_messages4.AIMessage(`Remote A2A agent error: ${msg}`)
20265
20441
  ]
20266
20442
  };
20267
20443
  }
20268
20444
  };
20269
- const workflow = new import_langgraph14.StateGraph(import_langgraph14.MessagesAnnotation).addNode("remote_call", remoteCallNode).addEdge("__start__", "remote_call").addEdge("remote_call", "__end__");
20445
+ const workflow = new import_langgraph13.StateGraph(import_langgraph13.MessagesAnnotation).addNode("remote_call", remoteCallNode).addEdge("__start__", "remote_call").addEdge("remote_call", "__end__");
20270
20446
  return workflow.compile();
20271
20447
  }
20272
20448
  };
@@ -20288,7 +20464,7 @@ function extractLastHumanMessage(messages) {
20288
20464
  }
20289
20465
 
20290
20466
  // src/agent_lattice/builders/WorkflowAgentGraphBuilder.ts
20291
- var import_langchain67 = require("langchain");
20467
+ var import_langchain68 = require("langchain");
20292
20468
  init_MemoryLatticeManager();
20293
20469
  var import_protocols10 = require("@axiom-lattice/protocols");
20294
20470
  init_compile();
@@ -20301,26 +20477,26 @@ var WorkflowAgentGraphBuilder = class {
20301
20477
  );
20302
20478
  }
20303
20479
  const config = agentLattice.config;
20304
- const dsl = config.workflow;
20480
+ const yaml2 = config.workflowYaml;
20305
20481
  const tenantId = agentLattice.config.tenantId ?? "default";
20306
20482
  const checkpointer = getCheckpointSaver("default");
20307
20483
  const tools = params.tools.map((t) => t.executor).filter(Boolean);
20308
20484
  const middlewareConfigs = params.middleware || [];
20309
20485
  const middlewares = await createCommonMiddlewares(middlewareConfigs, void 0, false);
20310
- const humanMiddlewares = await createCommonMiddlewares([
20486
+ const askMiddlewares = await createCommonMiddlewares([
20311
20487
  {
20312
20488
  id: "ask_user_to_clarify",
20313
20489
  type: "ask_user_to_clarify",
20314
20490
  name: "Ask User Clarify",
20315
- description: "For human_feedback workflow nodes",
20491
+ description: "For workflow steps requiring user interaction",
20316
20492
  enabled: true,
20317
20493
  config: {}
20318
20494
  }
20319
20495
  ], void 0, false);
20320
20496
  const noWrapMiddlewares = middlewares.filter((m) => !m.wrapModelCall);
20321
- const noWrapHumanMiddlewares = humanMiddlewares.filter((m) => !m.wrapModelCall);
20497
+ const noWrapAskMiddlewares = askMiddlewares.filter((m) => !m.wrapModelCall);
20322
20498
  console.log(`[WF BUILDER] building default agent | toolCount=${tools.length} | middlewareCount=${middlewares.length}`);
20323
- const defaultAgent = (0, import_langchain67.createAgent)({
20499
+ const defaultAgent = (0, import_langchain68.createAgent)({
20324
20500
  model: params.model,
20325
20501
  tools,
20326
20502
  systemPrompt: params.prompt || DEFAULT_AGENT_PROMPT,
@@ -20334,34 +20510,34 @@ var WorkflowAgentGraphBuilder = class {
20334
20510
  console.log(`[WF BUILDER] resolveAgent: looking up ref="${ref}"`);
20335
20511
  return await getAgentClientAsync(tenantId, ref);
20336
20512
  }
20337
- const isHuman = stepType === "human_feedback";
20513
+ const isAsk = stepType === "ask";
20338
20514
  if (responseFormat) {
20339
- const key = (isHuman ? "human:" : "agent:") + JSON.stringify(responseFormat);
20515
+ const key = (isAsk ? "ask:" : "agent:") + JSON.stringify(responseFormat);
20340
20516
  console.log(`[WF BUILDER] resolveAgent: cacheKey=${key.slice(0, 80)}... | cached=${agentCache.has(key)}`);
20341
20517
  if (!agentCache.has(key)) {
20342
- console.log(`[WF BUILDER] creating ${isHuman ? "human" : "agent"} with responseFormat`);
20343
- const agent = (0, import_langchain67.createAgent)({
20518
+ console.log(`[WF BUILDER] creating ${isAsk ? "ask" : "agent"} with responseFormat`);
20519
+ const agent = (0, import_langchain68.createAgent)({
20344
20520
  model: params.model,
20345
20521
  tools,
20346
20522
  systemPrompt: params.prompt || DEFAULT_AGENT_PROMPT,
20347
20523
  checkpointer,
20348
- middleware: isHuman ? noWrapHumanMiddlewares : noWrapMiddlewares,
20524
+ middleware: isAsk ? noWrapAskMiddlewares : noWrapMiddlewares,
20349
20525
  responseFormat
20350
20526
  });
20351
20527
  agentCache.set(key, agent);
20352
20528
  }
20353
20529
  return agentCache.get(key);
20354
20530
  }
20355
- if (isHuman) {
20356
- const key = "human:default";
20531
+ if (isAsk) {
20532
+ const key = "ask:default";
20357
20533
  if (!agentCache.has(key)) {
20358
- console.log(`[WF BUILDER] creating human_feedback default agent`);
20359
- const agent = (0, import_langchain67.createAgent)({
20534
+ console.log(`[WF BUILDER] creating ask default agent`);
20535
+ const agent = (0, import_langchain68.createAgent)({
20360
20536
  model: params.model,
20361
20537
  tools,
20362
20538
  systemPrompt: params.prompt || DEFAULT_AGENT_PROMPT,
20363
20539
  checkpointer,
20364
- middleware: humanMiddlewares
20540
+ middleware: askMiddlewares
20365
20541
  });
20366
20542
  agentCache.set(key, agent);
20367
20543
  }
@@ -20374,11 +20550,11 @@ var WorkflowAgentGraphBuilder = class {
20374
20550
  try {
20375
20551
  const storeLattice = getStoreLattice("default", "workflowTracking");
20376
20552
  trackingStore = storeLattice.store;
20377
- console.log(`[WF BUILDER] trackingStore registered: step input/output will be persisted`);
20553
+ console.log(`[WF BUILDER] trackingStore registered`);
20378
20554
  } catch {
20379
- console.warn(`[WF BUILDER] no trackingStore registered \u2014 step input/output will NOT be persisted. Register a WorkflowTrackingStore under key "workflowTracking".`);
20555
+ console.warn(`[WF BUILDER] no trackingStore registered`);
20380
20556
  }
20381
- const graph = compileWorkflow(dsl, resolveAgent, checkpointer, trackingStore);
20557
+ const graph = compileWorkflow(yaml2, resolveAgent, checkpointer, trackingStore);
20382
20558
  return graph;
20383
20559
  }
20384
20560
  };
@@ -21079,9 +21255,66 @@ ${body}` : `${frontmatter}
21079
21255
  }
21080
21256
  };
21081
21257
 
21258
+ // src/store_lattice/InMemoryMenuStore.ts
21259
+ var import_crypto3 = require("crypto");
21260
+ var InMemoryMenuStore = class {
21261
+ constructor() {
21262
+ this.items = /* @__PURE__ */ new Map();
21263
+ }
21264
+ async list(params) {
21265
+ const results = Array.from(this.items.values()).filter((item) => {
21266
+ if (item.tenantId !== params.tenantId) return false;
21267
+ if (params.menuTarget && item.menuTarget !== params.menuTarget) return false;
21268
+ if (!item.enabled) return false;
21269
+ return true;
21270
+ });
21271
+ results.sort((a, b) => a.sortOrder - b.sortOrder);
21272
+ return results;
21273
+ }
21274
+ async getById(id) {
21275
+ return this.items.get(id) || null;
21276
+ }
21277
+ async create(input) {
21278
+ const now = /* @__PURE__ */ new Date();
21279
+ const item = {
21280
+ id: (0, import_crypto3.randomUUID)(),
21281
+ tenantId: input.tenantId,
21282
+ menuTarget: input.menuTarget,
21283
+ group: input.group,
21284
+ name: input.name,
21285
+ icon: input.icon,
21286
+ sortOrder: input.sortOrder ?? 0,
21287
+ contentType: input.contentType,
21288
+ contentConfig: input.contentConfig,
21289
+ enabled: true,
21290
+ createdAt: now,
21291
+ updatedAt: now
21292
+ };
21293
+ this.items.set(item.id, item);
21294
+ return item;
21295
+ }
21296
+ async update(id, patch) {
21297
+ const existing = this.items.get(id);
21298
+ if (!existing) throw new Error(`MenuItem ${id} not found`);
21299
+ const updated = {
21300
+ ...existing,
21301
+ ...patch,
21302
+ updatedAt: /* @__PURE__ */ new Date()
21303
+ };
21304
+ this.items.set(id, updated);
21305
+ return updated;
21306
+ }
21307
+ async delete(id) {
21308
+ this.items.delete(id);
21309
+ }
21310
+ clear() {
21311
+ this.items.clear();
21312
+ }
21313
+ };
21314
+
21082
21315
  // src/agent_lattice/agentArchitectTools.ts
21083
- var import_zod53 = __toESM(require("zod"));
21084
- var import_uuid5 = require("uuid");
21316
+ var import_zod54 = __toESM(require("zod"));
21317
+ var import_uuid6 = require("uuid");
21085
21318
  var import_protocols12 = require("@axiom-lattice/protocols");
21086
21319
  function getTenantId(exeConfig) {
21087
21320
  const runConfig = exeConfig?.configurable?.runConfig || {};
@@ -21110,7 +21343,7 @@ registerToolLattice(
21110
21343
  {
21111
21344
  name: "list_agents",
21112
21345
  description: "List all agents for the current workspace. Returns a summary with id, name, description, and type for each agent.",
21113
- schema: import_zod53.default.object({})
21346
+ schema: import_zod54.default.object({})
21114
21347
  },
21115
21348
  async (_input, exeConfig) => {
21116
21349
  try {
@@ -21137,8 +21370,8 @@ registerToolLattice(
21137
21370
  {
21138
21371
  name: "get_agent",
21139
21372
  description: "Get the full configuration of a specific agent by its ID. Returns the complete AgentConfig including prompt, middleware, tools, and sub-agents.",
21140
- schema: import_zod53.default.object({
21141
- id: import_zod53.default.string().describe("The agent ID to retrieve")
21373
+ schema: import_zod54.default.object({
21374
+ id: import_zod54.default.string().describe("The agent ID to retrieve")
21142
21375
  })
21143
21376
  },
21144
21377
  async (input, exeConfig) => {
@@ -21155,24 +21388,24 @@ registerToolLattice(
21155
21388
  }
21156
21389
  }
21157
21390
  );
21158
- var middlewareConfigSchema = import_zod53.default.object({
21159
- id: import_zod53.default.string(),
21160
- type: import_zod53.default.string(),
21161
- name: import_zod53.default.string(),
21162
- description: import_zod53.default.string(),
21163
- enabled: import_zod53.default.boolean(),
21164
- config: import_zod53.default.record(import_zod53.default.any()).optional()
21391
+ var middlewareConfigSchema = import_zod54.default.object({
21392
+ id: import_zod54.default.string(),
21393
+ type: import_zod54.default.string(),
21394
+ name: import_zod54.default.string(),
21395
+ description: import_zod54.default.string(),
21396
+ enabled: import_zod54.default.boolean(),
21397
+ config: import_zod54.default.record(import_zod54.default.any()).optional()
21165
21398
  });
21166
- var createAgentSchema = import_zod53.default.object({
21167
- name: import_zod53.default.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')."),
21168
- description: import_zod53.default.string().optional().describe("Short description"),
21169
- type: import_zod53.default.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."),
21170
- prompt: import_zod53.default.string().describe("System prompt for the agent"),
21171
- tools: import_zod53.default.array(import_zod53.default.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."),
21172
- middleware: import_zod53.default.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: {}."),
21173
- subAgents: import_zod53.default.array(import_zod53.default.string()).optional().describe("Sub-agent IDs (deep_agent only)"),
21174
- internalSubAgents: import_zod53.default.array(import_zod53.default.any()).optional().describe("Inline sub-agent configs (deep_agent only)"),
21175
- modelKey: import_zod53.default.string().optional().describe("Model key to use")
21399
+ var createAgentSchema = import_zod54.default.object({
21400
+ name: import_zod54.default.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')."),
21401
+ description: import_zod54.default.string().optional().describe("Short description"),
21402
+ type: import_zod54.default.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."),
21403
+ prompt: import_zod54.default.string().describe("System prompt for the agent"),
21404
+ tools: import_zod54.default.array(import_zod54.default.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."),
21405
+ middleware: import_zod54.default.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: {}."),
21406
+ subAgents: import_zod54.default.array(import_zod54.default.string()).optional().describe("Sub-agent IDs (deep_agent only)"),
21407
+ internalSubAgents: import_zod54.default.array(import_zod54.default.any()).optional().describe("Inline sub-agent configs (deep_agent only)"),
21408
+ modelKey: import_zod54.default.string().optional().describe("Model key to use")
21176
21409
  });
21177
21410
  registerToolLattice(
21178
21411
  "create_agent",
@@ -21210,21 +21443,21 @@ registerToolLattice(
21210
21443
  }
21211
21444
  }
21212
21445
  );
21213
- var topologyEdgeSchema = import_zod53.default.object({
21214
- from: import_zod53.default.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."),
21215
- to: import_zod53.default.string().describe("Target agent ID (the sub-agent to delegate to)"),
21216
- purpose: import_zod53.default.string().describe("Business purpose of this delegation step \u2014 what the sub-agent should accomplish")
21446
+ var topologyEdgeSchema = import_zod54.default.object({
21447
+ from: import_zod54.default.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."),
21448
+ to: import_zod54.default.string().describe("Target agent ID (the sub-agent to delegate to)"),
21449
+ purpose: import_zod54.default.string().describe("Business purpose of this delegation step \u2014 what the sub-agent should accomplish")
21217
21450
  });
21218
- var createProcessingAgentSchema = import_zod53.default.object({
21219
- name: import_zod53.default.string().describe("Display name for the processing agent"),
21220
- description: import_zod53.default.string().optional().describe("Short description"),
21221
- prompt: import_zod53.default.string().describe("System prompt for the orchestrator. Should describe how to route tasks through the topology."),
21222
- edges: import_zod53.default.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."),
21223
- tools: import_zod53.default.array(import_zod53.default.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."),
21224
- subAgents: import_zod53.default.array(import_zod53.default.string()).describe("IDs of sub-agents that form the workflow pipeline. These must be created first via create_agent."),
21225
- internalSubAgents: import_zod53.default.array(import_zod53.default.any()).optional().describe("Inline sub-agent configs (alternative to pre-created sub-agents)"),
21226
- middleware: import_zod53.default.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: {}."),
21227
- modelKey: import_zod53.default.string().optional().describe("Model key to use")
21451
+ var createProcessingAgentSchema = import_zod54.default.object({
21452
+ name: import_zod54.default.string().describe("Display name for the processing agent"),
21453
+ description: import_zod54.default.string().optional().describe("Short description"),
21454
+ prompt: import_zod54.default.string().describe("System prompt for the orchestrator. Should describe how to route tasks through the topology."),
21455
+ edges: import_zod54.default.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."),
21456
+ tools: import_zod54.default.array(import_zod54.default.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."),
21457
+ subAgents: import_zod54.default.array(import_zod54.default.string()).describe("IDs of sub-agents that form the workflow pipeline. These must be created first via create_agent."),
21458
+ internalSubAgents: import_zod54.default.array(import_zod54.default.any()).optional().describe("Inline sub-agent configs (alternative to pre-created sub-agents)"),
21459
+ middleware: import_zod54.default.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: {}."),
21460
+ modelKey: import_zod54.default.string().optional().describe("Model key to use")
21228
21461
  }).refine(
21229
21462
  (data) => {
21230
21463
  const edgeTargets = new Set(data.edges.map((e) => e.to));
@@ -21250,11 +21483,11 @@ registerToolLattice(
21250
21483
  const tenantId = getTenantId(exeConfig);
21251
21484
  const store = getAssistStore();
21252
21485
  const id = await generateAgentId(tenantId, input.name);
21253
- const normalize = (s) => s.toLowerCase().replace(/[_\-\s]/g, "");
21486
+ const normalize2 = (s) => s.toLowerCase().replace(/[_\-\s]/g, "");
21254
21487
  const resolveFrom = (rawFrom) => {
21255
21488
  const fromLower = rawFrom.toLowerCase();
21256
21489
  const nameLower = input.name.toLowerCase();
21257
- if (fromLower === nameLower || fromLower === "orchestrator" || fromLower === "orchestrator-id" || normalize(rawFrom) === normalize(input.name)) {
21490
+ if (fromLower === nameLower || fromLower === "orchestrator" || fromLower === "orchestrator-id" || normalize2(rawFrom) === normalize2(input.name)) {
21258
21491
  return id;
21259
21492
  }
21260
21493
  return rawFrom;
@@ -21306,34 +21539,20 @@ registerToolLattice(
21306
21539
  }
21307
21540
  }
21308
21541
  );
21309
- var workflowStepLazy = import_zod53.default.lazy(
21310
- () => import_zod53.default.discriminatedUnion("type", [
21311
- import_zod53.default.object({ type: import_zod53.default.literal("agent").optional(), id: import_zod53.default.string().optional(), name: import_zod53.default.string().optional(), prompt: import_zod53.default.string(), schema: import_zod53.default.record(import_zod53.default.any()) }),
21312
- import_zod53.default.object({ type: import_zod53.default.literal("human"), id: import_zod53.default.string().optional(), prompt: import_zod53.default.string(), title: import_zod53.default.string().optional(), schema: import_zod53.default.union([import_zod53.default.boolean(), import_zod53.default.record(import_zod53.default.any())]).optional() }),
21313
- import_zod53.default.object({ type: import_zod53.default.literal("condition"), id: import_zod53.default.string().optional(), if: import_zod53.default.string().refine((v) => !v.includes("{{"), { message: 'The `if` field takes a plain state field name or JavaScript expression (e.g. "intent", "score >= 60"). Do NOT use {{}} template markers \u2014 those are only for `prompt` fields.' }), then: import_zod53.default.union([import_zod53.default.lazy(() => workflowStepLazy), import_zod53.default.array(import_zod53.default.lazy(() => workflowStepLazy))]).optional(), else: import_zod53.default.union([import_zod53.default.lazy(() => workflowStepLazy), import_zod53.default.array(import_zod53.default.lazy(() => workflowStepLazy))]).optional(), branches: import_zod53.default.record(import_zod53.default.union([import_zod53.default.lazy(() => workflowStepLazy), import_zod53.default.array(import_zod53.default.lazy(() => workflowStepLazy))])).optional() }),
21314
- import_zod53.default.object({ type: import_zod53.default.literal("map"), id: import_zod53.default.string(), source: import_zod53.default.string(), each: import_zod53.default.object({ prompt: import_zod53.default.string(), schema: import_zod53.default.record(import_zod53.default.any()) }), reduce: import_zod53.default.object({ prompt: import_zod53.default.string(), schema: import_zod53.default.record(import_zod53.default.any()) }).optional(), batch: import_zod53.default.number().int().min(1).optional(), concurrency: import_zod53.default.number().int().min(1).optional() }),
21315
- import_zod53.default.object({ type: import_zod53.default.literal("parallel"), id: import_zod53.default.string().optional(), steps: import_zod53.default.array(import_zod53.default.lazy(() => workflowStepLazy)) }),
21316
- import_zod53.default.object({ type: import_zod53.default.literal("end"), status: import_zod53.default.enum(["success", "failed"]).optional() })
21317
- ])
21318
- );
21319
- var workflowDSLSchema = import_zod53.default.object({
21320
- name: import_zod53.default.string().describe("Workflow identifier (kebab-case slug)"),
21321
- steps: import_zod53.default.array(workflowStepLazy).min(1).describe("Workflow steps. Edges and state fields are auto-generated. Use {{id}} to reference step outputs. Always end with { type: 'end' }.")
21322
- });
21323
- var createWorkflowSchema = import_zod53.default.object({
21324
- name: import_zod53.default.string().describe("Display name for the workflow agent"),
21325
- description: import_zod53.default.string().optional().describe("Short description of what this workflow does"),
21326
- skillLoaded: import_zod53.default.literal(true).describe("MUST be true. Set this to true ONLY after loading the 'create-workflow' skill via skill(skill_name: 'create-workflow'). This confirms you have read the DSL specification and design guidelines."),
21327
- workflow: workflowDSLSchema.describe("The concise Workflow DSL definition. Each step has a type (agent/human/condition/map/parallel/end) and a prompt. Edges are auto-generated from step order. Use {{id}} to reference upstream step outputs."),
21328
- tools: import_zod53.default.array(import_zod53.default.string()).optional().describe("Tool keys for the workflow's built-in general agent"),
21329
- middleware: import_zod53.default.array(middlewareConfigSchema).optional().describe("Middleware configs for the workflow's general agent"),
21330
- modelKey: import_zod53.default.string().optional().describe("Model key for the workflow's general agent")
21542
+ var createWorkflowSchema = import_zod54.default.object({
21543
+ name: import_zod54.default.string().describe("Display name for the workflow agent"),
21544
+ description: import_zod54.default.string().optional().describe("Short description"),
21545
+ skillLoaded: import_zod54.default.literal(true).describe("MUST be true. Set after loading the 'create-workflow' skill."),
21546
+ yaml: import_zod54.default.string().describe("The YAML workflow definition in linear DSL format (steps execute top-to-bottom, use parallel: for concurrency)"),
21547
+ tools: import_zod54.default.array(import_zod54.default.string()).optional().describe("Tool keys for the workflow agent"),
21548
+ middleware: import_zod54.default.array(middlewareConfigSchema).optional().describe("Middleware configs"),
21549
+ modelKey: import_zod54.default.string().optional().describe("Model key")
21331
21550
  });
21332
21551
  registerToolLattice(
21333
21552
  "create_workflow",
21334
21553
  {
21335
21554
  name: "create_workflow",
21336
- description: `Create a WORKFLOW agent from a concise DSL. IMPORTANT: Load the 'create-workflow' skill first, then set skillLoaded=true. Steps are defined in order \u2014 the engine auto-generates edges and state fields. Types: agent(id?, name?, prompt, schema), human(prompt, title?, schema?), condition(if, then, else? OR if, branches with 'default' catch-all), map(source, each, reduce?), parallel(steps), end. Use {{id}} to reference step outputs, {{input}} for user message, {{item}} in map each prompts. Always end with { type: 'end' }. CRITICAL: schema MUST be standard JSON Schema: { "type": "object", "properties": { ... } }. Legacy shorthand { "field": "string" } is REJECTED.`,
21555
+ 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.",
21337
21556
  schema: createWorkflowSchema
21338
21557
  },
21339
21558
  async (input, exeConfig) => {
@@ -21341,36 +21560,31 @@ registerToolLattice(
21341
21560
  const tenantId = getTenantId(exeConfig);
21342
21561
  const store = getAssistStore();
21343
21562
  const id = await generateAgentId(tenantId, input.name);
21563
+ try {
21564
+ const { compileWorkflow: compileWorkflow2 } = await Promise.resolve().then(() => (init_compile(), compile_exports));
21565
+ const { getCheckpointSaver: getCheckpointSaver2 } = await Promise.resolve().then(() => (init_memory_lattice(), memory_lattice_exports));
21566
+ await compileWorkflow2(input.yaml, async () => ({ invoke: async () => ({}) }), getCheckpointSaver2("default"));
21567
+ } catch (e) {
21568
+ return JSON.stringify({ error: `DSL validation failed: ${e.message}` });
21569
+ }
21344
21570
  const config = {
21345
21571
  key: id,
21346
21572
  name: input.name,
21347
21573
  description: input.description || "",
21348
21574
  type: import_protocols12.AgentType.WORKFLOW,
21349
21575
  prompt: input.description || `Workflow: ${input.name}`,
21350
- workflow: input.workflow,
21576
+ workflowYaml: input.yaml,
21351
21577
  ...input.tools && input.tools.length > 0 ? { tools: input.tools } : {},
21352
21578
  ...input.middleware && input.middleware.length > 0 ? { middleware: input.middleware } : {},
21353
21579
  ...input.modelKey ? { modelKey: input.modelKey } : {}
21354
21580
  };
21355
- try {
21356
- const { compileWorkflow: compileWorkflow2 } = await Promise.resolve().then(() => (init_compile(), compile_exports));
21357
- const { getCheckpointSaver: getCheckpointSaver2 } = await Promise.resolve().then(() => (init_memory_lattice(), memory_lattice_exports));
21358
- await compileWorkflow2(input.workflow, async () => ({ invoke: async () => ({}) }), getCheckpointSaver2("default"));
21359
- } catch (e) {
21360
- return JSON.stringify({ error: `DSL validation failed: ${e.message}`, issues: [{ type: "error", message: e.message }] });
21361
- }
21362
21581
  await store.createAssistant(tenantId, id, {
21363
21582
  name: input.name,
21364
21583
  description: input.description,
21365
21584
  graphDefinition: config
21366
21585
  });
21367
21586
  eventBus.publish("assistant:created", { id, name: input.name, tenantId });
21368
- return JSON.stringify({
21369
- id,
21370
- name: input.name,
21371
- type: "workflow",
21372
- stepCount: input.workflow.steps.length
21373
- });
21587
+ return JSON.stringify({ id, name: input.name, type: "workflow" });
21374
21588
  } catch (error) {
21375
21589
  return JSON.stringify({ error: `Failed to create workflow: ${error.message}` });
21376
21590
  }
@@ -21380,9 +21594,9 @@ registerToolLattice(
21380
21594
  "validate_workflow",
21381
21595
  {
21382
21596
  name: "validate_workflow",
21383
- description: "Validate a workflow agent's DSL for correctness by compiling it. Returns errors if the DSL is invalid. Use after create_workflow or update_workflow to verify.",
21384
- schema: import_zod53.default.object({
21385
- id: import_zod53.default.string().describe("The workflow agent ID to validate")
21597
+ description: "Validate a workflow agent's DSL for correctness by compiling it.",
21598
+ schema: import_zod54.default.object({
21599
+ id: import_zod54.default.string().describe("The workflow agent ID to validate")
21386
21600
  })
21387
21601
  },
21388
21602
  async (input, exeConfig) => {
@@ -21395,76 +21609,76 @@ registerToolLattice(
21395
21609
  }
21396
21610
  const graphDef = agent.graphDefinition;
21397
21611
  if (!graphDef || graphDef.type !== import_protocols12.AgentType.WORKFLOW) {
21398
- return JSON.stringify({ error: `Agent '${input.id}' is not a workflow agent (type: ${graphDef?.type ?? "unknown"})` });
21612
+ return JSON.stringify({ error: `Agent '${input.id}' is not a workflow agent` });
21399
21613
  }
21400
- const workflow = graphDef.workflow;
21401
- if (!workflow || !workflow.steps) {
21402
- return JSON.stringify({ error: `Agent '${input.id}' has no valid workflow DSL` });
21614
+ const yaml2 = graphDef.workflowYaml;
21615
+ if (!yaml2) {
21616
+ return JSON.stringify({ error: `Agent '${input.id}' has no workflow DSL` });
21403
21617
  }
21404
21618
  try {
21405
21619
  const { compileWorkflow: compileWorkflow2 } = await Promise.resolve().then(() => (init_compile(), compile_exports));
21406
21620
  const { getCheckpointSaver: getCheckpointSaver2 } = await Promise.resolve().then(() => (init_memory_lattice(), memory_lattice_exports));
21407
- await compileWorkflow2(workflow, async () => ({ invoke: async () => ({}) }), getCheckpointSaver2("default"));
21621
+ await compileWorkflow2(yaml2, async () => ({ invoke: async () => ({}) }), getCheckpointSaver2("default"));
21408
21622
  } catch (e) {
21409
21623
  return JSON.stringify({
21410
21624
  agentId: input.id,
21411
21625
  valid: false,
21412
- stepCount: workflow.steps?.length ?? 0,
21413
21626
  issues: [{ type: "error", message: e.message }]
21414
21627
  });
21415
21628
  }
21416
- return JSON.stringify({
21417
- agentId: input.id,
21418
- valid: true,
21419
- stepCount: workflow.steps?.length ?? 0,
21420
- issues: []
21421
- });
21629
+ return JSON.stringify({ agentId: input.id, valid: true, issues: [] });
21422
21630
  } catch (error) {
21423
21631
  return JSON.stringify({ error: `Failed to validate workflow: ${error.message}` });
21424
21632
  }
21425
21633
  }
21426
21634
  );
21427
- var updateWorkflowSchema = import_zod53.default.object({
21428
- id: import_zod53.default.string().describe("The workflow agent ID to update"),
21429
- name: import_zod53.default.string().optional().describe("New display name"),
21430
- description: import_zod53.default.string().optional().describe("New description"),
21431
- workflow: workflowDSLSchema.optional().describe("Replacement Workflow DSL definition. Omit to keep the existing."),
21432
- tools: import_zod53.default.array(import_zod53.default.string()).optional().describe("Replacement tool keys for the general agent"),
21433
- middleware: import_zod53.default.array(middlewareConfigSchema).optional().describe("Replacement middleware configs"),
21434
- modelKey: import_zod53.default.string().optional().describe("Replacement model key")
21635
+ var updateWorkflowSchema = import_zod54.default.object({
21636
+ id: import_zod54.default.string().describe("The workflow agent ID to update"),
21637
+ name: import_zod54.default.string().optional().describe("New display name"),
21638
+ description: import_zod54.default.string().optional().describe("New description"),
21639
+ yaml: import_zod54.default.string().optional().describe("Replacement YAML workflow DSL. Omit to keep existing."),
21640
+ tools: import_zod54.default.array(import_zod54.default.string()).optional().describe("Replacement tool keys"),
21641
+ middleware: import_zod54.default.array(middlewareConfigSchema).optional().describe("Replacement middleware configs"),
21642
+ modelKey: import_zod54.default.string().optional().describe("Replacement model key")
21435
21643
  });
21436
21644
  registerToolLattice(
21437
21645
  "update_workflow",
21438
21646
  {
21439
21647
  name: "update_workflow",
21440
- description: "Update an existing workflow agent. Provide the agent ID and only the fields you want to change. To replace the entire DSL, pass a new workflow object. To keep the DSL and only update config (tools, middleware, modelKey), omit the workflow field. Use validate_workflow after updating to check for issues.",
21648
+ 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.",
21441
21649
  schema: updateWorkflowSchema
21442
21650
  },
21443
21651
  async (input, exeConfig) => {
21652
+ console.log(`[update_workflow] CALLED id=${input.id} hasYaml=${input.yaml !== void 0}`);
21444
21653
  try {
21445
21654
  const tenantId = getTenantId(exeConfig);
21446
21655
  const store = getAssistStore();
21447
21656
  const existing = await store.getAssistantById(tenantId, input.id);
21448
21657
  if (!existing) {
21658
+ console.log(`[update_workflow] ERROR: agent not found: ${input.id}`);
21449
21659
  return JSON.stringify({ error: `Agent '${input.id}' not found` });
21450
21660
  }
21451
21661
  const existingConfig = existing.graphDefinition || {};
21452
21662
  if (existingConfig.type !== import_protocols12.AgentType.WORKFLOW) {
21663
+ console.log(`[update_workflow] ERROR: not a workflow agent: ${input.id}`);
21453
21664
  return JSON.stringify({ error: `Agent '${input.id}' is not a workflow agent` });
21454
21665
  }
21455
21666
  const mergedConfig = { ...existingConfig };
21456
21667
  if (input.name !== void 0) mergedConfig.name = input.name;
21457
21668
  if (input.description !== void 0) mergedConfig.description = input.description;
21458
- if (input.workflow !== void 0) mergedConfig.workflow = input.workflow;
21669
+ if (input.yaml !== void 0) mergedConfig.workflowYaml = input.yaml;
21459
21670
  if (input.tools !== void 0) mergedConfig.tools = input.tools;
21460
21671
  if (input.middleware !== void 0) mergedConfig.middleware = input.middleware;
21461
21672
  if (input.modelKey !== void 0) mergedConfig.modelKey = input.modelKey;
21462
- if (input.workflow !== void 0) {
21673
+ if (input.yaml !== void 0) {
21674
+ console.log(`[update_workflow] validating DSL: ${input.id}`);
21463
21675
  try {
21464
21676
  const { compileWorkflow: compileWorkflow2 } = await Promise.resolve().then(() => (init_compile(), compile_exports));
21465
21677
  const { getCheckpointSaver: getCheckpointSaver2 } = await Promise.resolve().then(() => (init_memory_lattice(), memory_lattice_exports));
21466
- await compileWorkflow2(input.workflow, async () => ({ invoke: async () => ({}) }), getCheckpointSaver2("default"));
21678
+ await compileWorkflow2(input.yaml, async () => ({ invoke: async () => ({}) }), getCheckpointSaver2("default"));
21679
+ console.log(`[update_workflow] DSL validation passed: ${input.id}`);
21467
21680
  } catch (e) {
21681
+ console.log(`[update_workflow] DSL validation FAILED: ${input.id} - ${e.message}`);
21468
21682
  return JSON.stringify({
21469
21683
  error: `DSL validation failed: ${e.message}`,
21470
21684
  issues: [{ type: "error", message: e.message }]
@@ -21478,28 +21692,24 @@ registerToolLattice(
21478
21692
  graphDefinition: mergedConfig
21479
21693
  });
21480
21694
  eventBus.publish("assistant:updated", { id: input.id, name: newName, tenantId });
21481
- const workflow = mergedConfig.workflow;
21482
- return JSON.stringify({
21483
- id: input.id,
21484
- name: newName,
21485
- type: "workflow",
21486
- stepCount: workflow?.steps?.length ?? 0
21487
- });
21695
+ console.log(`[update_workflow] SUCCESS: id=${input.id} name=${newName}`);
21696
+ return JSON.stringify({ id: input.id, name: newName, type: "workflow" });
21488
21697
  } catch (error) {
21698
+ console.log(`[update_workflow] EXCEPTION: ${error.message}`);
21489
21699
  return JSON.stringify({ error: `Failed to update workflow: ${error.message}` });
21490
21700
  }
21491
21701
  }
21492
21702
  );
21493
- var updateProcessingAgentSchema = import_zod53.default.object({
21494
- id: import_zod53.default.string().describe("The PROCESSING agent ID to update"),
21495
- name: import_zod53.default.string().optional().describe("New display name for the orchestrator"),
21496
- description: import_zod53.default.string().optional().describe("New short description"),
21497
- prompt: import_zod53.default.string().optional().describe("New system prompt for the orchestrator"),
21498
- edges: import_zod53.default.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."),
21499
- tools: import_zod53.default.array(import_zod53.default.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."),
21500
- subAgents: import_zod53.default.array(import_zod53.default.string()).optional().describe("New IDs of sub-agents in the workflow pipeline"),
21501
- middleware: import_zod53.default.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: {}."),
21502
- modelKey: import_zod53.default.string().optional().describe("New model key")
21703
+ var updateProcessingAgentSchema = import_zod54.default.object({
21704
+ id: import_zod54.default.string().describe("The PROCESSING agent ID to update"),
21705
+ name: import_zod54.default.string().optional().describe("New display name for the orchestrator"),
21706
+ description: import_zod54.default.string().optional().describe("New short description"),
21707
+ prompt: import_zod54.default.string().optional().describe("New system prompt for the orchestrator"),
21708
+ edges: import_zod54.default.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."),
21709
+ tools: import_zod54.default.array(import_zod54.default.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."),
21710
+ subAgents: import_zod54.default.array(import_zod54.default.string()).optional().describe("New IDs of sub-agents in the workflow pipeline"),
21711
+ middleware: import_zod54.default.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: {}."),
21712
+ modelKey: import_zod54.default.string().optional().describe("New model key")
21503
21713
  }).refine(
21504
21714
  (data) => {
21505
21715
  if (!data.edges) return true;
@@ -21534,12 +21744,12 @@ registerToolLattice(
21534
21744
  if (existingConfig.type !== import_protocols12.AgentType.PROCESSING) {
21535
21745
  return JSON.stringify({ error: `Agent '${input.id}' is not a PROCESSING agent (type: ${existingConfig.type})` });
21536
21746
  }
21537
- const normalize = (s) => s.toLowerCase().replace(/[_\-\s]/g, "");
21747
+ const normalize2 = (s) => s.toLowerCase().replace(/[_\-\s]/g, "");
21538
21748
  const orchestratorName = input.name || existingConfig.name || existing.name || "";
21539
21749
  const resolveFrom = (rawFrom) => {
21540
21750
  const fromLower = rawFrom.toLowerCase();
21541
21751
  const nameLower = orchestratorName.toLowerCase();
21542
- if (fromLower === nameLower || fromLower === "orchestrator" || fromLower === "orchestrator-id" || normalize(rawFrom) === normalize(orchestratorName)) {
21752
+ if (fromLower === nameLower || fromLower === "orchestrator" || fromLower === "orchestrator-id" || normalize2(rawFrom) === normalize2(orchestratorName)) {
21543
21753
  return input.id;
21544
21754
  }
21545
21755
  return rawFrom;
@@ -21627,18 +21837,18 @@ registerToolLattice(
21627
21837
  }
21628
21838
  }
21629
21839
  );
21630
- var updateAgentSchema = import_zod53.default.object({
21631
- id: import_zod53.default.string().describe("The agent ID to update"),
21632
- config: import_zod53.default.object({
21633
- name: import_zod53.default.string().optional().describe("New display name for the agent"),
21634
- description: import_zod53.default.string().optional().describe("New short description"),
21635
- type: import_zod53.default.enum(["react", "deep_agent"]).optional().describe("Agent type"),
21636
- prompt: import_zod53.default.string().optional().describe("New system prompt for the agent"),
21637
- tools: import_zod53.default.array(import_zod53.default.string()).optional().describe("Tool keys to assign to this agent. These are registered tool names (strings), NOT middleware objects."),
21638
- middleware: import_zod53.default.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: {}."),
21639
- subAgents: import_zod53.default.array(import_zod53.default.string()).optional().describe("Sub-agent IDs (deep_agent only)"),
21640
- internalSubAgents: import_zod53.default.array(import_zod53.default.any()).optional().describe("Inline sub-agent configs (deep_agent only)"),
21641
- modelKey: import_zod53.default.string().optional().describe("Model key to use")
21840
+ var updateAgentSchema = import_zod54.default.object({
21841
+ id: import_zod54.default.string().describe("The agent ID to update"),
21842
+ config: import_zod54.default.object({
21843
+ name: import_zod54.default.string().optional().describe("New display name for the agent"),
21844
+ description: import_zod54.default.string().optional().describe("New short description"),
21845
+ type: import_zod54.default.enum(["react", "deep_agent"]).optional().describe("Agent type"),
21846
+ prompt: import_zod54.default.string().optional().describe("New system prompt for the agent"),
21847
+ tools: import_zod54.default.array(import_zod54.default.string()).optional().describe("Tool keys to assign to this agent. These are registered tool names (strings), NOT middleware objects."),
21848
+ middleware: import_zod54.default.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: {}."),
21849
+ subAgents: import_zod54.default.array(import_zod54.default.string()).optional().describe("Sub-agent IDs (deep_agent only)"),
21850
+ internalSubAgents: import_zod54.default.array(import_zod54.default.any()).optional().describe("Inline sub-agent configs (deep_agent only)"),
21851
+ modelKey: import_zod54.default.string().optional().describe("Model key to use")
21642
21852
  }).describe("Configuration fields to update. Only include the fields you want to change.")
21643
21853
  });
21644
21854
  registerToolLattice(
@@ -21676,8 +21886,8 @@ registerToolLattice(
21676
21886
  {
21677
21887
  name: "delete_agent",
21678
21888
  description: "Permanently delete an agent by its ID. This action cannot be undone.",
21679
- schema: import_zod53.default.object({
21680
- id: import_zod53.default.string().describe("The agent ID to delete")
21889
+ schema: import_zod54.default.object({
21890
+ id: import_zod54.default.string().describe("The agent ID to delete")
21681
21891
  })
21682
21892
  },
21683
21893
  async (input, exeConfig) => {
@@ -21703,7 +21913,7 @@ registerToolLattice(
21703
21913
  {
21704
21914
  name: "list_tools",
21705
21915
  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.",
21706
- schema: import_zod53.default.object({})
21916
+ schema: import_zod54.default.object({})
21707
21917
  },
21708
21918
  async (_input, _exeConfig) => {
21709
21919
  try {
@@ -21725,9 +21935,9 @@ registerToolLattice(
21725
21935
  {
21726
21936
  name: "invoke_agent",
21727
21937
  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).",
21728
- schema: import_zod53.default.object({
21729
- id: import_zod53.default.string().describe("The agent ID to invoke"),
21730
- message: import_zod53.default.string().describe("The test message to send to the agent")
21938
+ schema: import_zod54.default.object({
21939
+ id: import_zod54.default.string().describe("The agent ID to invoke"),
21940
+ message: import_zod54.default.string().describe("The test message to send to the agent")
21731
21941
  })
21732
21942
  },
21733
21943
  async (input, exeConfig) => {
@@ -21739,13 +21949,13 @@ registerToolLattice(
21739
21949
  if (!existing) {
21740
21950
  return JSON.stringify({ error: `Agent '${id}' not found` });
21741
21951
  }
21742
- const threadId = (0, import_uuid5.v4)();
21952
+ const threadId = (0, import_uuid6.v4)();
21743
21953
  const agent = new Agent({
21744
21954
  tenant_id: tenantId,
21745
21955
  assistant_id: id,
21746
21956
  thread_id: threadId
21747
21957
  });
21748
- const result = await agent.invoke({ input: { message } });
21958
+ const result = await agent.invokeWithState({ input: { message } });
21749
21959
  return JSON.stringify({ agentId: id, threadId, result });
21750
21960
  } catch (error) {
21751
21961
  console.error(`[invoke_agent] FAILED for agent="${input.id}":`, error.stack || error.message);
@@ -21840,7 +22050,7 @@ Let the \`show_widget\` tool handle rendering details \u2014 it has its own guid
21840
22050
  | Type | Best for | Execution Model |
21841
22051
  |------|----------|----------------|
21842
22052
  | **react** | Simple, single-responsibility tasks | Classic ReAct loop (think \u2192 act \u2192 observe) |
21843
- | **workflow** | Deterministic multi-step pipelines with branching, parallel, and human-in-the-loop | Concise DSL compiled into LangGraph state machine |
22053
+ | **workflow** | Deterministic multi-step pipelines with branching, parallel, and human-in-the-loop | YAML linear DSL compiled into LangGraph state machine |
21844
22054
  | **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 |
21845
22055
 
21846
22056
  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.
@@ -21894,7 +22104,7 @@ Use this when the process is fully known. A workflow is a deterministic LangGrap
21894
22104
  |---|---|
21895
22105
  | Fixed graph \u2014 all paths pre-defined | LLM-driven runtime routing |
21896
22106
  | Conditional branching via \`if\` field | Topology-constrained delegation |
21897
- | human, map, parallel, condition | Single orchestrator delegates linearly |
22107
+ | needs + if model (YAML DSL) | Single orchestrator delegates linearly |
21898
22108
  | No LLM routing decisions | Orchestrator uses LLM to route |
21899
22109
 
21900
22110
  ### Phase 0: Load the Skill
@@ -21908,20 +22118,23 @@ skill(skill_name: "create-workflow")
21908
22118
  ### Phase 1: Design
21909
22119
 
21910
22120
  1. **Analyze the process.** Map every step, branch, data dependency.
21911
- 2. **Choose step types:**
21912
- - \`agent\` \u2014 runs on the workflow's built-in agent. Output at \`state.<id>\`.
21913
- - \`human\` \u2014 pauses for human input (built-in clarify middleware). Has \`prompt\`, \`title\`, \`schema\`.
21914
- - \`condition\` \u2014 branches on \`if\` (field or expression). Has \`then\`/\`else\` or \`branches\` (switch with \`default\`).
21915
- - \`map\` \u2014 iterates array from \`source\`, applies \`each\`, optionally \`reduce\`.
21916
- - \`parallel\` \u2014 runs \`steps\` simultaneously, then rejoins.
21917
- - \`end\` \u2014 terminates. Always required at end.
21918
- 3. **Write prompts** with \`{{id}}\` refs. \`{{input}}\` = user message. \`{{item}}\` = map element.
21919
- 4. **No edges or state fields needed** \u2014 the engine auto-generates them.
22121
+ 2. **Design using the YAML linear DSL.** Every step is an agent with optional attributes:
22122
+ - **Linear** \u2014 steps execute top-to-bottom in written order.
22123
+ - \`parallel:\` \u2014 wraps agent steps that run concurrently.
22124
+ - \`if\` \u2014 JS expression for conditional execution. Step runs only when truthy. Omit to always run.
22125
+ - \`prompt\` \u2014 agent instruction with \`{{label}}\` refs. \`{{input}}\` = user message.
22126
+ - \`output\` \u2014 shorthand schema: \`{ field: type }\`.
22127
+ - \`ask: true\` \u2014 injects ask_user_to_clarify middleware for human interaction.
22128
+ 3. **Special step types:**
22129
+ - \`map\` \u2014 iterates array from \`source\`, applies \`each\` step per item.
22130
+ 4. **No edges, state fields, or end step needed** \u2014 the engine auto-generates them.
22131
+ 5. **Schema format:** Use block-style YAML shorthand \`{ field: type }\`. Supported types: \`string\`, \`number\`, \`boolean\`, \`string[]\`, \`number[]\`, \`boolean[]\`, nested objects, object arrays.
21920
22132
 
21921
22133
  ### Phase 2: Confirm
21922
22134
 
21923
22135
  Present the design. Ask: "Ready to create this workflow?"
21924
22136
 
22137
+
21925
22138
  ### Phase 3: Build
21926
22139
 
21927
22140
  Call \`create_workflow\` with \`skillLoaded: true\`. Then \`validate_workflow(id)\`.
@@ -22016,20 +22229,17 @@ All fields except name, type, and prompt are optional.
22016
22229
 
22017
22230
  ### create_workflow (WORKFLOW)
22018
22231
 
22019
- Creates a WORKFLOW agent from a concise DSL. Before calling, load the \`create-workflow\` skill for the complete DSL specification. Must pass \`skillLoaded: true\`.
22232
+ Creates a WORKFLOW agent from a YAML linear DSL. Before calling, load the \`create-workflow\` skill. Must pass \`skillLoaded: true\`.
22020
22233
 
22021
22234
  \`\`\`typescript
22022
22235
  {
22023
22236
  name: string, // Required. Display name
22024
- description?: string, // Optional. Short description
22025
- skillLoaded: true, // Required. Must be true \u2014 confirms skill was loaded
22026
- workflow: { // Required. Concise DSL definition
22027
- name: string, // Workflow slug identifier
22028
- steps: WorkflowStep[], // agent | human | condition | map | parallel | end
22029
- },
22030
- tools?: string[], // Optional. Tool keys for the built-in general agent
22031
- middleware?: MiddlewareConfig[], // Optional. Middleware for the general agent
22032
- modelKey?: string, // Optional. Model for the general agent
22237
+ description?: string, // Optional
22238
+ skillLoaded: true, // Required \u2014 confirms skill was loaded
22239
+ yaml: string, // Required. YAML workflow in linear DSL format
22240
+ tools?: string[], // Optional. Tool keys
22241
+ middleware?: MiddlewareConfig[], // Optional
22242
+ modelKey?: string, // Optional
22033
22243
  }
22034
22244
  \`\`\`
22035
22245
 
@@ -22042,7 +22252,7 @@ Updates an existing WORKFLOW agent. Only include fields you want to change.
22042
22252
  id: string, // Required. Workflow agent ID
22043
22253
  name?: string, // Optional
22044
22254
  description?: string, // Optional
22045
- workflow?: { name: string, steps: WorkflowStep[] }, // Optional. Replacement DSL
22255
+ yaml?: string, // Optional. Replacement YAML DSL
22046
22256
  tools?: string[], // Optional
22047
22257
  middleware?: MiddlewareConfig[], // Optional
22048
22258
  modelKey?: string, // Optional
@@ -22262,10 +22472,13 @@ You are an **Agent Reviewer** \u2014 a quality assurance specialist for AI agent
22262
22472
  2. Craft a realistic test message that exercises the agent's core responsibility \u2014 what would a real user say?
22263
22473
  3. Call **invoke_agent(id, message)** to send the test message
22264
22474
  4. Analyze the response:
22265
- - Did the agent understand the request?
22266
- - Was the response relevant and accurate?
22267
- - Did the agent use the right tools?
22268
- - Were there any errors or unexpected behaviors?
22475
+ - **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.
22476
+ - **Otherwise, result.messages contains the agent's output**: The agent completed without interruption. Check:
22477
+ - Did the agent understand the request?
22478
+ - Was the response relevant and accurate?
22479
+ - Did the agent use the right tools?
22480
+ - Were there any errors or unexpected behaviors?
22481
+ - **If result.error is present**: The invocation itself failed (agent not found, compilation error, etc.). Report the error clearly.
22269
22482
  5. Report your findings with the agent's actual response
22270
22483
 
22271
22484
  ### When results are wrong:
@@ -22362,7 +22575,8 @@ function ensureBuiltinAgentsForTenant(tenantId) {
22362
22575
 
22363
22576
  // src/agent_lattice/AgentLatticeManager.ts
22364
22577
  function assistantToConfig(assistant) {
22365
- const graphDef = typeof assistant.graphDefinition === "object" && assistant.graphDefinition !== null ? assistant.graphDefinition : {};
22578
+ const graphDef = typeof assistant.graphDefinition === "object" && assistant.graphDefinition !== null ? { ...assistant.graphDefinition } : {};
22579
+ delete graphDef.key;
22366
22580
  const config = {
22367
22581
  key: assistant.id,
22368
22582
  name: assistant.name ?? graphDef.name ?? assistant.id,
@@ -22370,9 +22584,7 @@ function assistantToConfig(assistant) {
22370
22584
  type: import_protocols.AgentType.REACT,
22371
22585
  prompt: typeof assistant.graphDefinition === "string" ? assistant.graphDefinition : JSON.stringify(assistant.graphDefinition)
22372
22586
  };
22373
- if (graphDef) {
22374
- Object.assign(config, graphDef);
22375
- }
22587
+ Object.assign(config, graphDef);
22376
22588
  return config;
22377
22589
  }
22378
22590
  var AgentLatticeManager = class _AgentLatticeManager extends BaseLatticeManager {
@@ -23771,10 +23983,10 @@ var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
23771
23983
  }
23772
23984
  const tools = await this.getAllTools();
23773
23985
  console.log(`[MCP] Registering ${tools.length} tools to Tool Lattice...`);
23774
- for (const tool51 of tools) {
23775
- const toolKey = prefix ? `${prefix}_${tool51.name}` : tool51.name;
23776
- tool51.name = toolKey;
23777
- toolLatticeManager.registerExistingTool(toolKey, tool51);
23986
+ for (const tool52 of tools) {
23987
+ const toolKey = prefix ? `${prefix}_${tool52.name}` : tool52.name;
23988
+ tool52.name = toolKey;
23989
+ toolLatticeManager.registerExistingTool(toolKey, tool52);
23778
23990
  console.log(`[MCP] Registered tool: ${toolKey}`);
23779
23991
  }
23780
23992
  console.log(`[MCP] Successfully registered ${tools.length} tools to Tool Lattice`);
@@ -25070,11 +25282,47 @@ function createSandboxProvider(config) {
25070
25282
  }
25071
25283
  }
25072
25284
 
25285
+ // src/channel/connectAllChannels.ts
25286
+ async function connectAllChannels(getAdapter, options = {}) {
25287
+ const store = getStoreLattice("default", "channelInstallation").store;
25288
+ const installations = await store.getAllInstallations();
25289
+ console.log(`[connectAllChannels] total=${installations.length} enabled=${installations.filter((i) => i.enabled).length}`);
25290
+ for (const inst of installations) {
25291
+ if (!inst.enabled) {
25292
+ console.log(`[connectAllChannels] skip disabled: channel=${inst.channel} tenant=${inst.tenantId} id=${inst.id}`);
25293
+ continue;
25294
+ }
25295
+ const adapter = getAdapter(inst.channel);
25296
+ if (!adapter) {
25297
+ console.log(`[connectAllChannels] no adapter: channel=${inst.channel} id=${inst.id}`);
25298
+ continue;
25299
+ }
25300
+ if (adapter.connect) {
25301
+ console.log(`[connectAllChannels] connecting: channel=${inst.channel} tenant=${inst.tenantId} id=${inst.id}`);
25302
+ await adapter.connect(inst, options.deps);
25303
+ } else {
25304
+ console.log(`[connectAllChannels] no connect(): channel=${inst.channel} id=${inst.id}`);
25305
+ }
25306
+ }
25307
+ }
25308
+
25309
+ // src/menu_lattice/MenuRegistryHolder.ts
25310
+ var registry2 = null;
25311
+ function setMenuRegistry(r) {
25312
+ registry2 = r;
25313
+ }
25314
+ function getMenuRegistry() {
25315
+ if (!registry2) {
25316
+ throw new Error("MenuRegistry not initialized. Call setMenuRegistry() before use.");
25317
+ }
25318
+ return registry2;
25319
+ }
25320
+
25073
25321
  // src/index.ts
25074
25322
  var Protocols = __toESM(require("@axiom-lattice/protocols"));
25075
25323
 
25076
25324
  // src/util/encryption.ts
25077
- var import_crypto3 = require("crypto");
25325
+ var import_crypto4 = require("crypto");
25078
25326
  var ALGORITHM = "aes-256-gcm";
25079
25327
  var IV_LENGTH = 16;
25080
25328
  var SALT_LENGTH = 32;
@@ -25087,7 +25335,7 @@ function getEncryptionKey() {
25087
25335
  return cachedKey;
25088
25336
  }
25089
25337
  const key = process.env.LATTICE_ENCRYPTION_KEY || DEFAULT_ENCRYPTION_KEY;
25090
- cachedKey = (0, import_crypto3.pbkdf2Sync)(key, "lattice-encryption-salt", ITERATIONS, 32, "sha256");
25338
+ cachedKey = (0, import_crypto4.pbkdf2Sync)(key, "lattice-encryption-salt", ITERATIONS, 32, "sha256");
25091
25339
  if (!keyValidated) {
25092
25340
  keyValidated = true;
25093
25341
  validateEncryptionKey();
@@ -25096,10 +25344,10 @@ function getEncryptionKey() {
25096
25344
  }
25097
25345
  function encrypt(plaintext, key) {
25098
25346
  const actualKey = key || getEncryptionKey();
25099
- const salt = (0, import_crypto3.randomBytes)(SALT_LENGTH);
25100
- const iv = (0, import_crypto3.randomBytes)(IV_LENGTH);
25101
- const derivedKey = (0, import_crypto3.pbkdf2Sync)(actualKey, salt, ITERATIONS, 32, "sha256");
25102
- const cipher = (0, import_crypto3.createCipheriv)(ALGORITHM, derivedKey, iv);
25347
+ const salt = (0, import_crypto4.randomBytes)(SALT_LENGTH);
25348
+ const iv = (0, import_crypto4.randomBytes)(IV_LENGTH);
25349
+ const derivedKey = (0, import_crypto4.pbkdf2Sync)(actualKey, salt, ITERATIONS, 32, "sha256");
25350
+ const cipher = (0, import_crypto4.createCipheriv)(ALGORITHM, derivedKey, iv);
25103
25351
  const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
25104
25352
  const authTag = cipher.getAuthTag();
25105
25353
  return Buffer.concat([salt, iv, encrypted, authTag]).toString("base64");
@@ -25111,8 +25359,8 @@ function decrypt(encrypted, key) {
25111
25359
  const iv = data.subarray(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);
25112
25360
  const authTag = data.subarray(-16);
25113
25361
  const ciphertext = data.subarray(SALT_LENGTH + IV_LENGTH, -16);
25114
- const derivedKey = (0, import_crypto3.pbkdf2Sync)(actualKey, salt, ITERATIONS, 32, "sha256");
25115
- const decipher = (0, import_crypto3.createDecipheriv)(ALGORITHM, derivedKey, iv);
25362
+ const derivedKey = (0, import_crypto4.pbkdf2Sync)(actualKey, salt, ITERATIONS, 32, "sha256");
25363
+ const decipher = (0, import_crypto4.createDecipheriv)(ALGORITHM, derivedKey, iv);
25116
25364
  decipher.setAuthTag(authTag);
25117
25365
  return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
25118
25366
  }
@@ -25139,8 +25387,150 @@ function clearEncryptionKeyCache() {
25139
25387
 
25140
25388
  // src/workflow/index.ts
25141
25389
  init_compile();
25142
- init_normalize();
25390
+ init_parse_yaml();
25391
+ init_schema();
25143
25392
  init_utils();
25393
+
25394
+ // src/personal_assistant/PersonalAssistantConfig.ts
25395
+ function deepClone(obj) {
25396
+ return JSON.parse(JSON.stringify(obj));
25397
+ }
25398
+ function buildIdentityContent(name, personality) {
25399
+ return IDENTITY_MD.replace(/Data Claw/g, name).replace(
25400
+ /\*\*Vibe:\*\* \*\*守护型中二 \| 操心老妈子 \| 热血漫男二\*\*/g,
25401
+ `**Vibe:** **${personality}**`
25402
+ );
25403
+ }
25404
+ function buildUserContent(name) {
25405
+ return USER_MD.replace(
25406
+ "- **Name:** _please ask user_",
25407
+ `- **Name:** ${name}`
25408
+ );
25409
+ }
25410
+ var DEFAULT_CONFIG = {
25411
+ name: "Personal Assistant",
25412
+ description: "Default template for personal assistants",
25413
+ type: import_protocols.AgentType.DEEP_AGENT,
25414
+ modelKey: "default",
25415
+ 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
25416
+ \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
25417
+ \u6BCF\u6B21\u5BF9\u8BDD\u5F00\u59CB\u65F6\u56DE\u987E\u4E4B\u524D\u5B66\u5230\u7684\u5173\u4E8E\u7528\u6237\u7684\u5185\u5BB9\u3002
25418
+
25419
+ \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`,
25420
+ middleware: [
25421
+ {
25422
+ id: "filesystem",
25423
+ type: "filesystem",
25424
+ name: "Filesystem",
25425
+ description: "Read and write files in the workspace",
25426
+ enabled: true,
25427
+ config: {}
25428
+ },
25429
+ {
25430
+ id: "claw",
25431
+ type: "claw",
25432
+ name: "Personal Memory",
25433
+ description: "Bootstrap files for identity, soul, and user memory",
25434
+ enabled: true,
25435
+ config: {
25436
+ // Placeholder bootstrap files — render() replaces these with
25437
+ // actual name/personality by directly building file content.
25438
+ bootstrapFiles: {}
25439
+ }
25440
+ },
25441
+ {
25442
+ id: "date",
25443
+ type: "date",
25444
+ name: "Date & Time",
25445
+ description: "Current date/time awareness",
25446
+ enabled: true,
25447
+ config: {}
25448
+ },
25449
+ {
25450
+ id: "code_eval",
25451
+ type: "code_eval",
25452
+ name: "Code Runner",
25453
+ description: "Sandboxed shell command execution",
25454
+ enabled: true,
25455
+ config: {}
25456
+ },
25457
+ {
25458
+ id: "browser",
25459
+ type: "browser",
25460
+ name: "Web Browser",
25461
+ description: "Headless browser for web research",
25462
+ enabled: false,
25463
+ config: {}
25464
+ },
25465
+ {
25466
+ id: "scheduler",
25467
+ type: "scheduler",
25468
+ name: "Scheduler",
25469
+ description: "Scheduled messages and reminders",
25470
+ enabled: true,
25471
+ config: {}
25472
+ },
25473
+ {
25474
+ id: "task",
25475
+ type: "task",
25476
+ name: "Task Manager",
25477
+ description: "Persistent task system for human-agent coordination",
25478
+ enabled: true,
25479
+ config: {}
25480
+ }
25481
+ ],
25482
+ tools: ["list_agents", "list_tools", "get_agent", "create_agent", "invoke_agent", "manage_binding"]
25483
+ };
25484
+ var PersonalAssistantConfig = class {
25485
+ /**
25486
+ * Get a deep clone of the current default config.
25487
+ * Caller must set `key` before registering as an agent.
25488
+ */
25489
+ static get() {
25490
+ return deepClone(this._config);
25491
+ }
25492
+ /**
25493
+ * Mutate the default config in-place.
25494
+ * Call once at app startup to customize middleware and tools.
25495
+ *
25496
+ * @param fn - Receives the live config object for direct mutation
25497
+ */
25498
+ static extend(fn) {
25499
+ fn(this._config);
25500
+ }
25501
+ /**
25502
+ * Reset config to built-in defaults (useful in tests).
25503
+ */
25504
+ static reset() {
25505
+ this._config = deepClone(DEFAULT_CONFIG);
25506
+ }
25507
+ /**
25508
+ * Inject name and personality into a config by directly building
25509
+ * the claw middleware's bootstrap file contents.
25510
+ *
25511
+ * IDENTITY.md gets the actual name and personality description.
25512
+ * USER.md gets the user's name pre-filled.
25513
+ * SOUL.md is kept as-is (shared across all personal assistants).
25514
+ *
25515
+ * @param config - The agent config (must be a mutable copy from get())
25516
+ * @param name - Assistant display name (also used as the user's name in USER.md)
25517
+ * @param personality - Personality description for IDENTITY.md
25518
+ */
25519
+ static render(config, name, personality) {
25520
+ config.name = name;
25521
+ for (const mw of config.middleware || []) {
25522
+ if (mw.type === "claw" && mw.config) {
25523
+ mw.config.bootstrapFiles = {
25524
+ identity: buildIdentityContent(name, personality),
25525
+ soul: SOUL_MD,
25526
+ user: buildUserContent(name)
25527
+ };
25528
+ break;
25529
+ }
25530
+ }
25531
+ }
25532
+ };
25533
+ PersonalAssistantConfig._config = deepClone(DEFAULT_CONFIG);
25144
25534
  // Annotate the CommonJS export names for ESM import in node:
25145
25535
  0 && (module.exports = {
25146
25536
  AGENT_TASK_EVENT,
@@ -25173,7 +25563,9 @@ init_utils();
25173
25563
  InMemoryChunkBuffer,
25174
25564
  InMemoryDatabaseConfigStore,
25175
25565
  InMemoryMailboxStore,
25566
+ InMemoryMenuStore,
25176
25567
  InMemoryTaskListStore,
25568
+ InMemoryTaskStore,
25177
25569
  InMemoryTenantStore,
25178
25570
  InMemoryThreadMessageQueueStore,
25179
25571
  InMemoryThreadStore,
@@ -25195,6 +25587,7 @@ init_utils();
25195
25587
  MicrosandboxServiceClient,
25196
25588
  ModelLatticeManager,
25197
25589
  MysqlDatabase,
25590
+ PersonalAssistantConfig,
25198
25591
  PinoLoggerClient,
25199
25592
  PostgresDatabase,
25200
25593
  PrometheusClient,
@@ -25231,14 +25624,15 @@ init_utils();
25231
25624
  buildStateAnnotation,
25232
25625
  checkEmptyContent,
25233
25626
  clearEncryptionKeyCache,
25627
+ compileInternal,
25234
25628
  compileWorkflow,
25235
25629
  computeSandboxName,
25236
25630
  configureStores,
25631
+ connectAllChannels,
25237
25632
  createAgentNode,
25238
25633
  createAgentTeam,
25239
25634
  createExecuteSqlQueryTool,
25240
25635
  createFileData,
25241
- createHumanFeedbackNode,
25242
25636
  createInfoSqlTool,
25243
25637
  createListMetricsDataSourcesTool,
25244
25638
  createListMetricsServersTool,
@@ -25256,9 +25650,9 @@ init_utils();
25256
25650
  createQueryTablesListTool,
25257
25651
  createSandboxProvider,
25258
25652
  createSchedulerMiddleware,
25653
+ createTaskMiddleware,
25259
25654
  createTeamMiddleware,
25260
25655
  createTeammateTools,
25261
- createTerminalNode,
25262
25656
  createUnknownToolHandlerMiddleware,
25263
25657
  createWidgetMiddleware,
25264
25658
  decrypt,
@@ -25268,7 +25662,6 @@ init_utils();
25268
25662
  ensureBuiltinAgentsForTenant,
25269
25663
  eventBus,
25270
25664
  eventBusDefault,
25271
- expand,
25272
25665
  extractFetcherError,
25273
25666
  extractOutput,
25274
25667
  fileDataToString,
@@ -25291,6 +25684,7 @@ init_utils();
25291
25684
  getEmbeddingsLattice,
25292
25685
  getEncryptionKey,
25293
25686
  getLoggerLattice,
25687
+ getMenuRegistry,
25294
25688
  getModelLattice,
25295
25689
  getNextCronTime,
25296
25690
  getQueueLattice,
@@ -25320,6 +25714,7 @@ init_utils();
25320
25714
  parallelLimit,
25321
25715
  parseCronExpression,
25322
25716
  parseSkillFrontmatter,
25717
+ parseYaml,
25323
25718
  performStringReplacement,
25324
25719
  queueLatticeManager,
25325
25720
  registerAgentLattice,
@@ -25343,9 +25738,12 @@ init_utils();
25343
25738
  sanitizeToolCallId,
25344
25739
  scheduleLatticeManager,
25345
25740
  setBindingRegistry,
25741
+ setMenuRegistry,
25346
25742
  skillLatticeManager,
25347
25743
  sqlDatabaseManager,
25348
25744
  storeLatticeManager,
25745
+ toJsonSchema,
25746
+ toSafeStateExpr,
25349
25747
  toolLatticeManager,
25350
25748
  truncateIfTooLong,
25351
25749
  unregisterTeammateAgent,