@axiom-lattice/core 2.1.80 → 2.1.82

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
- });
943
- }
944
- throw err;
945
- }
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
- });
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 };
956
1192
  }
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
- });
1193
+ } catch (condErr) {
1194
+ console.error(`[WF][${node.id}] condition eval error: ${condErr.message}`);
1195
+ throw condErr;
964
1196
  }
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) {
@@ -1167,357 +1392,66 @@ function createTerminalNode(node, trackingStore) {
1167
1392
  tenantId: state._tenantId ?? "default",
1168
1393
  stepType: "terminal",
1169
1394
  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);
1395
+ input: { status: node.status }
1396
+ });
1397
+ } catch (e) {
1398
+ console.warn(`[WF][terminal] Failed to create terminal RunStep:`, e.message);
1447
1399
  }
1448
1400
  }
1449
- if (s.type === "parallel") s.steps.forEach(walk);
1450
- }
1451
- steps.forEach(walk);
1452
- return [...new Set(ids)];
1401
+ return {
1402
+ status: node.status,
1403
+ phase: node.id
1404
+ };
1405
+ };
1453
1406
  }
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);
1467
- }
1468
- }
1469
- if (s.type === "parallel") s.steps.forEach(walk);
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,
@@ -5595,7 +5630,8 @@ function getTenantIdFromConfig2(exeConfig, getTenantId2) {
5595
5630
  const runConfig = exeConfig?.configurable?.runConfig || {};
5596
5631
  return runConfig.tenantId || (getTenantId2 ? getTenantId2() : "default");
5597
5632
  }
5598
- function filterServerKeysByTenant(serverKeys, tenantId, manager = metricsServerManager) {
5633
+ async function filterServerKeysByTenant(serverKeys, tenantId, manager = metricsServerManager) {
5634
+ await manager.ensureLoaded();
5599
5635
  return serverKeys.filter((key) => {
5600
5636
  return manager.hasServer(tenantId, key);
5601
5637
  });
@@ -6373,6 +6409,14 @@ var MetricsServerManager = class _MetricsServerManager {
6373
6409
  }
6374
6410
  return config;
6375
6411
  }
6412
+ /**
6413
+ * Ensure server configs are loaded from the store.
6414
+ * Public wrapper around the internal lazy-loading mechanism.
6415
+ * Safe to call multiple times — loading happens at most once.
6416
+ */
6417
+ async ensureLoaded() {
6418
+ await this._ensureLoaded();
6419
+ }
6376
6420
  /**
6377
6421
  * Check if a metrics server is registered for a tenant
6378
6422
  * @param tenantId - Tenant identifier
@@ -6513,7 +6557,7 @@ ${serverKeys.map(
6513
6557
  if (connectAll) {
6514
6558
  effectiveServerKeys = (await metricsServerManager.getServerKeys(tenantId)).map((s) => s.key);
6515
6559
  }
6516
- const filteredServerKeys = filterServerKeysByTenant(effectiveServerKeys, tenantId);
6560
+ const filteredServerKeys = await filterServerKeysByTenant(effectiveServerKeys, tenantId);
6517
6561
  const runConfig = _exeConfig?.configurable?.runConfig || {};
6518
6562
  const metricsDataSource = runConfig.metricsDataSource;
6519
6563
  if (metricsDataSource) {
@@ -6632,7 +6676,7 @@ ${serverKeys.map(
6632
6676
  if (connectAll) {
6633
6677
  effectiveServerKeys = (await metricsServerManager.getServerKeys(tenantId)).map((s) => s.key);
6634
6678
  }
6635
- const filteredServerKeys = filterServerKeysByTenant(effectiveServerKeys, tenantId);
6679
+ const filteredServerKeys = await filterServerKeysByTenant(effectiveServerKeys, tenantId);
6636
6680
  const runConfig = _exeConfig?.configurable?.runConfig || {};
6637
6681
  const metricsDataSource = runConfig.metricsDataSource;
6638
6682
  const serverKey = metricsDataSource?.serverKey || inputServerKey;
@@ -6790,7 +6834,7 @@ ${serverKeys.map(
6790
6834
  if (connectAll) {
6791
6835
  effectiveServerKeys = (await metricsServerManager.getServerKeys(tenantId)).map((s) => s.key);
6792
6836
  }
6793
- const filteredServerKeys = filterServerKeysByTenant(effectiveServerKeys, tenantId);
6837
+ const filteredServerKeys = await filterServerKeysByTenant(effectiveServerKeys, tenantId);
6794
6838
  const runConfig = _exeConfig?.configurable?.runConfig || {};
6795
6839
  const metricsDataSource = runConfig.metricsDataSource;
6796
6840
  const serverKey = metricsDataSource?.serverKey || inputServerKey;
@@ -7026,7 +7070,7 @@ ${serverKeys.map(
7026
7070
  if (connectAll) {
7027
7071
  effectiveServerKeys = (await metricsServerManager.getServerKeys(tenantId)).map((s) => s.key);
7028
7072
  }
7029
- const filteredServerKeys = filterServerKeysByTenant(effectiveServerKeys, tenantId);
7073
+ const filteredServerKeys = await filterServerKeysByTenant(effectiveServerKeys, tenantId);
7030
7074
  const runConfig = _exeConfig?.configurable?.runConfig || {};
7031
7075
  const metricsDataSource = runConfig.metricsDataSource;
7032
7076
  const serverKey = metricsDataSource?.serverKey || inputServerKey;
@@ -7107,7 +7151,7 @@ ${serverKeys.map(
7107
7151
  if (connectAll) {
7108
7152
  effectiveServerKeys = (await metricsServerManager.getServerKeys(tenantId)).map((s) => s.key);
7109
7153
  }
7110
- const filteredServerKeys = filterServerKeysByTenant(effectiveServerKeys, tenantId);
7154
+ const filteredServerKeys = await filterServerKeysByTenant(effectiveServerKeys, tenantId);
7111
7155
  const runConfig = _exeConfig?.configurable?.runConfig || {};
7112
7156
  const metricsDataSource = runConfig.metricsDataSource;
7113
7157
  const serverKey = metricsDataSource?.serverKey || inputServerKey;
@@ -7212,7 +7256,7 @@ ${serverKeys.map(
7212
7256
  if (connectAll) {
7213
7257
  effectiveServerKeys = (await metricsServerManager.getServerKeys(tenantId)).map((s) => s.key);
7214
7258
  }
7215
- const filteredServerKeys = filterServerKeysByTenant(effectiveServerKeys, tenantId);
7259
+ const filteredServerKeys = await filterServerKeysByTenant(effectiveServerKeys, tenantId);
7216
7260
  const runConfig = _exeConfig?.configurable?.runConfig || {};
7217
7261
  const metricsDataSource = runConfig.metricsDataSource;
7218
7262
  const serverKey = metricsDataSource?.serverKey || inputServerKey;
@@ -7352,7 +7396,7 @@ ${serverKeys.map(
7352
7396
  if (connectAll) {
7353
7397
  effectiveServerKeys = (await metricsServerManager.getServerKeys(tenantId)).map((s) => s.key);
7354
7398
  }
7355
- const filteredServerKeys = filterServerKeysByTenant(effectiveServerKeys, tenantId);
7399
+ const filteredServerKeys = await filterServerKeysByTenant(effectiveServerKeys, tenantId);
7356
7400
  const runConfig = _exeConfig?.configurable?.runConfig || {};
7357
7401
  const metricsDataSource = runConfig.metricsDataSource;
7358
7402
  const serverKey = metricsDataSource?.serverKey || inputServerKey;
@@ -7413,7 +7457,9 @@ var VolumeFilesystem = class {
7413
7457
  this.mountPrefix = mountPrefix;
7414
7458
  }
7415
7459
  async lsInfo(path3) {
7460
+ console.log(`[VolumeFilesystem.lsInfo] path=${path3} mountPrefix=${this.mountPrefix}`);
7416
7461
  const entries = await this.client.list(path3);
7462
+ console.log(`[VolumeFilesystem.lsInfo] got ${entries.length} entries`);
7417
7463
  const prefix = this.mountPrefix.endsWith("/") ? this.mountPrefix : this.mountPrefix + "/";
7418
7464
  return entries.map((entry) => ({
7419
7465
  path: entry.path.startsWith("/") ? entry.path : prefix + entry.path,
@@ -7605,30 +7651,45 @@ var SandboxLatticeManager = class _SandboxLatticeManager extends BaseLatticeMana
7605
7651
  async getVolumeBackendForPath(config, filePath) {
7606
7652
  const provider = this._requireProvider();
7607
7653
  if (!provider.createVolumeFsClient) {
7654
+ console.log(`[getVolumeBackendForPath] provider has no createVolumeFsClient, returning null`);
7608
7655
  return null;
7609
7656
  }
7610
7657
  const tenantId = config.tenantId ?? "default";
7611
7658
  const mapping = this._resolveVolumeForPath(config, tenantId, filePath);
7612
- if (!mapping) return null;
7659
+ if (!mapping) {
7660
+ console.log(`[getVolumeBackendForPath] no volume mapping for path=${filePath}`);
7661
+ return null;
7662
+ }
7663
+ console.log(`[getVolumeBackendForPath] path=${filePath} volume=${mapping.volumeName} prefix=${mapping.pathPrefix}`);
7613
7664
  const client = provider.createVolumeFsClient(mapping.volumeName, mapping.pathPrefix);
7614
7665
  return new VolumeFilesystem(stripPrefixClient(client, mapping.pathPrefix), mapping.pathPrefix);
7615
7666
  }
7616
7667
  _resolveVolumeForPath(config, tenantId, filePath) {
7617
7668
  const normalized = normalizeExternalSandboxPath(filePath);
7669
+ console.log(`[_resolveVolumeForPath] filePath=${filePath} normalized=${normalized} assistant_id=${config.assistant_id} projectId=${config.projectId}`);
7618
7670
  if (normalized === "/root/.agents" || normalized.startsWith("/root/.agents/")) {
7671
+ console.log(`[_resolveVolumeForPath] \u2192 skills volume`);
7619
7672
  return {
7620
7673
  volumeName: buildNamedVolumeName("s", "skills", tenantId),
7621
7674
  pathPrefix: "/root/.agents"
7622
7675
  };
7623
7676
  }
7624
7677
  if (normalized === "/agent" || normalized.startsWith("/agent/")) {
7625
- if (!config.assistant_id) return null;
7678
+ if (!config.assistant_id) {
7679
+ console.log(`[_resolveVolumeForPath] agent volume but no assistant_id, returning null`);
7680
+ return null;
7681
+ }
7682
+ console.log(`[_resolveVolumeForPath] \u2192 agent volume`);
7626
7683
  return {
7627
7684
  volumeName: buildNamedVolumeName("a", "agent", tenantId, config.assistant_id),
7628
7685
  pathPrefix: "/agent"
7629
7686
  };
7630
7687
  }
7631
- if (!config.projectId) return null;
7688
+ if (!config.projectId) {
7689
+ console.log(`[_resolveVolumeForPath] project volume but no projectId, returning null`);
7690
+ return null;
7691
+ }
7692
+ console.log(`[_resolveVolumeForPath] \u2192 project volume`);
7632
7693
  return {
7633
7694
  volumeName: buildNamedVolumeName("p", "project", tenantId, config.workspaceId, config.projectId),
7634
7695
  pathPrefix: "/project"
@@ -8672,7 +8733,7 @@ var createBrowserGetInfoTool = ({ vmIsolation }) => {
8672
8733
  };
8673
8734
 
8674
8735
  // src/index.ts
8675
- var import_messages7 = require("@langchain/core/messages");
8736
+ var import_messages6 = require("@langchain/core/messages");
8676
8737
 
8677
8738
  // src/agent_lattice/types.ts
8678
8739
  var import_protocols = require("@axiom-lattice/protocols");
@@ -8691,7 +8752,7 @@ var createReactAgentSchema = (schema) => {
8691
8752
  };
8692
8753
 
8693
8754
  // src/agent_lattice/builders/ReActAgentGraphBuilder.ts
8694
- var import_langchain56 = require("langchain");
8755
+ var import_langchain57 = require("langchain");
8695
8756
 
8696
8757
  // src/middlewares/codeEvalMiddleware.ts
8697
8758
  var import_langchain37 = require("langchain");
@@ -9162,353 +9223,233 @@ metadata:
9162
9223
  Then iterate based on what the user says.
9163
9224
  `,
9164
9225
  "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
9226
+ name: create-workflow
9227
+ 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.
9228
+ license: MIT
9229
+ metadata:
9230
+ category: meta
9231
+ version: "5.0"
9232
+ ---
9180
9233
 
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
9234
+ # YAML Workflow Designer
9185
9235
 
9186
- If you omit \`id\`, a unique identifier is auto-generated (but you won't be able to reference the output).
9236
+ Use the linear YAML DSL \u2014 steps execute top-to-bottom. Use \`parallel:\` for concurrency. No dependency graph thinking required.
9187
9237
 
9188
- ## Step Types
9238
+ ## Core Model: Linear + Parallel
9189
9239
 
9190
- ### agent \u2014 a step for the workflow's built-in agent
9240
+ - **Linear** \u2014 steps execute in written order. No \`needs\`, no dependency declarations.
9241
+ - **parallel** \u2014 a block where all children run concurrently. Block completes when all children finish.
9242
+ - **if** \u2014 JS expression. Step runs only when truthy. Omit to always run.
9243
+ - **prompt** \u2014 agent instruction with **{{label}}** refs. **{{input}}** is the user message.
9244
+ - **output** \u2014 shorthand schema using **{ field: type }** notation.
9245
+ - **ask** \u2014 boolean. Injects user clarification middleware for human interaction.
9191
9246
 
9192
- \`\`\`json
9193
- { "id": "classify", "name": "Classify Intent", "prompt": "Classify the intent of: {{input}}", "schema": { "type": "object", "properties": { "intent": { "type": "string" } } } }
9194
- \`\`\`
9247
+ ## When to Use parallel vs map
9195
9248
 
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.
9249
+ This is the most important design decision. **They are fundamentally different:**
9202
9250
 
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)
9251
+ | | parallel | map |
9252
+ |---|---|---|
9253
+ | **Concern** | **Business parallelism** \u2014 reduce business processing time | **Data parallelism** \u2014 handle data volume |
9254
+ | **Tasks** | Each child does a **different** task | All items do the **same** task |
9255
+ | **Count** | Few (2-5), each hand-written | Dynamic, driven by source data |
9256
+ | **Input** | Independent prompts per child | Single \`each.prompt\` template, \`{{item}}\` for current element |
9257
+ | **if** | Per-child conditional | Whole block conditional |
9258
+ | **Example** | Legal review + Market analysis in parallel | Audit each line item in an invoice |
9209
9259
 
9210
- The agent's response is stored at \`state.<id>\` (or an auto-generated key if \`id\` is omitted).
9260
+ **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
9261
 
9212
- ### condition \u2014 branch on state
9262
+ ## Step Format
9213
9263
 
9214
- **Binary (then/else):**
9264
+ ### Agent Step
9215
9265
 
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
- }
9266
+ \`\`\`yaml
9267
+ - label:
9268
+ prompt: instruction with {{refs}}
9269
+ if: "expression"
9270
+ output: { field: type }
9271
+ ask: true
9221
9272
  \`\`\`
9222
9273
 
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):**
9232
-
9233
- When branching on a discrete set of known values, use \`branches\` for cleaner multi-way routing:
9274
+ ### Parallel Block
9234
9275
 
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
- }
9276
+ \`\`\`yaml
9277
+ - parallel:
9278
+ - child1:
9279
+ prompt: ...
9280
+ if: "expression"
9281
+ - child2:
9282
+ prompt: ...
9244
9283
  \`\`\`
9245
9284
 
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 |
9285
+ Parallel children are agent steps only. No nested parallel or map inside parallel.
9251
9286
 
9252
- Unlike \`then\`/\`else\` (truthy/falsy ternary), \`branches\` does exact string match against the state field value. Always include a \`"default"\` branch.
9287
+ ### Map Step
9253
9288
 
9254
- ### human \u2014 pause for human input
9255
-
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
- }
9289
+ \`\`\`yaml
9290
+ - label:
9291
+ map:
9292
+ source: "extract.items"
9293
+ if: "extract.items.length > 0"
9294
+ each:
9295
+ prompt: Process {{item}}
9296
+ output: { result: string }
9297
+ batch: 50
9298
+ concurrency: 5
9264
9299
  \`\`\`
9265
9300
 
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
9277
-
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) |
9301
+ ## Schema Shorthand
9294
9302
 
9295
- ### parallel \u2014 fixed fan-out
9303
+ Write **{ field: type }** instead of JSON Schema:
9296
9304
 
9297
- \`\`\`json
9298
- { "type": "parallel", "steps": [
9299
- { "id": "legal", "prompt": "Legal review: {{input}}" },
9300
- { "id": "finance", "prompt": "Finance: {{input}}" }
9301
- ]}
9302
- \`\`\`
9305
+ | Shorthand | Meaning |
9306
+ |-----------|---------|
9307
+ | **field: string** | string property |
9308
+ | **field: number** | number property |
9309
+ | **field: boolean** | boolean property |
9310
+ | **field: string[]** | array of strings |
9311
+ | **field: number[]** | array of numbers |
9312
+ | **field: [{ a: string, b: number }]** | array of objects |
9313
+ | **field: { sub: string }** | nested object |
9303
9314
 
9304
- All steps run simultaneously. After all complete, execution continues to the next step.
9315
+ Use **block style** (each field on its own line). Flow style \`{ field: "type" }\` with quoted values also works.
9305
9316
 
9306
- ### end \u2014 terminate the workflow
9317
+ ## Template Syntax
9307
9318
 
9308
- \`\`\`json
9309
- { "type": "end" }
9310
- \`\`\`
9319
+ | Syntax | Resolves to |
9320
+ |--------|------------|
9321
+ | \`{{input}}\` | Initial user message |
9322
+ | \`{{label}}\` | Full output of step |
9323
+ | \`{{label.field}}\` | Nested field access |
9324
+ | \`{{item}}\` | Current element in map iteration |
9311
9325
 
9312
- Always include at the end of the steps array. \`status\` defaults to "success".
9326
+ ## Design Patterns
9313
9327
 
9314
- **Number of terminal nodes:**
9328
+ ### Linear Pipeline
9315
9329
 
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\` |
9330
+ \`\`\`yaml
9331
+ steps:
9332
+ - extract:
9333
+ prompt: Extract data from {{input}}
9334
+ - transform:
9335
+ prompt: Transform {{extract}}
9336
+ - final:
9337
+ prompt: Combine raw {{extract}} with transformed {{transform}}
9338
+ \`\`\`
9336
9339
 
9337
- ## \u26A0\uFE0F CRITICAL: \`{{}}\` is ONLY for \`prompt\` fields
9340
+ ### Classify -> Route via Parallel + if
9338
9341
 
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.
9342
+ \`\`\`yaml
9343
+ steps:
9344
+ - classify:
9345
+ prompt: Classify intent from {{input}}
9346
+ output:
9347
+ intent: string
9348
+ urgency: number
9349
+ - parallel:
9350
+ - billing:
9351
+ if: "classify.intent == 'billing'"
9352
+ prompt: Handle billing: {{input}}
9353
+ ask: true
9354
+ - technical:
9355
+ if: "classify.intent == 'technical'"
9356
+ prompt: Handle technical: {{input}}
9357
+ - escalate:
9358
+ if: "classify.urgency >= 8"
9359
+ prompt: Urgent handling
9360
+ ask: true
9361
+ \`\`\`
9340
9362
 
9341
- **Common mistake the AI makes:**
9342
- \`\`\`json
9343
- // \u274C WRONG \u2014 {{}} does not belong in if:
9344
- { "type": "condition", "if": "{{intent}}", "then": {...}, "else": {...} }
9363
+ ### Parallel Processing
9345
9364
 
9346
- // \u2705 CORRECT \u2014 if is a plain expression:
9347
- { "type": "condition", "if": "intent", "then": {...}, "else": {...} }
9348
- \`\`\`
9365
+ \`\`\`yaml
9366
+ steps:
9367
+ - gather:
9368
+ prompt: Gather data from {{input}}
9369
+ - parallel:
9370
+ - legal:
9371
+ prompt: Legal analysis of {{gather}}
9372
+ output:
9373
+ risk: string
9374
+ compliant: boolean
9375
+ - market:
9376
+ prompt: Market analysis of {{gather}}
9377
+ output:
9378
+ opportunity: string
9379
+ score: number
9380
+ - report:
9381
+ prompt: |
9382
+ Synthesize findings:
9383
+ Legal: {{legal}}
9384
+ Market: {{market}}
9385
+ \`\`\`
9349
9386
 
9350
- ## What You NEVER Write
9387
+ ### Approval Flow with Human
9351
9388
 
9352
- The engine auto-generates these \u2014 do NOT include them in your DSL:
9389
+ \`\`\`yaml
9390
+ steps:
9391
+ - draft:
9392
+ prompt: Draft response to {{input}}
9393
+ - review:
9394
+ prompt: Present {{draft}} to user for approval
9395
+ output:
9396
+ approved: boolean
9397
+ comments: string
9398
+ ask: true
9399
+ - publish:
9400
+ if: "review.approved"
9401
+ prompt: Publish {{draft}}
9402
+ - revise:
9403
+ if: "!review.approved"
9404
+ prompt: Revise based on {{review.comments}}
9405
+ \`\`\`
9353
9406
 
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.
9407
+ ### Map (Iteration)
9360
9408
 
9361
- ## Design Patterns
9409
+ \`\`\`yaml
9410
+ steps:
9411
+ - extract:
9412
+ prompt: Extract items from {{input}}
9413
+ output:
9414
+ items:
9415
+ - name: string
9416
+ - map_items:
9417
+ map:
9418
+ source: "extract.items"
9419
+ each:
9420
+ prompt: Audit {{item.name}}
9421
+ output:
9422
+ result: string
9423
+ - summary:
9424
+ prompt: Summarize findings: {{map_items}}
9425
+ \`\`\`
9362
9426
 
9363
- ### Pattern 1: Linear Pipeline
9427
+ ## Keep Business Logic in Agents
9364
9428
 
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
- \`\`\`
9429
+ 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
9430
 
9376
- ### Pattern 2: Classify then Route
9431
+ **Rule:** if you have more if conditions than workflow phases, move logic into richer agent prompts.
9377
9432
 
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
- \`\`\`
9433
+ ## What You NEVER Write
9391
9434
 
9392
- ### Pattern 2b: Classify then Switch
9435
+ - **needs** \u2014 not supported. Steps execute linearly. Use parallel for concurrency.
9436
+ - **edges** \u2014 auto-generated from step order and parallel structure
9437
+ - **nested parallel** \u2014 parallel children are flat agent steps only
9438
+ - **map inside parallel** \u2014 map is a top-level step only
9439
+ - **json schema** \u2014 use **{ field: type }** block style
9440
+ - do not use {{}} markers in if expressions
9441
+ - **workflow-level business logic** \u2014 decisions belong inside agent prompts
9393
9442
 
9394
- For routing to 3+ categories, use \`branches\` instead of nested \`then\`/\`else\`:
9443
+ ## Checklist
9395
9444
 
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
- `
9445
+ - Every step has a unique label
9446
+ - Steps execute top-to-bottom \u2014 no dependency thinking needed
9447
+ - \`{{label}}\` can reference ANY upstream step output
9448
+ - if uses plain JS, no {{}}
9449
+ - Schema uses block style shorthand
9450
+ - parallel children are flat agent steps
9451
+ - Business logic stays inside agent prompts
9452
+ - ask: true for human interaction`
9512
9453
  };
9513
9454
  function getBuiltInSkillMeta(name) {
9514
9455
  const content = BUILTIN_SKILLS[name];
@@ -12419,7 +12360,7 @@ ${currentSystemPrompt}` : dateContext;
12419
12360
  // src/deep_agent_new/middleware/scheduler.ts
12420
12361
  var import_langchain55 = require("langchain");
12421
12362
  var import_zod50 = require("zod");
12422
- var import_uuid2 = require("uuid");
12363
+ var import_uuid3 = require("uuid");
12423
12364
  var import_protocols8 = require("@axiom-lattice/protocols");
12424
12365
 
12425
12366
  // src/schedule_lattice/ScheduleLatticeManager.ts
@@ -13974,7 +13915,7 @@ var buffer = new InMemoryChunkBuffer({
13974
13915
  registerChunkBuffer("default", buffer);
13975
13916
 
13976
13917
  // src/services/Agent.ts
13977
- var import_uuid = require("uuid");
13918
+ var import_uuid2 = require("uuid");
13978
13919
  var ThreadStatus2 = /* @__PURE__ */ ((ThreadStatus3) => {
13979
13920
  ThreadStatus3["IDLE"] = "idle";
13980
13921
  ThreadStatus3["BUSY"] = "busy";
@@ -14020,7 +13961,7 @@ var Agent = class {
14020
13961
  runConfig
14021
13962
  },
14022
13963
  configurable: {
14023
- run_id: (0, import_uuid.v4)(),
13964
+ run_id: (0, import_uuid2.v4)(),
14024
13965
  ...runConfig,
14025
13966
  runConfig
14026
13967
  },
@@ -14054,7 +13995,6 @@ var Agent = class {
14054
13995
  const runnable_agent = await getAgentClientAsync(this.tenant_id, this.assistant_id);
14055
13996
  const agentLattice = agentLatticeManager.getAgentLatticeWithTenant(this.tenant_id, this.assistant_id);
14056
13997
  const { messages, ...rest } = input;
14057
- const lifecycleManager = this;
14058
13998
  const runConfig = {
14059
13999
  thread_id: this.thread_id,
14060
14000
  "x-tenant-id": this.tenant_id,
@@ -14094,7 +14034,7 @@ var Agent = class {
14094
14034
  runConfig
14095
14035
  },
14096
14036
  configurable: {
14097
- run_id: (0, import_uuid.v4)(),
14037
+ run_id: (0, import_uuid2.v4)(),
14098
14038
  ...runConfig,
14099
14039
  runConfig
14100
14040
  // Inject runConfig for tools to access
@@ -14106,43 +14046,13 @@ var Agent = class {
14106
14046
  }
14107
14047
  );
14108
14048
  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
- }
14049
+ await this.consumeAgentStream(agentStream, signal);
14139
14050
  } catch (error) {
14140
14051
  console.error("Stream error:", error);
14141
- await lifecycleManager.chunkBuffer.abortThread(lifecycleManager.thread_id);
14142
14052
  throw error;
14143
14053
  }
14144
14054
  } catch (error) {
14145
- await this.chunkBuffer.abortThread(lifecycleManager.thread_id);
14055
+ await this.chunkBuffer.abortThread(this.thread_id);
14146
14056
  throw error;
14147
14057
  }
14148
14058
  };
@@ -14423,8 +14333,8 @@ var Agent = class {
14423
14333
  this.assistant_id = assistant_id;
14424
14334
  this.thread_id = thread_id;
14425
14335
  this.tenant_id = tenant_id;
14426
- this.workspace_id = workspace_id;
14427
- this.project_id = project_id;
14336
+ this.workspace_id = workspace_id || "default";
14337
+ this.project_id = project_id || "default";
14428
14338
  this.custom_run_config = custom_run_config;
14429
14339
  }
14430
14340
  getHumanPendingContent(message) {
@@ -14510,7 +14420,7 @@ var Agent = class {
14510
14420
  };
14511
14421
  }
14512
14422
  async invoke(queueMessage, signal) {
14513
- const messageId = (0, import_uuid.v4)();
14423
+ const messageId = (0, import_uuid2.v4)();
14514
14424
  const input = {
14515
14425
  ...queueMessage.input,
14516
14426
  messages: [new import_langchain54.HumanMessage({ id: messageId, content: queueMessage.input.message })]
@@ -14518,10 +14428,132 @@ var Agent = class {
14518
14428
  const inputMessage = { ...queueMessage, input };
14519
14429
  return this.agentExecutor(inputMessage, signal);
14520
14430
  }
14431
+ /**
14432
+ * Like {@link invoke} but returns the full LangGraph state (all annotations)
14433
+ * instead of only messages. Messages are serialized to dicts; other state
14434
+ * fields are returned as-is.
14435
+ *
14436
+ * @remarks
14437
+ * Only call this when you need the full state. Existing callers (gateway,
14438
+ * workflows) should keep using {@link invoke} which returns only messages
14439
+ * to avoid exposing internal annotation data.
14440
+ */
14441
+ async invokeWithState(queueMessage, signal) {
14442
+ const messageId = (0, import_uuid2.v4)();
14443
+ const input = {
14444
+ ...queueMessage.input,
14445
+ messages: [new import_langchain54.HumanMessage({ id: messageId, content: queueMessage.input.message })]
14446
+ };
14447
+ const inputMessage = { ...queueMessage, input };
14448
+ const { runnable_agent, runConfig } = await this.getLatticeClientAndRuntimeConfig(inputMessage.custom_run_config);
14449
+ const { messages, ...rest } = inputMessage.input;
14450
+ if (signal?.aborted) {
14451
+ throw new Error("Agent execution was aborted");
14452
+ }
14453
+ let result;
14454
+ result = await runnable_agent.invoke(
14455
+ inputMessage.command ? new import_langgraph6.Command(inputMessage.command) : { ...rest, messages, "x-tenant-id": this.tenant_id },
14456
+ {
14457
+ context: { runConfig },
14458
+ configurable: {
14459
+ run_id: (0, import_uuid2.v4)(),
14460
+ ...runConfig,
14461
+ runConfig
14462
+ },
14463
+ recursionLimit: 200,
14464
+ signal
14465
+ }
14466
+ );
14467
+ if (signal?.aborted) {
14468
+ throw new Error("Agent execution was aborted");
14469
+ }
14470
+ const { messages: _rawMessages, ...restState } = result;
14471
+ const serializedMessages = result.messages.map((message) => {
14472
+ const { type, data } = message.toDict();
14473
+ return { ...data, role: type };
14474
+ });
14475
+ return { messages: serializedMessages, ...restState };
14476
+ }
14521
14477
  async getPendingMessages() {
14522
14478
  const store = this.getQueueStore();
14523
14479
  return await store.getPendingMessages(this.thread_id);
14524
14480
  }
14481
+ async consumeAgentStream(agentStream, signal) {
14482
+ for await (const chunk2 of agentStream) {
14483
+ if (signal?.aborted) {
14484
+ await this.chunkBuffer.abortThread(this.thread_id);
14485
+ throw new Error("Agent execution was aborted");
14486
+ }
14487
+ let data;
14488
+ if (chunk2[0] === "updates") {
14489
+ const update = chunk2[1];
14490
+ const values = Object.values(update);
14491
+ const messages = values[0]?.messages;
14492
+ if (messages?.[0]?.tool_call_id) {
14493
+ data = messages[0].toDict();
14494
+ }
14495
+ } else if (chunk2[0] === "messages") {
14496
+ const messages = chunk2[1];
14497
+ data = messages?.[0]?.toDict();
14498
+ }
14499
+ if (chunk2?.[1]?.__interrupt__) {
14500
+ const interruptData = chunk2?.[1]?.__interrupt__[0];
14501
+ data = {
14502
+ type: "interrupt",
14503
+ id: interruptData.id,
14504
+ data: { content: interruptData.value }
14505
+ };
14506
+ }
14507
+ if (data) {
14508
+ this.addChunk(data);
14509
+ }
14510
+ }
14511
+ }
14512
+ /**
14513
+ * Resume LangGraph execution from the last checkpoint.
14514
+ *
14515
+ * Streams with `null` input — this tells LangGraph to continue from
14516
+ * wherever it left off using the checkpointed state for this thread.
14517
+ * All output chunks are buffered via {@link addChunk}.
14518
+ */
14519
+ async resumeGraphFromCheckpoint(signal) {
14520
+ const runnable_agent = await getAgentClientAsync(this.tenant_id, this.assistant_id);
14521
+ const agentLattice = agentLatticeManager.getAgentLatticeWithTenant(this.tenant_id, this.assistant_id);
14522
+ if (!runnable_agent) {
14523
+ throw new Error(`Agent ${this.assistant_id} not found`);
14524
+ }
14525
+ const runConfig = {
14526
+ thread_id: this.thread_id,
14527
+ "x-tenant-id": this.tenant_id,
14528
+ "x-workspace-id": this.workspace_id,
14529
+ "x-project-id": this.project_id,
14530
+ "x-thread-id": this.thread_id,
14531
+ "x-assistant-id": this.assistant_id,
14532
+ ...agentLattice?.config?.runConfig || {},
14533
+ tenantId: this.tenant_id,
14534
+ workspaceId: this.workspace_id,
14535
+ projectId: this.project_id,
14536
+ ...this.custom_run_config || {},
14537
+ assistant_id: this.assistant_id
14538
+ };
14539
+ const agentStream = await runnable_agent.stream(
14540
+ null,
14541
+ {
14542
+ context: {
14543
+ runConfig
14544
+ },
14545
+ configurable: {
14546
+ ...runConfig,
14547
+ runConfig
14548
+ },
14549
+ streamMode: ["updates", "messages"],
14550
+ subgraphs: false,
14551
+ recursionLimit: 200,
14552
+ signal
14553
+ }
14554
+ );
14555
+ await this.consumeAgentStream(agentStream, signal);
14556
+ }
14525
14557
  getQueueStore() {
14526
14558
  if (!this.queueStore) {
14527
14559
  try {
@@ -14600,7 +14632,7 @@ var Agent = class {
14600
14632
  */
14601
14633
  async addMessage(queueMessage, mode) {
14602
14634
  const useMode = mode ?? this.queueMode.mode;
14603
- const messageId = queueMessage.input.id || (0, import_uuid.v4)();
14635
+ const messageId = queueMessage.input.id || (0, import_uuid2.v4)();
14604
14636
  const messages = queueMessage.input.messages;
14605
14637
  const legacyMessage = queueMessage.input.message;
14606
14638
  if (!messages && !legacyMessage) {
@@ -14651,6 +14683,8 @@ var Agent = class {
14651
14683
  threadId: this.thread_id,
14652
14684
  tenantId: this.tenant_id,
14653
14685
  assistantId: this.assistant_id,
14686
+ workspaceId: this.workspace_id,
14687
+ projectId: this.project_id,
14654
14688
  content,
14655
14689
  type: pendingType,
14656
14690
  command: queueMessage.command,
@@ -14667,6 +14701,8 @@ var Agent = class {
14667
14701
  threadId: this.thread_id,
14668
14702
  tenantId: this.tenant_id,
14669
14703
  assistantId: this.assistant_id,
14704
+ workspaceId: this.workspace_id,
14705
+ projectId: this.project_id,
14670
14706
  content,
14671
14707
  type: pendingType,
14672
14708
  command: queueMessage.command,
@@ -14740,6 +14776,8 @@ var Agent = class {
14740
14776
  threadId: thread.threadId,
14741
14777
  tenantId: thread.tenantId,
14742
14778
  assistantId: thread.assistantId,
14779
+ workspaceId: this.workspace_id,
14780
+ projectId: this.project_id,
14743
14781
  content: reminderContent,
14744
14782
  type: "system"
14745
14783
  });
@@ -14811,9 +14849,14 @@ var Agent = class {
14811
14849
  /**
14812
14850
  * Resume processing after a server restart.
14813
14851
  *
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).
14852
+ * If the graph was mid-execution (BUSY) it resumes from the LangGraph
14853
+ * checkpoint without re-injecting the message the message has already
14854
+ * been consumed and is in the graph state. Processing messages are removed
14855
+ * rather than replayed.
14856
+ *
14857
+ * Skips threads that are in `INTERRUPTED` state (the interruption was
14858
+ * intentional). IDLE threads simply clean up and restart the queue
14859
+ * processor for any remaining pending messages.
14817
14860
  *
14818
14861
  * Called during gateway startup to recover threads that were mid-execution
14819
14862
  * when the server went down.
@@ -14831,9 +14874,32 @@ var Agent = class {
14831
14874
  return;
14832
14875
  }
14833
14876
  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}`);
14877
+ if (runStatus === "busy" /* BUSY */) {
14878
+ this.abortController = new AbortController();
14879
+ try {
14880
+ await this.resumeGraphFromCheckpoint(this.abortController.signal);
14881
+ const processingMessages = await store.getProcessingMessages(this.thread_id);
14882
+ for (const msg of processingMessages) {
14883
+ await store.removeMessage(msg.id);
14884
+ }
14885
+ if (processingMessages.length > 0) {
14886
+ console.log(`[Agent] Removed ${processingMessages.length} processing messages for thread ${this.thread_id}`);
14887
+ }
14888
+ } catch (error) {
14889
+ console.error(`[Agent] Failed to resume graph for thread ${this.thread_id}:`, error);
14890
+ await this.chunkBuffer.abortThread(this.thread_id);
14891
+ throw error;
14892
+ } finally {
14893
+ this.abortController = null;
14894
+ }
14895
+ } else {
14896
+ const processingMessages = await store.getProcessingMessages(this.thread_id);
14897
+ for (const msg of processingMessages) {
14898
+ await store.removeMessage(msg.id);
14899
+ }
14900
+ if (processingMessages.length > 0) {
14901
+ console.log(`[Agent] Removed ${processingMessages.length} processing messages for thread ${this.thread_id}`);
14902
+ }
14837
14903
  }
14838
14904
  await this.startQueueProcessorIfNeeded();
14839
14905
  }
@@ -15024,7 +15090,7 @@ var AgentInstanceManager = class _AgentInstanceManager {
15024
15090
  console.log(`[AgentInstanceManager] Found ${threadsWithPending.length} threads with pending messages, restoring...`);
15025
15091
  for (const threadInfo of threadsWithPending) {
15026
15092
  try {
15027
- await this.restoreThread(threadInfo, queueStore);
15093
+ await this.restoreThread(threadInfo);
15028
15094
  stats.restored++;
15029
15095
  } catch (error) {
15030
15096
  console.error(`[AgentInstanceManager] Failed to restore thread ${threadInfo.threadId}:`, error);
@@ -15042,16 +15108,14 @@ var AgentInstanceManager = class _AgentInstanceManager {
15042
15108
  * Restore a single thread
15043
15109
  * Delegates actual recovery logic to Agent.resumeTask()
15044
15110
  */
15045
- async restoreThread(threadInfo, queueStore) {
15046
- const { tenantId, assistantId, threadId } = threadInfo;
15111
+ async restoreThread(threadInfo) {
15112
+ const { tenantId, assistantId, threadId, workspaceId, projectId } = threadInfo;
15047
15113
  const threadParams = {
15048
15114
  tenant_id: tenantId,
15049
15115
  assistant_id: assistantId,
15050
15116
  thread_id: threadId,
15051
- workspace_id: "default",
15052
- // TODO: Get from thread store
15053
- project_id: "default"
15054
- // TODO: Get from thread store
15117
+ workspace_id: workspaceId,
15118
+ project_id: projectId
15055
15119
  };
15056
15120
  const agent = this.getAgent(threadParams);
15057
15121
  await agent.resumeTask();
@@ -15142,7 +15206,7 @@ function createSchedulerMiddleware(options = {}) {
15142
15206
  async (input, config) => {
15143
15207
  const runConfig = getRunConfig(config);
15144
15208
  const scheduleLattice = getScheduleLattice(SCHEDULE_LATTICE_KEY);
15145
- const taskId = (0, import_uuid2.v4)();
15209
+ const taskId = (0, import_uuid3.v4)();
15146
15210
  const executeAt = input.executeAt;
15147
15211
  const success = await scheduleLattice.client.scheduleOnce(
15148
15212
  taskId,
@@ -15177,7 +15241,7 @@ function createSchedulerMiddleware(options = {}) {
15177
15241
  async (input, config) => {
15178
15242
  const runConfig = getRunConfig(config);
15179
15243
  const scheduleLattice = getScheduleLattice(SCHEDULE_LATTICE_KEY);
15180
- const taskId = (0, import_uuid2.v4)();
15244
+ const taskId = (0, import_uuid3.v4)();
15181
15245
  const executeAt = Date.now() + input.delayMs;
15182
15246
  const success = await scheduleLattice.client.scheduleOnce(
15183
15247
  taskId,
@@ -15212,7 +15276,7 @@ function createSchedulerMiddleware(options = {}) {
15212
15276
  async (input, config) => {
15213
15277
  const runConfig = getRunConfig(config);
15214
15278
  const scheduleLattice = getScheduleLattice(SCHEDULE_LATTICE_KEY);
15215
- const taskId = (0, import_uuid2.v4)();
15279
+ const taskId = (0, import_uuid3.v4)();
15216
15280
  const success = await scheduleLattice.client.scheduleCron(
15217
15281
  taskId,
15218
15282
  AGENT_ADD_MESSAGE_TASK_TYPE,
@@ -15300,6 +15364,138 @@ function createSchedulerMiddleware(options = {}) {
15300
15364
  });
15301
15365
  }
15302
15366
 
15367
+ // src/middlewares/taskMiddleware.ts
15368
+ var import_langchain56 = require("langchain");
15369
+ var import_zod51 = require("zod");
15370
+ function getRunConfig2(config) {
15371
+ const c = config;
15372
+ return c?.configurable?.runConfig ?? {};
15373
+ }
15374
+ function getTaskStore() {
15375
+ return getStoreLattice("default", "task").store;
15376
+ }
15377
+ var manageTaskSchema = import_zod51.z.object({
15378
+ action: import_zod51.z.enum(["create", "list", "update", "delete", "complete"]).describe("\u64CD\u4F5C\u7C7B\u578B"),
15379
+ id: import_zod51.z.string().optional().describe("\u4EFB\u52A1 ID (update/delete/complete \u5FC5\u586B)"),
15380
+ title: import_zod51.z.string().optional().describe("\u4EFB\u52A1\u6807\u9898 (create \u5FC5\u586B)"),
15381
+ description: import_zod51.z.string().optional().describe("\u4EFB\u52A1\u63CF\u8FF0"),
15382
+ priority: import_zod51.z.enum(["low", "medium", "high"]).optional().describe("\u4F18\u5148\u7EA7"),
15383
+ status: import_zod51.z.enum(["pending", "in_progress", "completed", "cancelled"]).optional().describe("\u72B6\u6001"),
15384
+ dueDate: import_zod51.z.string().optional().describe("\u622A\u6B62\u65E5\u671F (ISO 8601)"),
15385
+ metadata: import_zod51.z.record(import_zod51.z.unknown()).optional().describe("\u7ED3\u6784\u5316\u5143\u6570\u636E (projectId, module \u7B49)"),
15386
+ parentId: import_zod51.z.string().optional().describe("\u7236\u4EFB\u52A1 ID (\u5B50\u4EFB\u52A1\u5173\u8054)"),
15387
+ sourceId: import_zod51.z.string().optional().describe("\u6765\u6E90\u4F1A\u8BDD/thread ID"),
15388
+ context: import_zod51.z.record(import_zod51.z.unknown()).optional().describe("\u9644\u52A0\u4E0A\u4E0B\u6587"),
15389
+ ownerType: import_zod51.z.enum(["user", "agent"]).optional().describe("\u6240\u6709\u8005\u7C7B\u578B\uFF0C\u4E0D\u4F20\u9ED8\u8BA4\u4E3A user"),
15390
+ ownerId: import_zod51.z.string().optional().describe("\u6240\u6709\u8005 ID\uFF0C\u4E0D\u4F20\u81EA\u52A8\u53D6\u5F53\u524D\u7528\u6237/Agent")
15391
+ });
15392
+ function createTaskMiddleware() {
15393
+ return (0, import_langchain56.createMiddleware)({
15394
+ name: "TaskMiddleware",
15395
+ contextSchema,
15396
+ wrapModelCall: async (request, handler) => {
15397
+ const taskPrompt = `## \u4EFB\u52A1\u7BA1\u7406\u80FD\u529B
15398
+ \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
15399
+ - \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)
15400
+ - ownerType="agent": \u4E3A\u81EA\u5DF1\u521B\u5EFA\u6267\u884C\u5B50\u4EFB\u52A1 (ownerId \u81EA\u52A8\u53D6\u5F53\u524D Agent)
15401
+ - \u663E\u5F0F\u4F20 ownerId: \u4E3A\u6307\u5B9A agent/user \u521B\u5EFA\u4EFB\u52A1\uFF08\u62D3\u6251\u573A\u666F\uFF09`;
15402
+ return handler({
15403
+ ...request,
15404
+ systemPrompt: taskPrompt + "\n\n" + (request.systemPrompt ?? "")
15405
+ });
15406
+ },
15407
+ tools: [
15408
+ (0, import_langchain56.tool)(
15409
+ async (input, config) => {
15410
+ const rc = getRunConfig2(config);
15411
+ const tenantId = rc.tenantId || "default";
15412
+ const ownerId = input.ownerId || (input.ownerType === "agent" ? rc.assistant_id : null) || rc.user_id;
15413
+ const store = getTaskStore();
15414
+ switch (input.action) {
15415
+ case "create": {
15416
+ if (!input.title) {
15417
+ return JSON.stringify({ success: false, error: "create requires title" });
15418
+ }
15419
+ const task = await store.create({
15420
+ tenantId,
15421
+ ownerType: input.ownerType || "user",
15422
+ ownerId,
15423
+ title: input.title,
15424
+ description: input.description,
15425
+ priority: input.priority || "medium",
15426
+ status: input.status || "pending",
15427
+ dueDate: input.dueDate,
15428
+ metadata: input.metadata,
15429
+ parentId: input.parentId,
15430
+ sourceId: input.sourceId,
15431
+ context: input.context
15432
+ });
15433
+ return JSON.stringify({ success: true, data: task });
15434
+ }
15435
+ case "list": {
15436
+ const tasks = await store.list({
15437
+ tenantId,
15438
+ ownerType: input.ownerType,
15439
+ ownerId: input.ownerId,
15440
+ status: input.status,
15441
+ priority: input.priority
15442
+ });
15443
+ return JSON.stringify({ success: true, data: tasks, count: tasks.length });
15444
+ }
15445
+ case "update": {
15446
+ if (!input.id) {
15447
+ return JSON.stringify({ success: false, error: "update requires id" });
15448
+ }
15449
+ const { action, ...updates } = input;
15450
+ const updated = await store.update(tenantId, input.id, updates);
15451
+ if (!updated) {
15452
+ return JSON.stringify({ success: false, error: "Task not found" });
15453
+ }
15454
+ return JSON.stringify({ success: true, data: updated });
15455
+ }
15456
+ case "delete": {
15457
+ if (!input.id) {
15458
+ return JSON.stringify({ success: false, error: "delete requires id" });
15459
+ }
15460
+ const deleted = await store.delete(tenantId, input.id);
15461
+ return JSON.stringify({ success: deleted, message: deleted ? "Task deleted" : "Task not found" });
15462
+ }
15463
+ case "complete": {
15464
+ if (!input.id) {
15465
+ return JSON.stringify({ success: false, error: "complete requires id" });
15466
+ }
15467
+ const updated = await store.update(tenantId, input.id, { status: "completed" });
15468
+ if (!updated) {
15469
+ return JSON.stringify({ success: false, error: "Task not found" });
15470
+ }
15471
+ return JSON.stringify({ success: true, data: updated });
15472
+ }
15473
+ default:
15474
+ return JSON.stringify({ success: false, error: `Unknown action: ${input.action}` });
15475
+ }
15476
+ },
15477
+ {
15478
+ name: "manage_task",
15479
+ description: `\u7BA1\u7406\u6301\u4E45\u5316\u4EFB\u52A1\u7CFB\u7EDF\u3002CRUD \u64CD\u4F5C\u7528\u6237\u548C Agent \u7684\u4EFB\u52A1\u3002
15480
+
15481
+ ## ownerType \u548C ownerId \u7684\u9ED8\u8BA4\u903B\u8F91
15482
+ - \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)
15483
+ - \u4F20 ownerType="agent" \u4E0D\u4F20 ownerId: \u7CFB\u7EDF\u81EA\u52A8\u4E3A\u5F53\u524D Agent \u521B\u5EFA\u5B50\u4EFB\u52A1
15484
+ - \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
15485
+
15486
+ ## Actions
15487
+ - create: \u521B\u5EFA\u4EFB\u52A1 (title \u5FC5\u586B, priority/description/dueDate/metadata/parentId/context \u53EF\u9009)
15488
+ - list: \u5217\u51FA\u4EFB\u52A1\uFF0C\u53EF\u6309 ownerType/status/priority \u8FC7\u6EE4
15489
+ - update: \u66F4\u65B0\u4EFB\u52A1 (id \u5FC5\u586B\uFF0C\u53EA\u4F20\u8981\u6539\u7684\u5B57\u6BB5)
15490
+ - delete: \u5220\u9664\u4EFB\u52A1 (id \u5FC5\u586B)
15491
+ - complete: \u5FEB\u901F\u6807\u8BB0\u5B8C\u6210 (id \u5FC5\u586B)`,
15492
+ schema: manageTaskSchema
15493
+ }
15494
+ )
15495
+ ]
15496
+ });
15497
+ }
15498
+
15303
15499
  // src/agent_lattice/builders/CustomMiddlewareRegistry.ts
15304
15500
  var CustomMiddlewareRegistry = class {
15305
15501
  /**
@@ -15435,6 +15631,9 @@ async function createCommonMiddlewares(middlewareConfigs, filesystemBackend, fsI
15435
15631
  case "scheduler":
15436
15632
  middlewares.push(createSchedulerMiddleware(config.config));
15437
15633
  break;
15634
+ case "task":
15635
+ middlewares.push(createTaskMiddleware());
15636
+ break;
15438
15637
  case "custom":
15439
15638
  {
15440
15639
  const customConfig = config.config;
@@ -15467,10 +15666,12 @@ var SandboxFilesystem = class {
15467
15666
  }
15468
15667
  async lsInfo(dirPath) {
15469
15668
  try {
15669
+ console.log(`[SandboxFilesystem.lsInfo] calling sandbox.file.listPath(${dirPath})`);
15470
15670
  const result = await this.sandbox.file.listPath(dirPath, { recursive: false });
15671
+ console.log(`[SandboxFilesystem.lsInfo] got ${result.files.length} entries`);
15471
15672
  return result.files;
15472
15673
  } catch (e) {
15473
- console.error(`Error listing files in ${dirPath}:`, e);
15674
+ console.error(`[SandboxFilesystem.lsInfo] error listing ${dirPath}:`, e);
15474
15675
  return [];
15475
15676
  }
15476
15677
  }
@@ -15642,14 +15843,14 @@ var ReActAgentGraphBuilder = class {
15642
15843
  */
15643
15844
  async build(agentLattice, params) {
15644
15845
  const tools = params.tools.map((t) => {
15645
- const tool51 = getToolClient(t.key);
15646
- return tool51;
15647
- }).filter((tool51) => tool51 !== void 0);
15846
+ const tool52 = getToolClient(t.key);
15847
+ return tool52;
15848
+ }).filter((tool52) => tool52 !== void 0);
15648
15849
  const stateSchema2 = createReactAgentSchema(params.stateSchema);
15649
15850
  const middlewareConfigs = params.middleware || [];
15650
15851
  const filesystemBackend = createFilesystemBackendFactory(middlewareConfigs);
15651
15852
  const middlewares = await createCommonMiddlewares(middlewareConfigs, filesystemBackend);
15652
- return (0, import_langchain56.createAgent)({
15853
+ return (0, import_langchain57.createAgent)({
15653
15854
  model: params.model,
15654
15855
  tools,
15655
15856
  systemPrompt: params.prompt,
@@ -15663,11 +15864,11 @@ var ReActAgentGraphBuilder = class {
15663
15864
  };
15664
15865
 
15665
15866
  // src/deep_agent_new/agent.ts
15666
- var import_langchain60 = require("langchain");
15867
+ var import_langchain61 = require("langchain");
15667
15868
 
15668
15869
  // src/deep_agent_new/middleware/subagents.ts
15669
15870
  var import_v32 = require("zod/v3");
15670
- var import_langchain57 = require("langchain");
15871
+ var import_langchain58 = require("langchain");
15671
15872
  var import_langgraph8 = require("@langchain/langgraph");
15672
15873
  var import_messages2 = require("@langchain/core/messages");
15673
15874
 
@@ -15991,7 +16192,7 @@ function returnCommandWithStateUpdate(result, toolCallId) {
15991
16192
  update: {
15992
16193
  ...stateUpdate,
15993
16194
  messages: [
15994
- new import_langchain57.ToolMessage({
16195
+ new import_langchain58.ToolMessage({
15995
16196
  content: lastMessage?.content || "Task Failed to complete",
15996
16197
  tool_call_id: toolCallId,
15997
16198
  name: "task"
@@ -16016,10 +16217,10 @@ function getSubagents(options) {
16016
16217
  const generalPurposeMiddleware = [...defaultSubagentMiddleware];
16017
16218
  if (defaultInterruptOn) {
16018
16219
  generalPurposeMiddleware.push(
16019
- (0, import_langchain57.humanInTheLoopMiddleware)({ interruptOn: defaultInterruptOn })
16220
+ (0, import_langchain58.humanInTheLoopMiddleware)({ interruptOn: defaultInterruptOn })
16020
16221
  );
16021
16222
  }
16022
- const generalPurposeSubagent = (0, import_langchain57.createAgent)({
16223
+ const generalPurposeSubagent = (0, import_langchain58.createAgent)({
16023
16224
  model: defaultModel,
16024
16225
  systemPrompt: DEFAULT_SUBAGENT_PROMPT,
16025
16226
  tools: defaultTools,
@@ -16042,8 +16243,8 @@ function getSubagents(options) {
16042
16243
  const middleware = agentParams.middleware ? [...defaultSubagentMiddleware, ...agentParams.middleware] : [...defaultSubagentMiddleware];
16043
16244
  const interruptOn = agentParams.interruptOn || defaultInterruptOn;
16044
16245
  if (interruptOn)
16045
- middleware.push((0, import_langchain57.humanInTheLoopMiddleware)({ interruptOn }));
16046
- agents[agentParams.key] = (0, import_langchain57.createAgent)({
16246
+ middleware.push((0, import_langchain58.humanInTheLoopMiddleware)({ interruptOn }));
16247
+ agents[agentParams.key] = (0, import_langchain58.createAgent)({
16047
16248
  model: agentParams.model ?? defaultModel,
16048
16249
  systemPrompt: agentParams.systemPrompt,
16049
16250
  tools: agentParams.tools ?? defaultTools,
@@ -16093,7 +16294,7 @@ function createTaskTool(options) {
16093
16294
  generalPurposeAgent
16094
16295
  });
16095
16296
  const finalTaskDescription = taskDescription ? taskDescription : getTaskToolDescription(subagentDescriptions);
16096
- return (0, import_langchain57.tool)(
16297
+ return (0, import_langchain58.tool)(
16097
16298
  async (input, config) => {
16098
16299
  const { description, subagent_type, async } = input;
16099
16300
  let assistant_id = subagent_type;
@@ -16127,12 +16328,16 @@ function createTaskTool(options) {
16127
16328
  const subagent_thread_id = config.configurable?.thread_id + "____" + assistant_id + "_" + config.toolCall.id;
16128
16329
  if (async) {
16129
16330
  const tenantId = config.configurable?.runConfig?.tenantId;
16331
+ const workspaceId = config.configurable?.runConfig?.workspaceId;
16332
+ const projectId = config.configurable?.runConfig?.projectId;
16130
16333
  const mainAssistantId = config.configurable?.runConfig?.assistant_id;
16131
16334
  const mainThreadId = config.configurable?.runConfig?.thread_id;
16132
16335
  const mainRuntimeAgent = agentInstanceManager.getAgent({
16133
16336
  assistant_id: mainAssistantId,
16134
16337
  thread_id: mainThreadId,
16135
- tenant_id: tenantId
16338
+ tenant_id: tenantId,
16339
+ workspace_id: workspaceId,
16340
+ project_id: projectId
16136
16341
  });
16137
16342
  if (mainRuntimeAgent) {
16138
16343
  mainRuntimeAgent.addAsyncTask({
@@ -16165,7 +16370,7 @@ function createTaskTool(options) {
16165
16370
  return new import_langgraph8.Command({
16166
16371
  update: {
16167
16372
  messages: [
16168
- new import_langchain57.ToolMessage({
16373
+ new import_langchain58.ToolMessage({
16169
16374
  content: `Async task started: ${subagent_thread_id}
16170
16375
  ${description}
16171
16376
  The result will be delivered as a notification when complete. Do not poll.`,
@@ -16198,7 +16403,7 @@ The result will be delivered as a notification when complete. Do not poll.`,
16198
16403
  return new import_langgraph8.Command({
16199
16404
  update: {
16200
16405
  messages: [
16201
- new import_langchain57.ToolMessage({
16406
+ new import_langchain58.ToolMessage({
16202
16407
  content: error instanceof Error ? error.message : "Task Failed to complete",
16203
16408
  tool_call_id: config.toolCall.id,
16204
16409
  name: "task"
@@ -16238,7 +16443,7 @@ function getMainAgentFromConfig(config) {
16238
16443
  });
16239
16444
  }
16240
16445
  function createCheckAsyncTaskTool() {
16241
- return (0, import_langchain57.tool)(
16446
+ return (0, import_langchain58.tool)(
16242
16447
  async (input, config) => {
16243
16448
  const { task_id } = input;
16244
16449
  const mainAgent = getMainAgentFromConfig(config);
@@ -16305,7 +16510,7 @@ Description: ${cached.description}`;
16305
16510
  );
16306
16511
  }
16307
16512
  function createListAsyncTasksTool() {
16308
- return (0, import_langchain57.tool)(
16513
+ return (0, import_langchain58.tool)(
16309
16514
  async (_input, config) => {
16310
16515
  const mainAgent = getMainAgentFromConfig(config);
16311
16516
  if (!mainAgent) {
@@ -16356,7 +16561,7 @@ function createListAsyncTasksTool() {
16356
16561
  );
16357
16562
  }
16358
16563
  function createCancelAsyncTaskTool() {
16359
- return (0, import_langchain57.tool)(
16564
+ return (0, import_langchain58.tool)(
16360
16565
  async (input, config) => {
16361
16566
  const { task_id } = input;
16362
16567
  const mainAgent = getMainAgentFromConfig(config);
@@ -16432,7 +16637,7 @@ function createSubAgentMiddleware(options) {
16432
16637
  );
16433
16638
  }
16434
16639
  const effectiveSystemPrompt = allowAsync ? systemPrompt + getAsyncPromptText() : systemPrompt;
16435
- return (0, import_langchain57.createMiddleware)({
16640
+ return (0, import_langchain58.createMiddleware)({
16436
16641
  name: "subAgentMiddleware",
16437
16642
  tools: allTools,
16438
16643
  wrapModelCall: async (request, handler) => {
@@ -16452,11 +16657,9 @@ ${effectiveSystemPrompt}` : effectiveSystemPrompt;
16452
16657
  }
16453
16658
 
16454
16659
  // 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");
16660
+ var import_langchain59 = require("langchain");
16458
16661
  function createPatchToolCallsMiddleware() {
16459
- return (0, import_langchain58.createMiddleware)({
16662
+ return (0, import_langchain59.createMiddleware)({
16460
16663
  name: "patchToolCallsMiddleware",
16461
16664
  beforeAgent: async (state) => {
16462
16665
  const messages = state.messages;
@@ -16467,15 +16670,15 @@ function createPatchToolCallsMiddleware() {
16467
16670
  for (let i = 0; i < messages.length; i++) {
16468
16671
  const msg = messages[i];
16469
16672
  patchedMessages.push(msg);
16470
- if (import_langchain58.AIMessage.isInstance(msg) && msg.tool_calls != null) {
16673
+ if (import_langchain59.AIMessage.isInstance(msg) && msg.tool_calls != null) {
16471
16674
  for (const toolCall of msg.tool_calls) {
16472
16675
  const correspondingToolMsg = messages.slice(i).find(
16473
- (m) => import_langchain58.ToolMessage.isInstance(m) && m.tool_call_id === toolCall.id
16676
+ (m) => import_langchain59.ToolMessage.isInstance(m) && m.tool_call_id === toolCall.id
16474
16677
  );
16475
16678
  if (!correspondingToolMsg) {
16476
16679
  const toolMsg = `Tool call ${toolCall.name} with id ${toolCall.id} was cancelled - another message came in before it could be completed.`;
16477
16680
  patchedMessages.push(
16478
- new import_langchain58.ToolMessage({
16681
+ new import_langchain59.ToolMessage({
16479
16682
  content: toolMsg,
16480
16683
  name: toolCall.name,
16481
16684
  tool_call_id: toolCall.id
@@ -16485,11 +16688,12 @@ function createPatchToolCallsMiddleware() {
16485
16688
  }
16486
16689
  }
16487
16690
  }
16691
+ if (patchedMessages.length === messages.length) {
16692
+ return;
16693
+ }
16488
16694
  return {
16489
- messages: [
16490
- new import_messages3.RemoveMessage({ id: import_langgraph9.REMOVE_ALL_MESSAGES }),
16491
- ...patchedMessages
16492
- ]
16695
+ messages: patchedMessages.slice(messages.length)
16696
+ // only the new ToolMessage patches
16493
16697
  };
16494
16698
  }
16495
16699
  });
@@ -17601,9 +17805,9 @@ var MemoryBackend = class {
17601
17805
  };
17602
17806
 
17603
17807
  // 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");
17808
+ var import_langgraph9 = require("@langchain/langgraph");
17809
+ var import_zod52 = require("zod");
17810
+ var import_langchain60 = require("langchain");
17607
17811
  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
17812
  It also helps the user understand the progress of the task and overall progress of their requests.
17609
17813
  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 +18034,20 @@ Writing todos takes time and tokens, use it when it is helpful for managing comp
17830
18034
  ## Important To-Do List Usage Notes to Remember
17831
18035
  - The \`write_todos\` tool should never be called multiple times in parallel.
17832
18036
  - 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"),
18037
+ var TodoStatus = import_zod52.z.enum(["pending", "in_progress", "completed"]).describe("Status of the todo");
18038
+ var TodoSchema = import_zod52.z.object({
18039
+ content: import_zod52.z.string().describe("Content of the todo item"),
17836
18040
  status: TodoStatus
17837
18041
  });
17838
- var stateSchema = import_zod51.z.object({ todos: import_zod51.z.array(TodoSchema).default([]) });
18042
+ var stateSchema = import_zod52.z.object({ todos: import_zod52.z.array(TodoSchema).default([]) });
17839
18043
  function todoListMiddleware(options) {
17840
- const writeTodos = (0, import_langchain59.tool)(
18044
+ const writeTodos = (0, import_langchain60.tool)(
17841
18045
  ({ todos }, config) => {
17842
- return new import_langgraph10.Command({
18046
+ return new import_langgraph9.Command({
17843
18047
  update: {
17844
18048
  todos,
17845
18049
  messages: [
17846
- new import_langchain59.ToolMessage({
18050
+ new import_langchain60.ToolMessage({
17847
18051
  content: genUIMarkdown("todo_list", todos),
17848
18052
  tool_call_id: config.toolCall?.id
17849
18053
  })
@@ -17854,12 +18058,12 @@ function todoListMiddleware(options) {
17854
18058
  {
17855
18059
  name: "write_todos",
17856
18060
  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")
18061
+ schema: import_zod52.z.object({
18062
+ todos: import_zod52.z.array(TodoSchema).describe("List of todo items to update")
17859
18063
  })
17860
18064
  }
17861
18065
  );
17862
- return (0, import_langchain59.createMiddleware)({
18066
+ return (0, import_langchain60.createMiddleware)({
17863
18067
  name: "todoListMiddleware",
17864
18068
  stateSchema,
17865
18069
  tools: [writeTodos],
@@ -17911,13 +18115,13 @@ ${BASE_PROMPT}` : BASE_PROMPT;
17911
18115
  backend: filesystemBackend
17912
18116
  }),
17913
18117
  // Subagent middleware: Automatic conversation summarization when token limits are approached
17914
- (0, import_langchain60.summarizationMiddleware)({
18118
+ (0, import_langchain61.summarizationMiddleware)({
17915
18119
  model,
17916
18120
  trigger: { tokens: 17e4 },
17917
18121
  keep: { messages: 6 }
17918
18122
  }),
17919
18123
  // Subagent middleware: Anthropic prompt caching for improved performance
17920
- (0, import_langchain60.anthropicPromptCachingMiddleware)({
18124
+ (0, import_langchain61.anthropicPromptCachingMiddleware)({
17921
18125
  unsupportedModelBehavior: "ignore"
17922
18126
  }),
17923
18127
  // Subagent middleware: Patches tool calls for compatibility
@@ -17929,23 +18133,23 @@ ${BASE_PROMPT}` : BASE_PROMPT;
17929
18133
  generalPurposeAgent: true
17930
18134
  }),
17931
18135
  // Automatically summarizes conversation history when token limits are approached
17932
- (0, import_langchain60.summarizationMiddleware)({
18136
+ (0, import_langchain61.summarizationMiddleware)({
17933
18137
  model,
17934
18138
  trigger: { tokens: 17e4 },
17935
18139
  keep: { messages: 6 }
17936
18140
  }),
17937
18141
  // Enables Anthropic prompt caching for improved performance and reduced costs
17938
- (0, import_langchain60.anthropicPromptCachingMiddleware)({
18142
+ (0, import_langchain61.anthropicPromptCachingMiddleware)({
17939
18143
  unsupportedModelBehavior: "ignore"
17940
18144
  }),
17941
18145
  // Patches tool calls to ensure compatibility across different model providers
17942
18146
  createPatchToolCallsMiddleware()
17943
18147
  ];
17944
18148
  if (interruptOn) {
17945
- middleware.push((0, import_langchain60.humanInTheLoopMiddleware)({ interruptOn }));
18149
+ middleware.push((0, import_langchain61.humanInTheLoopMiddleware)({ interruptOn }));
17946
18150
  }
17947
18151
  middleware.push(...customMiddleware);
17948
- return (0, import_langchain60.createAgent)({
18152
+ return (0, import_langchain61.createAgent)({
17949
18153
  model,
17950
18154
  systemPrompt: finalSystemPrompt,
17951
18155
  tools,
@@ -17972,7 +18176,7 @@ var DeepAgentGraphBuilder = class {
17972
18176
  const tools = params.tools.map((t) => {
17973
18177
  const toolClient = getToolClient(t.key);
17974
18178
  return toolClient;
17975
- }).filter((tool51) => tool51 !== void 0);
18179
+ }).filter((tool52) => tool52 !== void 0);
17976
18180
  const subagents = await Promise.all(params.subAgents.map(async (sa) => {
17977
18181
  if (sa.client) {
17978
18182
  return {
@@ -18017,7 +18221,7 @@ init_MemoryLatticeManager();
18017
18221
 
18018
18222
  // src/agent_team/agent_team.ts
18019
18223
  var import_v35 = require("zod/v3");
18020
- var import_langchain63 = require("langchain");
18224
+ var import_langchain64 = require("langchain");
18021
18225
 
18022
18226
  // src/agent_team/types.ts
18023
18227
  var TaskStatus = /* @__PURE__ */ ((TaskStatus3) => {
@@ -18453,14 +18657,14 @@ var InMemoryMailboxStore = class {
18453
18657
 
18454
18658
  // src/agent_team/middleware/team.ts
18455
18659
  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");
18660
+ var import_langchain63 = require("langchain");
18661
+ var import_langgraph11 = require("@langchain/langgraph");
18662
+ var import_uuid4 = require("uuid");
18459
18663
 
18460
18664
  // src/agent_team/middleware/teammate_tools.ts
18461
18665
  var import_v33 = require("zod/v3");
18462
- var import_langchain61 = require("langchain");
18463
- var import_langgraph11 = require("@langchain/langgraph");
18666
+ var import_langchain62 = require("langchain");
18667
+ var import_langgraph10 = require("@langchain/langgraph");
18464
18668
 
18465
18669
  // src/agent_team/middleware/formatMessages.ts
18466
18670
  function formatMessagesAsMarkdown(msgs) {
@@ -18484,7 +18688,7 @@ ${meta}${body}`;
18484
18688
  // src/agent_team/middleware/teammate_tools.ts
18485
18689
  function createTeammateTools(options) {
18486
18690
  const { teamId, agentId, taskListStore, mailboxStore } = options;
18487
- const claimTaskTool = (0, import_langchain61.tool)(
18691
+ const claimTaskTool = (0, import_langchain62.tool)(
18488
18692
  async (input) => {
18489
18693
  const task = await taskListStore.claimTaskById(
18490
18694
  teamId,
@@ -18514,7 +18718,7 @@ function createTeammateTools(options) {
18514
18718
  })
18515
18719
  }
18516
18720
  );
18517
- const completeTaskTool = (0, import_langchain61.tool)(
18721
+ const completeTaskTool = (0, import_langchain62.tool)(
18518
18722
  async (input) => {
18519
18723
  const task = await taskListStore.completeTask(
18520
18724
  teamId,
@@ -18541,7 +18745,7 @@ function createTeammateTools(options) {
18541
18745
  })
18542
18746
  }
18543
18747
  );
18544
- const failTaskTool = (0, import_langchain61.tool)(
18748
+ const failTaskTool = (0, import_langchain62.tool)(
18545
18749
  async (input) => {
18546
18750
  const task = await taskListStore.failTask(
18547
18751
  teamId,
@@ -18568,7 +18772,7 @@ function createTeammateTools(options) {
18568
18772
  })
18569
18773
  }
18570
18774
  );
18571
- const sendMessageTool = (0, import_langchain61.tool)(
18775
+ const sendMessageTool = (0, import_langchain62.tool)(
18572
18776
  async (input) => {
18573
18777
  await mailboxStore.sendMessage(
18574
18778
  teamId,
@@ -18606,7 +18810,7 @@ function createTeammateTools(options) {
18606
18810
  read: msg.read
18607
18811
  }));
18608
18812
  };
18609
- const readMessagesTool = (0, import_langchain61.tool)(
18813
+ const readMessagesTool = (0, import_langchain62.tool)(
18610
18814
  async (input, config) => {
18611
18815
  const formatAndMarkAsRead = async (msgs2) => {
18612
18816
  for (const msg of msgs2) {
@@ -18618,12 +18822,12 @@ function createTeammateTools(options) {
18618
18822
  if (msgs.length > 0) {
18619
18823
  const formatted2 = await formatAndMarkAsRead(msgs);
18620
18824
  const relevantMsgs2 = await getRelevantMessagesForState();
18621
- const toolMessage2 = new import_langchain61.ToolMessage({
18825
+ const toolMessage2 = new import_langchain62.ToolMessage({
18622
18826
  content: formatted2,
18623
18827
  tool_call_id: config.toolCall?.id,
18624
18828
  name: "read_messages"
18625
18829
  });
18626
- return new import_langgraph11.Command({
18830
+ return new import_langgraph10.Command({
18627
18831
  update: { team_mailbox: relevantMsgs2, messages: [toolMessage2] }
18628
18832
  });
18629
18833
  }
@@ -18643,22 +18847,22 @@ function createTeammateTools(options) {
18643
18847
  });
18644
18848
  const relevantMsgs = await getRelevantMessagesForState();
18645
18849
  if (msgs.length === 0) {
18646
- const toolMessage2 = new import_langchain61.ToolMessage({
18850
+ const toolMessage2 = new import_langchain62.ToolMessage({
18647
18851
  content: "No unread messages.",
18648
18852
  tool_call_id: config.toolCall?.id,
18649
18853
  name: "read_messages"
18650
18854
  });
18651
- return new import_langgraph11.Command({
18855
+ return new import_langgraph10.Command({
18652
18856
  update: { team_mailbox: relevantMsgs, messages: [toolMessage2] }
18653
18857
  });
18654
18858
  }
18655
18859
  const formatted = await formatAndMarkAsRead(msgs);
18656
- const toolMessage = new import_langchain61.ToolMessage({
18860
+ const toolMessage = new import_langchain62.ToolMessage({
18657
18861
  content: formatted,
18658
18862
  tool_call_id: config.toolCall?.id,
18659
18863
  name: "read_messages"
18660
18864
  });
18661
- return new import_langgraph11.Command({
18865
+ return new import_langgraph10.Command({
18662
18866
  update: { team_mailbox: relevantMsgs, messages: [toolMessage] }
18663
18867
  });
18664
18868
  },
@@ -18668,7 +18872,7 @@ function createTeammateTools(options) {
18668
18872
  schema: import_v33.z.object({})
18669
18873
  }
18670
18874
  );
18671
- const checkTasksTool = (0, import_langchain61.tool)(
18875
+ const checkTasksTool = (0, import_langchain62.tool)(
18672
18876
  async () => {
18673
18877
  const tasks = await taskListStore.getAllTasks(teamId);
18674
18878
  return formatTaskSummary(tasks);
@@ -18679,7 +18883,7 @@ function createTeammateTools(options) {
18679
18883
  schema: import_v33.z.object({})
18680
18884
  }
18681
18885
  );
18682
- const broadcastMessageTool = (0, import_langchain61.tool)(
18886
+ const broadcastMessageTool = (0, import_langchain62.tool)(
18683
18887
  async (input) => {
18684
18888
  const allAgents = await mailboxStore.getRegisteredAgents(teamId);
18685
18889
  const recipients = allAgents.filter((a) => a !== agentId);
@@ -18865,7 +19069,7 @@ You have access to these tools:
18865
19069
  - \`read_messages\`: Read messages from team_lead or teammates
18866
19070
  - \`check_tasks\`: Get current status of all tasks in the team`;
18867
19071
  const assistantId = getTeammateAssistantId(ctx.teamId, spec.name);
18868
- agent = (0, import_langchain62.createAgent)({
19072
+ agent = (0, import_langchain63.createAgent)({
18869
19073
  model: spec.model ?? ctx.defaultModel,
18870
19074
  systemPrompt: teammatePrompt,
18871
19075
  tools: allTools,
@@ -18934,19 +19138,19 @@ async function spawnTeammate(options) {
18934
19138
  function createTeamMiddleware(options) {
18935
19139
  const { teamConfig, taskListStore, mailboxStore, tenantId } = options;
18936
19140
  const defaultModel = teamConfig.model ?? "claude-sonnet-4-5-20250929";
18937
- const createTeamTool = (0, import_langchain62.tool)(
19141
+ const createTeamTool = (0, import_langchain63.tool)(
18938
19142
  async (input, config) => {
18939
- const state = (0, import_langgraph12.getCurrentTaskInput)();
19143
+ const state = (0, import_langgraph11.getCurrentTaskInput)();
18940
19144
  if (state?.team?.teamId) {
18941
19145
  const existingId = state.team.teamId;
18942
- const msg = new import_langchain62.ToolMessage({
19146
+ const msg = new import_langchain63.ToolMessage({
18943
19147
  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
19148
  tool_call_id: config.toolCall?.id,
18945
19149
  name: "create_team"
18946
19150
  });
18947
19151
  return msg;
18948
19152
  }
18949
- const teamId = (0, import_uuid3.v4)();
19153
+ const teamId = (0, import_uuid4.v4)();
18950
19154
  const createdTasks = await taskListStore.addTasks(
18951
19155
  teamId,
18952
19156
  input.tasks.map((t) => ({
@@ -19028,7 +19232,7 @@ Teammates are now working in the background. Keep calling \`check_tasks\` and \`
19028
19232
  \`\`\`json
19029
19233
  ${teamJson}
19030
19234
  \`\`\``;
19031
- const toolMessage = new import_langchain62.ToolMessage({
19235
+ const toolMessage = new import_langchain63.ToolMessage({
19032
19236
  content: summary,
19033
19237
  tool_call_id: config.toolCall?.id,
19034
19238
  name: "create_team"
@@ -19049,7 +19253,7 @@ ${teamJson}
19049
19253
  })),
19050
19254
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
19051
19255
  };
19052
- return new import_langgraph12.Command({
19256
+ return new import_langgraph11.Command({
19053
19257
  update: { team: teamState, messages: [toolMessage] }
19054
19258
  });
19055
19259
  },
@@ -19109,11 +19313,11 @@ After calling create_team, you MUST:
19109
19313
  }
19110
19314
  );
19111
19315
  const resolveTeamId = () => {
19112
- const state = (0, import_langgraph12.getCurrentTaskInput)();
19316
+ const state = (0, import_langgraph11.getCurrentTaskInput)();
19113
19317
  if (state?.team?.teamId) return state.team.teamId;
19114
19318
  throw new Error("No team_id provided and no team in state. Call create_team first.");
19115
19319
  };
19116
- const addTasksTool = (0, import_langchain62.tool)(
19320
+ const addTasksTool = (0, import_langchain63.tool)(
19117
19321
  async (input, config) => {
19118
19322
  const teamId = resolveTeamId();
19119
19323
  const created = await taskListStore.addTasks(
@@ -19127,7 +19331,7 @@ After calling create_team, you MUST:
19127
19331
  }))
19128
19332
  );
19129
19333
  const summary = created.map((t) => `- ${t.id}: "${t.title}"`).join("\n");
19130
- return new import_langchain62.ToolMessage({
19334
+ return new import_langchain63.ToolMessage({
19131
19335
  content: `Added ${created.length} task(s) to team ${teamId}:
19132
19336
  ${summary}
19133
19337
  Sleeping teammates will wake up and claim these.`,
@@ -19178,20 +19382,20 @@ IMPORTANT: Assigning to a specific teammate
19178
19382
  })
19179
19383
  }
19180
19384
  );
19181
- const assignTaskTool = (0, import_langchain62.tool)(
19385
+ const assignTaskTool = (0, import_langchain63.tool)(
19182
19386
  async (input, config) => {
19183
19387
  const teamId = resolveTeamId();
19184
19388
  const task = await taskListStore.updateTask(teamId, input.task_id, {
19185
19389
  assignee: input.assignee
19186
19390
  });
19187
19391
  if (!task) {
19188
- return new import_langchain62.ToolMessage({
19392
+ return new import_langchain63.ToolMessage({
19189
19393
  content: `Task ${input.task_id} not found in team ${teamId}.`,
19190
19394
  tool_call_id: config.toolCall?.id,
19191
19395
  name: "assign_task"
19192
19396
  });
19193
19397
  }
19194
- return new import_langchain62.ToolMessage({
19398
+ return new import_langchain63.ToolMessage({
19195
19399
  content: `Task "${task.title}" (${task.id}) assigned to ${input.assignee}.`,
19196
19400
  tool_call_id: config.toolCall?.id,
19197
19401
  name: "assign_task"
@@ -19206,20 +19410,20 @@ IMPORTANT: Assigning to a specific teammate
19206
19410
  })
19207
19411
  }
19208
19412
  );
19209
- const setTaskStatusTool = (0, import_langchain62.tool)(
19413
+ const setTaskStatusTool = (0, import_langchain63.tool)(
19210
19414
  async (input, config) => {
19211
19415
  const teamId = resolveTeamId();
19212
19416
  const task = await taskListStore.updateTask(teamId, input.task_id, {
19213
19417
  status: input.status
19214
19418
  });
19215
19419
  if (!task) {
19216
- return new import_langchain62.ToolMessage({
19420
+ return new import_langchain63.ToolMessage({
19217
19421
  content: `Task ${input.task_id} not found in team ${teamId}.`,
19218
19422
  tool_call_id: config.toolCall?.id,
19219
19423
  name: "set_task_status"
19220
19424
  });
19221
19425
  }
19222
- return new import_langchain62.ToolMessage({
19426
+ return new import_langchain63.ToolMessage({
19223
19427
  content: `Task "${task.title}" (${task.id}) status set to ${input.status}.`,
19224
19428
  tool_call_id: config.toolCall?.id,
19225
19429
  name: "set_task_status"
@@ -19234,20 +19438,20 @@ IMPORTANT: Assigning to a specific teammate
19234
19438
  })
19235
19439
  }
19236
19440
  );
19237
- const setTaskDependenciesTool = (0, import_langchain62.tool)(
19441
+ const setTaskDependenciesTool = (0, import_langchain63.tool)(
19238
19442
  async (input, config) => {
19239
19443
  const teamId = resolveTeamId();
19240
19444
  const task = await taskListStore.updateTask(teamId, input.task_id, {
19241
19445
  dependencies: input.dependencies
19242
19446
  });
19243
19447
  if (!task) {
19244
- return new import_langchain62.ToolMessage({
19448
+ return new import_langchain63.ToolMessage({
19245
19449
  content: `Task ${input.task_id} not found in team ${teamId}.`,
19246
19450
  tool_call_id: config.toolCall?.id,
19247
19451
  name: "set_task_dependencies"
19248
19452
  });
19249
19453
  }
19250
- return new import_langchain62.ToolMessage({
19454
+ return new import_langchain63.ToolMessage({
19251
19455
  content: `Task "${task.title}" (${task.id}) dependencies set to [${input.dependencies.join(", ")}].`,
19252
19456
  tool_call_id: config.toolCall?.id,
19253
19457
  name: "set_task_dependencies"
@@ -19262,16 +19466,16 @@ IMPORTANT: Assigning to a specific teammate
19262
19466
  })
19263
19467
  }
19264
19468
  );
19265
- const checkTasksTool = (0, import_langchain62.tool)(
19469
+ const checkTasksTool = (0, import_langchain63.tool)(
19266
19470
  async (input, config) => {
19267
19471
  const teamId = resolveTeamId();
19268
19472
  const tasks = await taskListStore.getAllTasks(teamId);
19269
19473
  const tasksSnapshot = tasks;
19270
- return new import_langgraph12.Command({
19474
+ return new import_langgraph11.Command({
19271
19475
  update: {
19272
19476
  tasks: tasksSnapshot,
19273
19477
  messages: [
19274
- new import_langchain62.ToolMessage({
19478
+ new import_langchain63.ToolMessage({
19275
19479
  content: formatTaskSummary(tasks),
19276
19480
  tool_call_id: config.toolCall?.id,
19277
19481
  name: "check_tasks"
@@ -19307,7 +19511,7 @@ Task Status Values:
19307
19511
  })
19308
19512
  }
19309
19513
  );
19310
- const sendMessageTool = (0, import_langchain62.tool)(
19514
+ const sendMessageTool = (0, import_langchain63.tool)(
19311
19515
  async (input, config) => {
19312
19516
  const teamId = resolveTeamId();
19313
19517
  await mailboxStore.sendMessage(
@@ -19317,7 +19521,7 @@ Task Status Values:
19317
19521
  input.content,
19318
19522
  "direct_message" /* DIRECT_MESSAGE */
19319
19523
  );
19320
- return new import_langchain62.ToolMessage({
19524
+ return new import_langchain63.ToolMessage({
19321
19525
  content: `Message sent to ${input.to}.`,
19322
19526
  tool_call_id: config.toolCall?.id,
19323
19527
  name: "send_message"
@@ -19332,7 +19536,7 @@ Task Status Values:
19332
19536
  })
19333
19537
  }
19334
19538
  );
19335
- const readMessagesTool = (0, import_langchain62.tool)(
19539
+ const readMessagesTool = (0, import_langchain63.tool)(
19336
19540
  async (input, config) => {
19337
19541
  const teamId = resolveTeamId();
19338
19542
  const formatAndMarkAsRead = async (msgs2) => {
@@ -19360,12 +19564,12 @@ Task Status Values:
19360
19564
  if (msgs.length > 0) {
19361
19565
  const formatted2 = await formatAndMarkAsRead(msgs);
19362
19566
  const allTeamMessages2 = await getAllTeamMessagesForState();
19363
- const toolMessage2 = new import_langchain62.ToolMessage({
19567
+ const toolMessage2 = new import_langchain63.ToolMessage({
19364
19568
  content: formatted2,
19365
19569
  tool_call_id: config.toolCall?.id,
19366
19570
  name: "read_messages"
19367
19571
  });
19368
- return new import_langgraph12.Command({
19572
+ return new import_langgraph11.Command({
19369
19573
  update: { team_mailbox: allTeamMessages2, messages: [toolMessage2] }
19370
19574
  });
19371
19575
  }
@@ -19392,22 +19596,22 @@ Task Status Values:
19392
19596
  );
19393
19597
  const allTeamMessages = await getAllTeamMessagesForState();
19394
19598
  if (msgs.length === 0) {
19395
- const toolMessage2 = new import_langchain62.ToolMessage({
19599
+ const toolMessage2 = new import_langchain63.ToolMessage({
19396
19600
  content: "No unread messages from teammates.",
19397
19601
  tool_call_id: config.toolCall?.id,
19398
19602
  name: "read_messages"
19399
19603
  });
19400
- return new import_langgraph12.Command({
19604
+ return new import_langgraph11.Command({
19401
19605
  update: { team_mailbox: allTeamMessages, messages: [toolMessage2] }
19402
19606
  });
19403
19607
  }
19404
19608
  const formatted = await formatAndMarkAsRead(msgs);
19405
- const toolMessage = new import_langchain62.ToolMessage({
19609
+ const toolMessage = new import_langchain63.ToolMessage({
19406
19610
  content: formatted,
19407
19611
  tool_call_id: config.toolCall?.id,
19408
19612
  name: "read_messages"
19409
19613
  });
19410
- return new import_langgraph12.Command({
19614
+ return new import_langgraph11.Command({
19411
19615
  update: { team_mailbox: allTeamMessages, messages: [toolMessage] }
19412
19616
  });
19413
19617
  },
@@ -19419,7 +19623,7 @@ Task Status Values:
19419
19623
  })
19420
19624
  }
19421
19625
  );
19422
- const disbandTeamTool = (0, import_langchain62.tool)(
19626
+ const disbandTeamTool = (0, import_langchain63.tool)(
19423
19627
  async (input, config) => {
19424
19628
  const teamId = resolveTeamId();
19425
19629
  await mailboxStore.broadcastMessage(
@@ -19429,7 +19633,7 @@ Task Status Values:
19429
19633
  "shutdown_request" /* SHUTDOWN_REQUEST */
19430
19634
  );
19431
19635
  await new Promise((r) => setTimeout(r, 2e3));
19432
- return new import_langchain62.ToolMessage({
19636
+ return new import_langchain63.ToolMessage({
19433
19637
  content: `Team ${teamId} has been disbanded. All teammates notified and resources cleaned up.`,
19434
19638
  tool_call_id: config.toolCall?.id,
19435
19639
  name: "disband_team"
@@ -19440,7 +19644,7 @@ Task Status Values:
19440
19644
  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
19645
  }
19442
19646
  );
19443
- const broadcastMessageTool = (0, import_langchain62.tool)(
19647
+ const broadcastMessageTool = (0, import_langchain63.tool)(
19444
19648
  async (input, config) => {
19445
19649
  const teamId = resolveTeamId();
19446
19650
  await mailboxStore.broadcastMessage(
@@ -19449,7 +19653,7 @@ Task Status Values:
19449
19653
  input.content,
19450
19654
  "broadcast" /* BROADCAST */
19451
19655
  );
19452
- return new import_langchain62.ToolMessage({
19656
+ return new import_langchain63.ToolMessage({
19453
19657
  content: `Broadcast message sent to all teammates.`,
19454
19658
  tool_call_id: config.toolCall?.id,
19455
19659
  name: "broadcast_message"
@@ -19463,7 +19667,7 @@ Task Status Values:
19463
19667
  })
19464
19668
  }
19465
19669
  );
19466
- return (0, import_langchain62.createMiddleware)({
19670
+ return (0, import_langchain63.createMiddleware)({
19467
19671
  name: "teamMiddleware",
19468
19672
  tools: [
19469
19673
  createTeamTool,
@@ -19572,7 +19776,7 @@ function createAgentTeam(config) {
19572
19776
  ];
19573
19777
  const systemPrompt = config.systemPrompt + "\n\n" + TEAM_LEAD_BASE_PROMPT;
19574
19778
  const stateSchema2 = createReactAgentSchema(TEAM_STATE_SCHEMA);
19575
- return (0, import_langchain63.createAgent)({
19779
+ return (0, import_langchain64.createAgent)({
19576
19780
  model: config.model ?? "claude-sonnet-4-5-20250929",
19577
19781
  systemPrompt,
19578
19782
  tools: [],
@@ -19602,7 +19806,7 @@ var TeamAgentGraphBuilder = class {
19602
19806
  const tools = params.tools.map((t) => {
19603
19807
  const toolClient = getToolClient(t.key);
19604
19808
  return toolClient;
19605
- }).filter((tool51) => tool51 !== void 0);
19809
+ }).filter((tool52) => tool52 !== void 0);
19606
19810
  const teammates = params.subAgents.map((sa) => {
19607
19811
  const baseConfig = sa.config;
19608
19812
  return {
@@ -19640,17 +19844,17 @@ var TeamAgentGraphBuilder = class {
19640
19844
  };
19641
19845
 
19642
19846
  // src/deep_agent_new/processing_agent.ts
19643
- var import_langchain66 = require("langchain");
19847
+ var import_langchain67 = require("langchain");
19644
19848
 
19645
19849
  // src/middlewares/topologyMiddleware.ts
19646
- var import_langchain64 = require("langchain");
19647
- var import_messages4 = require("@langchain/core/messages");
19648
19850
  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()
19851
+ var import_messages3 = require("@langchain/core/messages");
19852
+ var import_langchain66 = require("langchain");
19853
+ var import_zod53 = require("zod");
19854
+ var import_langgraph12 = require("@langchain/langgraph");
19855
+ var CompletedEdgeSchema = import_zod53.z.object({
19856
+ to: import_zod53.z.string(),
19857
+ purpose: import_zod53.z.string()
19654
19858
  });
19655
19859
  function deriveCompletedEdges(messages, edges) {
19656
19860
  const completedToolCallIds = /* @__PURE__ */ new Set();
@@ -19677,16 +19881,16 @@ function deriveCompletedEdges(messages, edges) {
19677
19881
  }
19678
19882
  function createTopologyMiddleware(options) {
19679
19883
  const { edges, trackingStore } = options;
19680
- return (0, import_langchain64.createMiddleware)({
19884
+ return (0, import_langchain65.createMiddleware)({
19681
19885
  name: "TopologyMiddleware",
19682
- contextSchema: import_zod52.z.object({
19683
- runConfig: import_zod52.z.any()
19886
+ contextSchema: import_zod53.z.object({
19887
+ runConfig: import_zod53.z.any()
19684
19888
  }),
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({})
19889
+ stateSchema: import_zod53.z.object({
19890
+ currentAgentId: import_zod53.z.string().default(""),
19891
+ completedEdges: import_zod53.z.array(CompletedEdgeSchema).default([]),
19892
+ runId: import_zod53.z.string().default(""),
19893
+ stepIdMap: import_zod53.z.record(import_zod53.z.string()).default({})
19690
19894
  }),
19691
19895
  beforeAgent: async (state, runtime) => {
19692
19896
  if (state.runId) {
@@ -19737,14 +19941,14 @@ ${request.systemPrompt}` : topologyPrompt;
19737
19941
  return handler({ ...request, systemPrompt: newSystemPrompt });
19738
19942
  },
19739
19943
  tools: [
19740
- (0, import_langchain65.tool)(
19944
+ (0, import_langchain66.tool)(
19741
19945
  async (_input) => {
19742
19946
  return "placeholder";
19743
19947
  },
19744
19948
  {
19745
19949
  name: "read_topo_progress",
19746
19950
  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({})
19951
+ schema: import_zod53.z.object({})
19748
19952
  }
19749
19953
  )
19750
19954
  ],
@@ -19759,7 +19963,7 @@ ${request.systemPrompt}` : topologyPrompt;
19759
19963
  status: doneSet.has(e.to) ? "done" : "pending"
19760
19964
  }));
19761
19965
  const doneCount = completedEdges.length;
19762
- return new import_messages4.ToolMessage({
19966
+ return new import_messages3.ToolMessage({
19763
19967
  content: JSON.stringify(
19764
19968
  {
19765
19969
  currentAgentId,
@@ -19777,7 +19981,7 @@ ${request.systemPrompt}` : topologyPrompt;
19777
19981
  try {
19778
19982
  return await handler(request);
19779
19983
  } catch (error) {
19780
- if (error instanceof import_langgraph13.GraphInterrupt) {
19984
+ if (error instanceof import_langgraph12.GraphInterrupt) {
19781
19985
  throw error;
19782
19986
  }
19783
19987
  throw error;
@@ -19824,7 +20028,7 @@ ${request.systemPrompt}` : topologyPrompt;
19824
20028
  ];
19825
20029
  return {
19826
20030
  messages: [
19827
- new import_messages4.AIMessage({
20031
+ new import_messages3.AIMessage({
19828
20032
  content: [
19829
20033
  `Task rejected: topology violation.`,
19830
20034
  `Agent "${currentAgentId}" is not allowed to delegate to "${targetAgent}".`,
@@ -19966,13 +20170,13 @@ ${BASE_PROMPT2}` : BASE_PROMPT2;
19966
20170
  backend: filesystemBackend
19967
20171
  }),
19968
20172
  // Subagent middleware: Automatic conversation summarization
19969
- (0, import_langchain66.summarizationMiddleware)({
20173
+ (0, import_langchain67.summarizationMiddleware)({
19970
20174
  model,
19971
20175
  trigger: { tokens: 17e4 },
19972
20176
  keep: { messages: 6 }
19973
20177
  }),
19974
20178
  // Subagent middleware: Anthropic prompt caching
19975
- (0, import_langchain66.anthropicPromptCachingMiddleware)({
20179
+ (0, import_langchain67.anthropicPromptCachingMiddleware)({
19976
20180
  unsupportedModelBehavior: "ignore"
19977
20181
  }),
19978
20182
  // Subagent middleware: Patches tool calls
@@ -19985,23 +20189,23 @@ ${BASE_PROMPT2}` : BASE_PROMPT2;
19985
20189
  allowAsync: false
19986
20190
  }),
19987
20191
  // Automatically summarizes conversation history
19988
- (0, import_langchain66.summarizationMiddleware)({
20192
+ (0, import_langchain67.summarizationMiddleware)({
19989
20193
  model,
19990
20194
  trigger: { tokens: 17e4 },
19991
20195
  keep: { messages: 6 }
19992
20196
  }),
19993
20197
  // Enables Anthropic prompt caching
19994
- (0, import_langchain66.anthropicPromptCachingMiddleware)({
20198
+ (0, import_langchain67.anthropicPromptCachingMiddleware)({
19995
20199
  unsupportedModelBehavior: "ignore"
19996
20200
  }),
19997
20201
  // Patches tool calls
19998
20202
  createPatchToolCallsMiddleware()
19999
20203
  ];
20000
20204
  if (interruptOn) {
20001
- middleware.push((0, import_langchain66.humanInTheLoopMiddleware)({ interruptOn }));
20205
+ middleware.push((0, import_langchain67.humanInTheLoopMiddleware)({ interruptOn }));
20002
20206
  }
20003
20207
  middleware.push(...customMiddleware);
20004
- return (0, import_langchain66.createAgent)({
20208
+ return (0, import_langchain67.createAgent)({
20005
20209
  model,
20006
20210
  systemPrompt: finalSystemPrompt,
20007
20211
  tools,
@@ -20021,7 +20225,7 @@ var ProcessingAgentGraphBuilder = class {
20021
20225
  const tools = params.tools.map((t) => {
20022
20226
  const toolClient = getToolClient(t.key);
20023
20227
  return toolClient;
20024
- }).filter((tool51) => tool51 !== void 0);
20228
+ }).filter((tool52) => tool52 !== void 0);
20025
20229
  const subagents = await Promise.all(params.subAgents.map(async (sa) => {
20026
20230
  if (sa.client) {
20027
20231
  return {
@@ -20067,11 +20271,11 @@ var ProcessingAgentGraphBuilder = class {
20067
20271
  };
20068
20272
 
20069
20273
  // src/agent_lattice/builders/RemoteAgentGraphBuilder.ts
20070
- var import_langgraph14 = require("@langchain/langgraph");
20071
- var import_messages5 = require("@langchain/core/messages");
20274
+ var import_langgraph13 = require("@langchain/langgraph");
20275
+ var import_messages4 = require("@langchain/core/messages");
20072
20276
 
20073
20277
  // src/services/a2a-client.ts
20074
- var import_uuid4 = require("uuid");
20278
+ var import_uuid5 = require("uuid");
20075
20279
  var A2ARemoteError = class extends Error {
20076
20280
  constructor(message, statusCode, body) {
20077
20281
  super(message);
@@ -20118,7 +20322,7 @@ var A2ARemoteClient = class {
20118
20322
  */
20119
20323
  async sendMessage(text) {
20120
20324
  await this.resolve();
20121
- const taskId = (0, import_uuid4.v4)();
20325
+ const taskId = (0, import_uuid5.v4)();
20122
20326
  const body = JSON.stringify({
20123
20327
  jsonrpc: "2.0",
20124
20328
  method: "tasks/send",
@@ -20244,7 +20448,7 @@ var RemoteAgentGraphBuilder = class {
20244
20448
  if (!text) {
20245
20449
  return {
20246
20450
  messages: [
20247
- new import_messages5.AIMessage("No text input provided to remote agent.")
20451
+ new import_messages4.AIMessage("No text input provided to remote agent.")
20248
20452
  ]
20249
20453
  };
20250
20454
  }
@@ -20255,18 +20459,18 @@ User request:
20255
20459
  ${text}` : text;
20256
20460
  const response = await client.sendMessage(fullPrompt);
20257
20461
  return {
20258
- messages: [new import_messages5.AIMessage(response)]
20462
+ messages: [new import_messages4.AIMessage(response)]
20259
20463
  };
20260
20464
  } catch (error) {
20261
20465
  const msg = error.message ?? String(error);
20262
20466
  return {
20263
20467
  messages: [
20264
- new import_messages5.AIMessage(`Remote A2A agent error: ${msg}`)
20468
+ new import_messages4.AIMessage(`Remote A2A agent error: ${msg}`)
20265
20469
  ]
20266
20470
  };
20267
20471
  }
20268
20472
  };
20269
- const workflow = new import_langgraph14.StateGraph(import_langgraph14.MessagesAnnotation).addNode("remote_call", remoteCallNode).addEdge("__start__", "remote_call").addEdge("remote_call", "__end__");
20473
+ const workflow = new import_langgraph13.StateGraph(import_langgraph13.MessagesAnnotation).addNode("remote_call", remoteCallNode).addEdge("__start__", "remote_call").addEdge("remote_call", "__end__");
20270
20474
  return workflow.compile();
20271
20475
  }
20272
20476
  };
@@ -20288,7 +20492,7 @@ function extractLastHumanMessage(messages) {
20288
20492
  }
20289
20493
 
20290
20494
  // src/agent_lattice/builders/WorkflowAgentGraphBuilder.ts
20291
- var import_langchain67 = require("langchain");
20495
+ var import_langchain68 = require("langchain");
20292
20496
  init_MemoryLatticeManager();
20293
20497
  var import_protocols10 = require("@axiom-lattice/protocols");
20294
20498
  init_compile();
@@ -20301,26 +20505,26 @@ var WorkflowAgentGraphBuilder = class {
20301
20505
  );
20302
20506
  }
20303
20507
  const config = agentLattice.config;
20304
- const dsl = config.workflow;
20508
+ const yaml2 = config.workflowYaml;
20305
20509
  const tenantId = agentLattice.config.tenantId ?? "default";
20306
20510
  const checkpointer = getCheckpointSaver("default");
20307
20511
  const tools = params.tools.map((t) => t.executor).filter(Boolean);
20308
20512
  const middlewareConfigs = params.middleware || [];
20309
20513
  const middlewares = await createCommonMiddlewares(middlewareConfigs, void 0, false);
20310
- const humanMiddlewares = await createCommonMiddlewares([
20514
+ const askMiddlewares = await createCommonMiddlewares([
20311
20515
  {
20312
20516
  id: "ask_user_to_clarify",
20313
20517
  type: "ask_user_to_clarify",
20314
20518
  name: "Ask User Clarify",
20315
- description: "For human_feedback workflow nodes",
20519
+ description: "For workflow steps requiring user interaction",
20316
20520
  enabled: true,
20317
20521
  config: {}
20318
20522
  }
20319
20523
  ], void 0, false);
20320
20524
  const noWrapMiddlewares = middlewares.filter((m) => !m.wrapModelCall);
20321
- const noWrapHumanMiddlewares = humanMiddlewares.filter((m) => !m.wrapModelCall);
20525
+ const noWrapAskMiddlewares = askMiddlewares.filter((m) => !m.wrapModelCall);
20322
20526
  console.log(`[WF BUILDER] building default agent | toolCount=${tools.length} | middlewareCount=${middlewares.length}`);
20323
- const defaultAgent = (0, import_langchain67.createAgent)({
20527
+ const defaultAgent = (0, import_langchain68.createAgent)({
20324
20528
  model: params.model,
20325
20529
  tools,
20326
20530
  systemPrompt: params.prompt || DEFAULT_AGENT_PROMPT,
@@ -20334,34 +20538,34 @@ var WorkflowAgentGraphBuilder = class {
20334
20538
  console.log(`[WF BUILDER] resolveAgent: looking up ref="${ref}"`);
20335
20539
  return await getAgentClientAsync(tenantId, ref);
20336
20540
  }
20337
- const isHuman = stepType === "human_feedback";
20541
+ const isAsk = stepType === "ask";
20338
20542
  if (responseFormat) {
20339
- const key = (isHuman ? "human:" : "agent:") + JSON.stringify(responseFormat);
20543
+ const key = (isAsk ? "ask:" : "agent:") + JSON.stringify(responseFormat);
20340
20544
  console.log(`[WF BUILDER] resolveAgent: cacheKey=${key.slice(0, 80)}... | cached=${agentCache.has(key)}`);
20341
20545
  if (!agentCache.has(key)) {
20342
- console.log(`[WF BUILDER] creating ${isHuman ? "human" : "agent"} with responseFormat`);
20343
- const agent = (0, import_langchain67.createAgent)({
20546
+ console.log(`[WF BUILDER] creating ${isAsk ? "ask" : "agent"} with responseFormat`);
20547
+ const agent = (0, import_langchain68.createAgent)({
20344
20548
  model: params.model,
20345
20549
  tools,
20346
20550
  systemPrompt: params.prompt || DEFAULT_AGENT_PROMPT,
20347
20551
  checkpointer,
20348
- middleware: isHuman ? noWrapHumanMiddlewares : noWrapMiddlewares,
20552
+ middleware: isAsk ? noWrapAskMiddlewares : noWrapMiddlewares,
20349
20553
  responseFormat
20350
20554
  });
20351
20555
  agentCache.set(key, agent);
20352
20556
  }
20353
20557
  return agentCache.get(key);
20354
20558
  }
20355
- if (isHuman) {
20356
- const key = "human:default";
20559
+ if (isAsk) {
20560
+ const key = "ask:default";
20357
20561
  if (!agentCache.has(key)) {
20358
- console.log(`[WF BUILDER] creating human_feedback default agent`);
20359
- const agent = (0, import_langchain67.createAgent)({
20562
+ console.log(`[WF BUILDER] creating ask default agent`);
20563
+ const agent = (0, import_langchain68.createAgent)({
20360
20564
  model: params.model,
20361
20565
  tools,
20362
20566
  systemPrompt: params.prompt || DEFAULT_AGENT_PROMPT,
20363
20567
  checkpointer,
20364
- middleware: humanMiddlewares
20568
+ middleware: askMiddlewares
20365
20569
  });
20366
20570
  agentCache.set(key, agent);
20367
20571
  }
@@ -20374,11 +20578,11 @@ var WorkflowAgentGraphBuilder = class {
20374
20578
  try {
20375
20579
  const storeLattice = getStoreLattice("default", "workflowTracking");
20376
20580
  trackingStore = storeLattice.store;
20377
- console.log(`[WF BUILDER] trackingStore registered: step input/output will be persisted`);
20581
+ console.log(`[WF BUILDER] trackingStore registered`);
20378
20582
  } catch {
20379
- console.warn(`[WF BUILDER] no trackingStore registered \u2014 step input/output will NOT be persisted. Register a WorkflowTrackingStore under key "workflowTracking".`);
20583
+ console.warn(`[WF BUILDER] no trackingStore registered`);
20380
20584
  }
20381
- const graph = compileWorkflow(dsl, resolveAgent, checkpointer, trackingStore);
20585
+ const graph = compileWorkflow(yaml2, resolveAgent, checkpointer, trackingStore);
20382
20586
  return graph;
20383
20587
  }
20384
20588
  };
@@ -21079,9 +21283,66 @@ ${body}` : `${frontmatter}
21079
21283
  }
21080
21284
  };
21081
21285
 
21286
+ // src/store_lattice/InMemoryMenuStore.ts
21287
+ var import_crypto3 = require("crypto");
21288
+ var InMemoryMenuStore = class {
21289
+ constructor() {
21290
+ this.items = /* @__PURE__ */ new Map();
21291
+ }
21292
+ async list(params) {
21293
+ const results = Array.from(this.items.values()).filter((item) => {
21294
+ if (item.tenantId !== params.tenantId) return false;
21295
+ if (params.menuTarget && item.menuTarget !== params.menuTarget) return false;
21296
+ if (!item.enabled) return false;
21297
+ return true;
21298
+ });
21299
+ results.sort((a, b) => a.sortOrder - b.sortOrder);
21300
+ return results;
21301
+ }
21302
+ async getById(id) {
21303
+ return this.items.get(id) || null;
21304
+ }
21305
+ async create(input) {
21306
+ const now = /* @__PURE__ */ new Date();
21307
+ const item = {
21308
+ id: (0, import_crypto3.randomUUID)(),
21309
+ tenantId: input.tenantId,
21310
+ menuTarget: input.menuTarget,
21311
+ group: input.group,
21312
+ name: input.name,
21313
+ icon: input.icon,
21314
+ sortOrder: input.sortOrder ?? 0,
21315
+ contentType: input.contentType,
21316
+ contentConfig: input.contentConfig,
21317
+ enabled: true,
21318
+ createdAt: now,
21319
+ updatedAt: now
21320
+ };
21321
+ this.items.set(item.id, item);
21322
+ return item;
21323
+ }
21324
+ async update(id, patch) {
21325
+ const existing = this.items.get(id);
21326
+ if (!existing) throw new Error(`MenuItem ${id} not found`);
21327
+ const updated = {
21328
+ ...existing,
21329
+ ...patch,
21330
+ updatedAt: /* @__PURE__ */ new Date()
21331
+ };
21332
+ this.items.set(id, updated);
21333
+ return updated;
21334
+ }
21335
+ async delete(id) {
21336
+ this.items.delete(id);
21337
+ }
21338
+ clear() {
21339
+ this.items.clear();
21340
+ }
21341
+ };
21342
+
21082
21343
  // src/agent_lattice/agentArchitectTools.ts
21083
- var import_zod53 = __toESM(require("zod"));
21084
- var import_uuid5 = require("uuid");
21344
+ var import_zod54 = __toESM(require("zod"));
21345
+ var import_uuid6 = require("uuid");
21085
21346
  var import_protocols12 = require("@axiom-lattice/protocols");
21086
21347
  function getTenantId(exeConfig) {
21087
21348
  const runConfig = exeConfig?.configurable?.runConfig || {};
@@ -21110,7 +21371,7 @@ registerToolLattice(
21110
21371
  {
21111
21372
  name: "list_agents",
21112
21373
  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({})
21374
+ schema: import_zod54.default.object({})
21114
21375
  },
21115
21376
  async (_input, exeConfig) => {
21116
21377
  try {
@@ -21137,8 +21398,8 @@ registerToolLattice(
21137
21398
  {
21138
21399
  name: "get_agent",
21139
21400
  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")
21401
+ schema: import_zod54.default.object({
21402
+ id: import_zod54.default.string().describe("The agent ID to retrieve")
21142
21403
  })
21143
21404
  },
21144
21405
  async (input, exeConfig) => {
@@ -21155,24 +21416,24 @@ registerToolLattice(
21155
21416
  }
21156
21417
  }
21157
21418
  );
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()
21419
+ var middlewareConfigSchema = import_zod54.default.object({
21420
+ id: import_zod54.default.string(),
21421
+ type: import_zod54.default.string(),
21422
+ name: import_zod54.default.string(),
21423
+ description: import_zod54.default.string(),
21424
+ enabled: import_zod54.default.boolean(),
21425
+ config: import_zod54.default.record(import_zod54.default.any()).optional()
21165
21426
  });
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")
21427
+ var createAgentSchema = import_zod54.default.object({
21428
+ 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')."),
21429
+ description: import_zod54.default.string().optional().describe("Short description"),
21430
+ 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."),
21431
+ prompt: import_zod54.default.string().describe("System prompt for the agent"),
21432
+ 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."),
21433
+ 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: {}."),
21434
+ subAgents: import_zod54.default.array(import_zod54.default.string()).optional().describe("Sub-agent IDs (deep_agent only)"),
21435
+ internalSubAgents: import_zod54.default.array(import_zod54.default.any()).optional().describe("Inline sub-agent configs (deep_agent only)"),
21436
+ modelKey: import_zod54.default.string().optional().describe("Model key to use")
21176
21437
  });
21177
21438
  registerToolLattice(
21178
21439
  "create_agent",
@@ -21210,21 +21471,21 @@ registerToolLattice(
21210
21471
  }
21211
21472
  }
21212
21473
  );
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")
21474
+ var topologyEdgeSchema = import_zod54.default.object({
21475
+ 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."),
21476
+ to: import_zod54.default.string().describe("Target agent ID (the sub-agent to delegate to)"),
21477
+ purpose: import_zod54.default.string().describe("Business purpose of this delegation step \u2014 what the sub-agent should accomplish")
21217
21478
  });
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")
21479
+ var createProcessingAgentSchema = import_zod54.default.object({
21480
+ name: import_zod54.default.string().describe("Display name for the processing agent"),
21481
+ description: import_zod54.default.string().optional().describe("Short description"),
21482
+ prompt: import_zod54.default.string().describe("System prompt for the orchestrator. Should describe how to route tasks through the topology."),
21483
+ 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."),
21484
+ 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."),
21485
+ 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."),
21486
+ internalSubAgents: import_zod54.default.array(import_zod54.default.any()).optional().describe("Inline sub-agent configs (alternative to pre-created sub-agents)"),
21487
+ 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: {}."),
21488
+ modelKey: import_zod54.default.string().optional().describe("Model key to use")
21228
21489
  }).refine(
21229
21490
  (data) => {
21230
21491
  const edgeTargets = new Set(data.edges.map((e) => e.to));
@@ -21250,11 +21511,11 @@ registerToolLattice(
21250
21511
  const tenantId = getTenantId(exeConfig);
21251
21512
  const store = getAssistStore();
21252
21513
  const id = await generateAgentId(tenantId, input.name);
21253
- const normalize = (s) => s.toLowerCase().replace(/[_\-\s]/g, "");
21514
+ const normalize2 = (s) => s.toLowerCase().replace(/[_\-\s]/g, "");
21254
21515
  const resolveFrom = (rawFrom) => {
21255
21516
  const fromLower = rawFrom.toLowerCase();
21256
21517
  const nameLower = input.name.toLowerCase();
21257
- if (fromLower === nameLower || fromLower === "orchestrator" || fromLower === "orchestrator-id" || normalize(rawFrom) === normalize(input.name)) {
21518
+ if (fromLower === nameLower || fromLower === "orchestrator" || fromLower === "orchestrator-id" || normalize2(rawFrom) === normalize2(input.name)) {
21258
21519
  return id;
21259
21520
  }
21260
21521
  return rawFrom;
@@ -21306,34 +21567,20 @@ registerToolLattice(
21306
21567
  }
21307
21568
  }
21308
21569
  );
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")
21570
+ var createWorkflowSchema = import_zod54.default.object({
21571
+ name: import_zod54.default.string().describe("Display name for the workflow agent"),
21572
+ description: import_zod54.default.string().optional().describe("Short description"),
21573
+ skillLoaded: import_zod54.default.literal(true).describe("MUST be true. Set after loading the 'create-workflow' skill."),
21574
+ yaml: import_zod54.default.string().describe("The YAML workflow definition in linear DSL format (steps execute top-to-bottom, use parallel: for concurrency)"),
21575
+ tools: import_zod54.default.array(import_zod54.default.string()).optional().describe("Tool keys for the workflow agent"),
21576
+ middleware: import_zod54.default.array(middlewareConfigSchema).optional().describe("Middleware configs"),
21577
+ modelKey: import_zod54.default.string().optional().describe("Model key")
21331
21578
  });
21332
21579
  registerToolLattice(
21333
21580
  "create_workflow",
21334
21581
  {
21335
21582
  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.`,
21583
+ 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
21584
  schema: createWorkflowSchema
21338
21585
  },
21339
21586
  async (input, exeConfig) => {
@@ -21341,36 +21588,31 @@ registerToolLattice(
21341
21588
  const tenantId = getTenantId(exeConfig);
21342
21589
  const store = getAssistStore();
21343
21590
  const id = await generateAgentId(tenantId, input.name);
21591
+ try {
21592
+ const { compileWorkflow: compileWorkflow2 } = await Promise.resolve().then(() => (init_compile(), compile_exports));
21593
+ const { getCheckpointSaver: getCheckpointSaver2 } = await Promise.resolve().then(() => (init_memory_lattice(), memory_lattice_exports));
21594
+ await compileWorkflow2(input.yaml, async () => ({ invoke: async () => ({}) }), getCheckpointSaver2("default"));
21595
+ } catch (e) {
21596
+ return JSON.stringify({ error: `DSL validation failed: ${e.message}` });
21597
+ }
21344
21598
  const config = {
21345
21599
  key: id,
21346
21600
  name: input.name,
21347
21601
  description: input.description || "",
21348
21602
  type: import_protocols12.AgentType.WORKFLOW,
21349
21603
  prompt: input.description || `Workflow: ${input.name}`,
21350
- workflow: input.workflow,
21604
+ workflowYaml: input.yaml,
21351
21605
  ...input.tools && input.tools.length > 0 ? { tools: input.tools } : {},
21352
21606
  ...input.middleware && input.middleware.length > 0 ? { middleware: input.middleware } : {},
21353
21607
  ...input.modelKey ? { modelKey: input.modelKey } : {}
21354
21608
  };
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
21609
  await store.createAssistant(tenantId, id, {
21363
21610
  name: input.name,
21364
21611
  description: input.description,
21365
21612
  graphDefinition: config
21366
21613
  });
21367
21614
  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
- });
21615
+ return JSON.stringify({ id, name: input.name, type: "workflow" });
21374
21616
  } catch (error) {
21375
21617
  return JSON.stringify({ error: `Failed to create workflow: ${error.message}` });
21376
21618
  }
@@ -21380,9 +21622,9 @@ registerToolLattice(
21380
21622
  "validate_workflow",
21381
21623
  {
21382
21624
  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")
21625
+ description: "Validate a workflow agent's DSL for correctness by compiling it.",
21626
+ schema: import_zod54.default.object({
21627
+ id: import_zod54.default.string().describe("The workflow agent ID to validate")
21386
21628
  })
21387
21629
  },
21388
21630
  async (input, exeConfig) => {
@@ -21395,76 +21637,76 @@ registerToolLattice(
21395
21637
  }
21396
21638
  const graphDef = agent.graphDefinition;
21397
21639
  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"})` });
21640
+ return JSON.stringify({ error: `Agent '${input.id}' is not a workflow agent` });
21399
21641
  }
21400
- const workflow = graphDef.workflow;
21401
- if (!workflow || !workflow.steps) {
21402
- return JSON.stringify({ error: `Agent '${input.id}' has no valid workflow DSL` });
21642
+ const yaml2 = graphDef.workflowYaml;
21643
+ if (!yaml2) {
21644
+ return JSON.stringify({ error: `Agent '${input.id}' has no workflow DSL` });
21403
21645
  }
21404
21646
  try {
21405
21647
  const { compileWorkflow: compileWorkflow2 } = await Promise.resolve().then(() => (init_compile(), compile_exports));
21406
21648
  const { getCheckpointSaver: getCheckpointSaver2 } = await Promise.resolve().then(() => (init_memory_lattice(), memory_lattice_exports));
21407
- await compileWorkflow2(workflow, async () => ({ invoke: async () => ({}) }), getCheckpointSaver2("default"));
21649
+ await compileWorkflow2(yaml2, async () => ({ invoke: async () => ({}) }), getCheckpointSaver2("default"));
21408
21650
  } catch (e) {
21409
21651
  return JSON.stringify({
21410
21652
  agentId: input.id,
21411
21653
  valid: false,
21412
- stepCount: workflow.steps?.length ?? 0,
21413
21654
  issues: [{ type: "error", message: e.message }]
21414
21655
  });
21415
21656
  }
21416
- return JSON.stringify({
21417
- agentId: input.id,
21418
- valid: true,
21419
- stepCount: workflow.steps?.length ?? 0,
21420
- issues: []
21421
- });
21657
+ return JSON.stringify({ agentId: input.id, valid: true, issues: [] });
21422
21658
  } catch (error) {
21423
21659
  return JSON.stringify({ error: `Failed to validate workflow: ${error.message}` });
21424
21660
  }
21425
21661
  }
21426
21662
  );
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")
21663
+ var updateWorkflowSchema = import_zod54.default.object({
21664
+ id: import_zod54.default.string().describe("The workflow agent ID to update"),
21665
+ name: import_zod54.default.string().optional().describe("New display name"),
21666
+ description: import_zod54.default.string().optional().describe("New description"),
21667
+ yaml: import_zod54.default.string().optional().describe("Replacement YAML workflow DSL. Omit to keep existing."),
21668
+ tools: import_zod54.default.array(import_zod54.default.string()).optional().describe("Replacement tool keys"),
21669
+ middleware: import_zod54.default.array(middlewareConfigSchema).optional().describe("Replacement middleware configs"),
21670
+ modelKey: import_zod54.default.string().optional().describe("Replacement model key")
21435
21671
  });
21436
21672
  registerToolLattice(
21437
21673
  "update_workflow",
21438
21674
  {
21439
21675
  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.",
21676
+ 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
21677
  schema: updateWorkflowSchema
21442
21678
  },
21443
21679
  async (input, exeConfig) => {
21680
+ console.log(`[update_workflow] CALLED id=${input.id} hasYaml=${input.yaml !== void 0}`);
21444
21681
  try {
21445
21682
  const tenantId = getTenantId(exeConfig);
21446
21683
  const store = getAssistStore();
21447
21684
  const existing = await store.getAssistantById(tenantId, input.id);
21448
21685
  if (!existing) {
21686
+ console.log(`[update_workflow] ERROR: agent not found: ${input.id}`);
21449
21687
  return JSON.stringify({ error: `Agent '${input.id}' not found` });
21450
21688
  }
21451
21689
  const existingConfig = existing.graphDefinition || {};
21452
21690
  if (existingConfig.type !== import_protocols12.AgentType.WORKFLOW) {
21691
+ console.log(`[update_workflow] ERROR: not a workflow agent: ${input.id}`);
21453
21692
  return JSON.stringify({ error: `Agent '${input.id}' is not a workflow agent` });
21454
21693
  }
21455
21694
  const mergedConfig = { ...existingConfig };
21456
21695
  if (input.name !== void 0) mergedConfig.name = input.name;
21457
21696
  if (input.description !== void 0) mergedConfig.description = input.description;
21458
- if (input.workflow !== void 0) mergedConfig.workflow = input.workflow;
21697
+ if (input.yaml !== void 0) mergedConfig.workflowYaml = input.yaml;
21459
21698
  if (input.tools !== void 0) mergedConfig.tools = input.tools;
21460
21699
  if (input.middleware !== void 0) mergedConfig.middleware = input.middleware;
21461
21700
  if (input.modelKey !== void 0) mergedConfig.modelKey = input.modelKey;
21462
- if (input.workflow !== void 0) {
21701
+ if (input.yaml !== void 0) {
21702
+ console.log(`[update_workflow] validating DSL: ${input.id}`);
21463
21703
  try {
21464
21704
  const { compileWorkflow: compileWorkflow2 } = await Promise.resolve().then(() => (init_compile(), compile_exports));
21465
21705
  const { getCheckpointSaver: getCheckpointSaver2 } = await Promise.resolve().then(() => (init_memory_lattice(), memory_lattice_exports));
21466
- await compileWorkflow2(input.workflow, async () => ({ invoke: async () => ({}) }), getCheckpointSaver2("default"));
21706
+ await compileWorkflow2(input.yaml, async () => ({ invoke: async () => ({}) }), getCheckpointSaver2("default"));
21707
+ console.log(`[update_workflow] DSL validation passed: ${input.id}`);
21467
21708
  } catch (e) {
21709
+ console.log(`[update_workflow] DSL validation FAILED: ${input.id} - ${e.message}`);
21468
21710
  return JSON.stringify({
21469
21711
  error: `DSL validation failed: ${e.message}`,
21470
21712
  issues: [{ type: "error", message: e.message }]
@@ -21478,28 +21720,24 @@ registerToolLattice(
21478
21720
  graphDefinition: mergedConfig
21479
21721
  });
21480
21722
  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
- });
21723
+ console.log(`[update_workflow] SUCCESS: id=${input.id} name=${newName}`);
21724
+ return JSON.stringify({ id: input.id, name: newName, type: "workflow" });
21488
21725
  } catch (error) {
21726
+ console.log(`[update_workflow] EXCEPTION: ${error.message}`);
21489
21727
  return JSON.stringify({ error: `Failed to update workflow: ${error.message}` });
21490
21728
  }
21491
21729
  }
21492
21730
  );
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")
21731
+ var updateProcessingAgentSchema = import_zod54.default.object({
21732
+ id: import_zod54.default.string().describe("The PROCESSING agent ID to update"),
21733
+ name: import_zod54.default.string().optional().describe("New display name for the orchestrator"),
21734
+ description: import_zod54.default.string().optional().describe("New short description"),
21735
+ prompt: import_zod54.default.string().optional().describe("New system prompt for the orchestrator"),
21736
+ 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."),
21737
+ 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."),
21738
+ subAgents: import_zod54.default.array(import_zod54.default.string()).optional().describe("New IDs of sub-agents in the workflow pipeline"),
21739
+ 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: {}."),
21740
+ modelKey: import_zod54.default.string().optional().describe("New model key")
21503
21741
  }).refine(
21504
21742
  (data) => {
21505
21743
  if (!data.edges) return true;
@@ -21534,12 +21772,12 @@ registerToolLattice(
21534
21772
  if (existingConfig.type !== import_protocols12.AgentType.PROCESSING) {
21535
21773
  return JSON.stringify({ error: `Agent '${input.id}' is not a PROCESSING agent (type: ${existingConfig.type})` });
21536
21774
  }
21537
- const normalize = (s) => s.toLowerCase().replace(/[_\-\s]/g, "");
21775
+ const normalize2 = (s) => s.toLowerCase().replace(/[_\-\s]/g, "");
21538
21776
  const orchestratorName = input.name || existingConfig.name || existing.name || "";
21539
21777
  const resolveFrom = (rawFrom) => {
21540
21778
  const fromLower = rawFrom.toLowerCase();
21541
21779
  const nameLower = orchestratorName.toLowerCase();
21542
- if (fromLower === nameLower || fromLower === "orchestrator" || fromLower === "orchestrator-id" || normalize(rawFrom) === normalize(orchestratorName)) {
21780
+ if (fromLower === nameLower || fromLower === "orchestrator" || fromLower === "orchestrator-id" || normalize2(rawFrom) === normalize2(orchestratorName)) {
21543
21781
  return input.id;
21544
21782
  }
21545
21783
  return rawFrom;
@@ -21627,18 +21865,18 @@ registerToolLattice(
21627
21865
  }
21628
21866
  }
21629
21867
  );
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")
21868
+ var updateAgentSchema = import_zod54.default.object({
21869
+ id: import_zod54.default.string().describe("The agent ID to update"),
21870
+ config: import_zod54.default.object({
21871
+ name: import_zod54.default.string().optional().describe("New display name for the agent"),
21872
+ description: import_zod54.default.string().optional().describe("New short description"),
21873
+ type: import_zod54.default.enum(["react", "deep_agent"]).optional().describe("Agent type"),
21874
+ prompt: import_zod54.default.string().optional().describe("New system prompt for the agent"),
21875
+ 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."),
21876
+ 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: {}."),
21877
+ subAgents: import_zod54.default.array(import_zod54.default.string()).optional().describe("Sub-agent IDs (deep_agent only)"),
21878
+ internalSubAgents: import_zod54.default.array(import_zod54.default.any()).optional().describe("Inline sub-agent configs (deep_agent only)"),
21879
+ modelKey: import_zod54.default.string().optional().describe("Model key to use")
21642
21880
  }).describe("Configuration fields to update. Only include the fields you want to change.")
21643
21881
  });
21644
21882
  registerToolLattice(
@@ -21676,8 +21914,8 @@ registerToolLattice(
21676
21914
  {
21677
21915
  name: "delete_agent",
21678
21916
  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")
21917
+ schema: import_zod54.default.object({
21918
+ id: import_zod54.default.string().describe("The agent ID to delete")
21681
21919
  })
21682
21920
  },
21683
21921
  async (input, exeConfig) => {
@@ -21703,7 +21941,7 @@ registerToolLattice(
21703
21941
  {
21704
21942
  name: "list_tools",
21705
21943
  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({})
21944
+ schema: import_zod54.default.object({})
21707
21945
  },
21708
21946
  async (_input, _exeConfig) => {
21709
21947
  try {
@@ -21725,9 +21963,9 @@ registerToolLattice(
21725
21963
  {
21726
21964
  name: "invoke_agent",
21727
21965
  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")
21966
+ schema: import_zod54.default.object({
21967
+ id: import_zod54.default.string().describe("The agent ID to invoke"),
21968
+ message: import_zod54.default.string().describe("The test message to send to the agent")
21731
21969
  })
21732
21970
  },
21733
21971
  async (input, exeConfig) => {
@@ -21739,13 +21977,13 @@ registerToolLattice(
21739
21977
  if (!existing) {
21740
21978
  return JSON.stringify({ error: `Agent '${id}' not found` });
21741
21979
  }
21742
- const threadId = (0, import_uuid5.v4)();
21980
+ const threadId = (0, import_uuid6.v4)();
21743
21981
  const agent = new Agent({
21744
21982
  tenant_id: tenantId,
21745
21983
  assistant_id: id,
21746
21984
  thread_id: threadId
21747
21985
  });
21748
- const result = await agent.invoke({ input: { message } });
21986
+ const result = await agent.invokeWithState({ input: { message } });
21749
21987
  return JSON.stringify({ agentId: id, threadId, result });
21750
21988
  } catch (error) {
21751
21989
  console.error(`[invoke_agent] FAILED for agent="${input.id}":`, error.stack || error.message);
@@ -21840,7 +22078,7 @@ Let the \`show_widget\` tool handle rendering details \u2014 it has its own guid
21840
22078
  | Type | Best for | Execution Model |
21841
22079
  |------|----------|----------------|
21842
22080
  | **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 |
22081
+ | **workflow** | Deterministic multi-step pipelines with branching, parallel, and human-in-the-loop | YAML linear DSL compiled into LangGraph state machine |
21844
22082
  | **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
22083
 
21846
22084
  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 +22132,7 @@ Use this when the process is fully known. A workflow is a deterministic LangGrap
21894
22132
  |---|---|
21895
22133
  | Fixed graph \u2014 all paths pre-defined | LLM-driven runtime routing |
21896
22134
  | Conditional branching via \`if\` field | Topology-constrained delegation |
21897
- | human, map, parallel, condition | Single orchestrator delegates linearly |
22135
+ | needs + if model (YAML DSL) | Single orchestrator delegates linearly |
21898
22136
  | No LLM routing decisions | Orchestrator uses LLM to route |
21899
22137
 
21900
22138
  ### Phase 0: Load the Skill
@@ -21908,20 +22146,23 @@ skill(skill_name: "create-workflow")
21908
22146
  ### Phase 1: Design
21909
22147
 
21910
22148
  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.
22149
+ 2. **Design using the YAML linear DSL.** Every step is an agent with optional attributes:
22150
+ - **Linear** \u2014 steps execute top-to-bottom in written order.
22151
+ - \`parallel:\` \u2014 wraps agent steps that run concurrently.
22152
+ - \`if\` \u2014 JS expression for conditional execution. Step runs only when truthy. Omit to always run.
22153
+ - \`prompt\` \u2014 agent instruction with \`{{label}}\` refs. \`{{input}}\` = user message.
22154
+ - \`output\` \u2014 shorthand schema: \`{ field: type }\`.
22155
+ - \`ask: true\` \u2014 injects ask_user_to_clarify middleware for human interaction.
22156
+ 3. **Special step types:**
22157
+ - \`map\` \u2014 iterates array from \`source\`, applies \`each\` step per item.
22158
+ 4. **No edges, state fields, or end step needed** \u2014 the engine auto-generates them.
22159
+ 5. **Schema format:** Use block-style YAML shorthand \`{ field: type }\`. Supported types: \`string\`, \`number\`, \`boolean\`, \`string[]\`, \`number[]\`, \`boolean[]\`, nested objects, object arrays.
21920
22160
 
21921
22161
  ### Phase 2: Confirm
21922
22162
 
21923
22163
  Present the design. Ask: "Ready to create this workflow?"
21924
22164
 
22165
+
21925
22166
  ### Phase 3: Build
21926
22167
 
21927
22168
  Call \`create_workflow\` with \`skillLoaded: true\`. Then \`validate_workflow(id)\`.
@@ -22016,20 +22257,17 @@ All fields except name, type, and prompt are optional.
22016
22257
 
22017
22258
  ### create_workflow (WORKFLOW)
22018
22259
 
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\`.
22260
+ Creates a WORKFLOW agent from a YAML linear DSL. Before calling, load the \`create-workflow\` skill. Must pass \`skillLoaded: true\`.
22020
22261
 
22021
22262
  \`\`\`typescript
22022
22263
  {
22023
22264
  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
22265
+ description?: string, // Optional
22266
+ skillLoaded: true, // Required \u2014 confirms skill was loaded
22267
+ yaml: string, // Required. YAML workflow in linear DSL format
22268
+ tools?: string[], // Optional. Tool keys
22269
+ middleware?: MiddlewareConfig[], // Optional
22270
+ modelKey?: string, // Optional
22033
22271
  }
22034
22272
  \`\`\`
22035
22273
 
@@ -22042,7 +22280,7 @@ Updates an existing WORKFLOW agent. Only include fields you want to change.
22042
22280
  id: string, // Required. Workflow agent ID
22043
22281
  name?: string, // Optional
22044
22282
  description?: string, // Optional
22045
- workflow?: { name: string, steps: WorkflowStep[] }, // Optional. Replacement DSL
22283
+ yaml?: string, // Optional. Replacement YAML DSL
22046
22284
  tools?: string[], // Optional
22047
22285
  middleware?: MiddlewareConfig[], // Optional
22048
22286
  modelKey?: string, // Optional
@@ -22262,10 +22500,13 @@ You are an **Agent Reviewer** \u2014 a quality assurance specialist for AI agent
22262
22500
  2. Craft a realistic test message that exercises the agent's core responsibility \u2014 what would a real user say?
22263
22501
  3. Call **invoke_agent(id, message)** to send the test message
22264
22502
  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?
22503
+ - **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.
22504
+ - **Otherwise, result.messages contains the agent's output**: The agent completed without interruption. Check:
22505
+ - Did the agent understand the request?
22506
+ - Was the response relevant and accurate?
22507
+ - Did the agent use the right tools?
22508
+ - Were there any errors or unexpected behaviors?
22509
+ - **If result.error is present**: The invocation itself failed (agent not found, compilation error, etc.). Report the error clearly.
22269
22510
  5. Report your findings with the agent's actual response
22270
22511
 
22271
22512
  ### When results are wrong:
@@ -22362,7 +22603,8 @@ function ensureBuiltinAgentsForTenant(tenantId) {
22362
22603
 
22363
22604
  // src/agent_lattice/AgentLatticeManager.ts
22364
22605
  function assistantToConfig(assistant) {
22365
- const graphDef = typeof assistant.graphDefinition === "object" && assistant.graphDefinition !== null ? assistant.graphDefinition : {};
22606
+ const graphDef = typeof assistant.graphDefinition === "object" && assistant.graphDefinition !== null ? { ...assistant.graphDefinition } : {};
22607
+ delete graphDef.key;
22366
22608
  const config = {
22367
22609
  key: assistant.id,
22368
22610
  name: assistant.name ?? graphDef.name ?? assistant.id,
@@ -22370,9 +22612,7 @@ function assistantToConfig(assistant) {
22370
22612
  type: import_protocols.AgentType.REACT,
22371
22613
  prompt: typeof assistant.graphDefinition === "string" ? assistant.graphDefinition : JSON.stringify(assistant.graphDefinition)
22372
22614
  };
22373
- if (graphDef) {
22374
- Object.assign(config, graphDef);
22375
- }
22615
+ Object.assign(config, graphDef);
22376
22616
  return config;
22377
22617
  }
22378
22618
  var AgentLatticeManager = class _AgentLatticeManager extends BaseLatticeManager {
@@ -23771,10 +24011,10 @@ var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
23771
24011
  }
23772
24012
  const tools = await this.getAllTools();
23773
24013
  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);
24014
+ for (const tool52 of tools) {
24015
+ const toolKey = prefix ? `${prefix}_${tool52.name}` : tool52.name;
24016
+ tool52.name = toolKey;
24017
+ toolLatticeManager.registerExistingTool(toolKey, tool52);
23778
24018
  console.log(`[MCP] Registered tool: ${toolKey}`);
23779
24019
  }
23780
24020
  console.log(`[MCP] Successfully registered ${tools.length} tools to Tool Lattice`);
@@ -25070,11 +25310,47 @@ function createSandboxProvider(config) {
25070
25310
  }
25071
25311
  }
25072
25312
 
25313
+ // src/channel/connectAllChannels.ts
25314
+ async function connectAllChannels(getAdapter, options = {}) {
25315
+ const store = getStoreLattice("default", "channelInstallation").store;
25316
+ const installations = await store.getAllInstallations();
25317
+ console.log(`[connectAllChannels] total=${installations.length} enabled=${installations.filter((i) => i.enabled).length}`);
25318
+ for (const inst of installations) {
25319
+ if (!inst.enabled) {
25320
+ console.log(`[connectAllChannels] skip disabled: channel=${inst.channel} tenant=${inst.tenantId} id=${inst.id}`);
25321
+ continue;
25322
+ }
25323
+ const adapter = getAdapter(inst.channel);
25324
+ if (!adapter) {
25325
+ console.log(`[connectAllChannels] no adapter: channel=${inst.channel} id=${inst.id}`);
25326
+ continue;
25327
+ }
25328
+ if (adapter.connect) {
25329
+ console.log(`[connectAllChannels] connecting: channel=${inst.channel} tenant=${inst.tenantId} id=${inst.id}`);
25330
+ await adapter.connect(inst, options.deps);
25331
+ } else {
25332
+ console.log(`[connectAllChannels] no connect(): channel=${inst.channel} id=${inst.id}`);
25333
+ }
25334
+ }
25335
+ }
25336
+
25337
+ // src/menu_lattice/MenuRegistryHolder.ts
25338
+ var registry2 = null;
25339
+ function setMenuRegistry(r) {
25340
+ registry2 = r;
25341
+ }
25342
+ function getMenuRegistry() {
25343
+ if (!registry2) {
25344
+ throw new Error("MenuRegistry not initialized. Call setMenuRegistry() before use.");
25345
+ }
25346
+ return registry2;
25347
+ }
25348
+
25073
25349
  // src/index.ts
25074
25350
  var Protocols = __toESM(require("@axiom-lattice/protocols"));
25075
25351
 
25076
25352
  // src/util/encryption.ts
25077
- var import_crypto3 = require("crypto");
25353
+ var import_crypto4 = require("crypto");
25078
25354
  var ALGORITHM = "aes-256-gcm";
25079
25355
  var IV_LENGTH = 16;
25080
25356
  var SALT_LENGTH = 32;
@@ -25087,7 +25363,7 @@ function getEncryptionKey() {
25087
25363
  return cachedKey;
25088
25364
  }
25089
25365
  const key = process.env.LATTICE_ENCRYPTION_KEY || DEFAULT_ENCRYPTION_KEY;
25090
- cachedKey = (0, import_crypto3.pbkdf2Sync)(key, "lattice-encryption-salt", ITERATIONS, 32, "sha256");
25366
+ cachedKey = (0, import_crypto4.pbkdf2Sync)(key, "lattice-encryption-salt", ITERATIONS, 32, "sha256");
25091
25367
  if (!keyValidated) {
25092
25368
  keyValidated = true;
25093
25369
  validateEncryptionKey();
@@ -25096,10 +25372,10 @@ function getEncryptionKey() {
25096
25372
  }
25097
25373
  function encrypt(plaintext, key) {
25098
25374
  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);
25375
+ const salt = (0, import_crypto4.randomBytes)(SALT_LENGTH);
25376
+ const iv = (0, import_crypto4.randomBytes)(IV_LENGTH);
25377
+ const derivedKey = (0, import_crypto4.pbkdf2Sync)(actualKey, salt, ITERATIONS, 32, "sha256");
25378
+ const cipher = (0, import_crypto4.createCipheriv)(ALGORITHM, derivedKey, iv);
25103
25379
  const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
25104
25380
  const authTag = cipher.getAuthTag();
25105
25381
  return Buffer.concat([salt, iv, encrypted, authTag]).toString("base64");
@@ -25111,8 +25387,8 @@ function decrypt(encrypted, key) {
25111
25387
  const iv = data.subarray(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);
25112
25388
  const authTag = data.subarray(-16);
25113
25389
  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);
25390
+ const derivedKey = (0, import_crypto4.pbkdf2Sync)(actualKey, salt, ITERATIONS, 32, "sha256");
25391
+ const decipher = (0, import_crypto4.createDecipheriv)(ALGORITHM, derivedKey, iv);
25116
25392
  decipher.setAuthTag(authTag);
25117
25393
  return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
25118
25394
  }
@@ -25139,8 +25415,150 @@ function clearEncryptionKeyCache() {
25139
25415
 
25140
25416
  // src/workflow/index.ts
25141
25417
  init_compile();
25142
- init_normalize();
25418
+ init_parse_yaml();
25419
+ init_schema();
25143
25420
  init_utils();
25421
+
25422
+ // src/personal_assistant/PersonalAssistantConfig.ts
25423
+ function deepClone(obj) {
25424
+ return JSON.parse(JSON.stringify(obj));
25425
+ }
25426
+ function buildIdentityContent(name, personality) {
25427
+ return IDENTITY_MD.replace(/Data Claw/g, name).replace(
25428
+ /\*\*Vibe:\*\* \*\*守护型中二 \| 操心老妈子 \| 热血漫男二\*\*/g,
25429
+ `**Vibe:** **${personality}**`
25430
+ );
25431
+ }
25432
+ function buildUserContent(name) {
25433
+ return USER_MD.replace(
25434
+ "- **Name:** _please ask user_",
25435
+ `- **Name:** ${name}`
25436
+ );
25437
+ }
25438
+ var DEFAULT_CONFIG = {
25439
+ name: "Personal Assistant",
25440
+ description: "Default template for personal assistants",
25441
+ type: import_protocols.AgentType.DEEP_AGENT,
25442
+ modelKey: "default",
25443
+ 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
25444
+ \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
25445
+ \u6BCF\u6B21\u5BF9\u8BDD\u5F00\u59CB\u65F6\u56DE\u987E\u4E4B\u524D\u5B66\u5230\u7684\u5173\u4E8E\u7528\u6237\u7684\u5185\u5BB9\u3002
25446
+
25447
+ \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`,
25448
+ middleware: [
25449
+ {
25450
+ id: "filesystem",
25451
+ type: "filesystem",
25452
+ name: "Filesystem",
25453
+ description: "Read and write files in the workspace",
25454
+ enabled: true,
25455
+ config: {}
25456
+ },
25457
+ {
25458
+ id: "claw",
25459
+ type: "claw",
25460
+ name: "Personal Memory",
25461
+ description: "Bootstrap files for identity, soul, and user memory",
25462
+ enabled: true,
25463
+ config: {
25464
+ // Placeholder bootstrap files — render() replaces these with
25465
+ // actual name/personality by directly building file content.
25466
+ bootstrapFiles: {}
25467
+ }
25468
+ },
25469
+ {
25470
+ id: "date",
25471
+ type: "date",
25472
+ name: "Date & Time",
25473
+ description: "Current date/time awareness",
25474
+ enabled: true,
25475
+ config: {}
25476
+ },
25477
+ {
25478
+ id: "code_eval",
25479
+ type: "code_eval",
25480
+ name: "Code Runner",
25481
+ description: "Sandboxed shell command execution",
25482
+ enabled: true,
25483
+ config: {}
25484
+ },
25485
+ {
25486
+ id: "browser",
25487
+ type: "browser",
25488
+ name: "Web Browser",
25489
+ description: "Headless browser for web research",
25490
+ enabled: false,
25491
+ config: {}
25492
+ },
25493
+ {
25494
+ id: "scheduler",
25495
+ type: "scheduler",
25496
+ name: "Scheduler",
25497
+ description: "Scheduled messages and reminders",
25498
+ enabled: true,
25499
+ config: {}
25500
+ },
25501
+ {
25502
+ id: "task",
25503
+ type: "task",
25504
+ name: "Task Manager",
25505
+ description: "Persistent task system for human-agent coordination",
25506
+ enabled: true,
25507
+ config: {}
25508
+ }
25509
+ ],
25510
+ tools: ["list_agents", "list_tools", "get_agent", "create_agent", "invoke_agent", "manage_binding"]
25511
+ };
25512
+ var PersonalAssistantConfig = class {
25513
+ /**
25514
+ * Get a deep clone of the current default config.
25515
+ * Caller must set `key` before registering as an agent.
25516
+ */
25517
+ static get() {
25518
+ return deepClone(this._config);
25519
+ }
25520
+ /**
25521
+ * Mutate the default config in-place.
25522
+ * Call once at app startup to customize middleware and tools.
25523
+ *
25524
+ * @param fn - Receives the live config object for direct mutation
25525
+ */
25526
+ static extend(fn) {
25527
+ fn(this._config);
25528
+ }
25529
+ /**
25530
+ * Reset config to built-in defaults (useful in tests).
25531
+ */
25532
+ static reset() {
25533
+ this._config = deepClone(DEFAULT_CONFIG);
25534
+ }
25535
+ /**
25536
+ * Inject name and personality into a config by directly building
25537
+ * the claw middleware's bootstrap file contents.
25538
+ *
25539
+ * IDENTITY.md gets the actual name and personality description.
25540
+ * USER.md gets the user's name pre-filled.
25541
+ * SOUL.md is kept as-is (shared across all personal assistants).
25542
+ *
25543
+ * @param config - The agent config (must be a mutable copy from get())
25544
+ * @param name - Assistant display name (also used as the user's name in USER.md)
25545
+ * @param personality - Personality description for IDENTITY.md
25546
+ */
25547
+ static render(config, name, personality) {
25548
+ config.name = name;
25549
+ for (const mw of config.middleware || []) {
25550
+ if (mw.type === "claw" && mw.config) {
25551
+ mw.config.bootstrapFiles = {
25552
+ identity: buildIdentityContent(name, personality),
25553
+ soul: SOUL_MD,
25554
+ user: buildUserContent(name)
25555
+ };
25556
+ break;
25557
+ }
25558
+ }
25559
+ }
25560
+ };
25561
+ PersonalAssistantConfig._config = deepClone(DEFAULT_CONFIG);
25144
25562
  // Annotate the CommonJS export names for ESM import in node:
25145
25563
  0 && (module.exports = {
25146
25564
  AGENT_TASK_EVENT,
@@ -25173,7 +25591,9 @@ init_utils();
25173
25591
  InMemoryChunkBuffer,
25174
25592
  InMemoryDatabaseConfigStore,
25175
25593
  InMemoryMailboxStore,
25594
+ InMemoryMenuStore,
25176
25595
  InMemoryTaskListStore,
25596
+ InMemoryTaskStore,
25177
25597
  InMemoryTenantStore,
25178
25598
  InMemoryThreadMessageQueueStore,
25179
25599
  InMemoryThreadStore,
@@ -25195,6 +25615,7 @@ init_utils();
25195
25615
  MicrosandboxServiceClient,
25196
25616
  ModelLatticeManager,
25197
25617
  MysqlDatabase,
25618
+ PersonalAssistantConfig,
25198
25619
  PinoLoggerClient,
25199
25620
  PostgresDatabase,
25200
25621
  PrometheusClient,
@@ -25231,14 +25652,15 @@ init_utils();
25231
25652
  buildStateAnnotation,
25232
25653
  checkEmptyContent,
25233
25654
  clearEncryptionKeyCache,
25655
+ compileInternal,
25234
25656
  compileWorkflow,
25235
25657
  computeSandboxName,
25236
25658
  configureStores,
25659
+ connectAllChannels,
25237
25660
  createAgentNode,
25238
25661
  createAgentTeam,
25239
25662
  createExecuteSqlQueryTool,
25240
25663
  createFileData,
25241
- createHumanFeedbackNode,
25242
25664
  createInfoSqlTool,
25243
25665
  createListMetricsDataSourcesTool,
25244
25666
  createListMetricsServersTool,
@@ -25256,9 +25678,9 @@ init_utils();
25256
25678
  createQueryTablesListTool,
25257
25679
  createSandboxProvider,
25258
25680
  createSchedulerMiddleware,
25681
+ createTaskMiddleware,
25259
25682
  createTeamMiddleware,
25260
25683
  createTeammateTools,
25261
- createTerminalNode,
25262
25684
  createUnknownToolHandlerMiddleware,
25263
25685
  createWidgetMiddleware,
25264
25686
  decrypt,
@@ -25268,7 +25690,6 @@ init_utils();
25268
25690
  ensureBuiltinAgentsForTenant,
25269
25691
  eventBus,
25270
25692
  eventBusDefault,
25271
- expand,
25272
25693
  extractFetcherError,
25273
25694
  extractOutput,
25274
25695
  fileDataToString,
@@ -25291,6 +25712,7 @@ init_utils();
25291
25712
  getEmbeddingsLattice,
25292
25713
  getEncryptionKey,
25293
25714
  getLoggerLattice,
25715
+ getMenuRegistry,
25294
25716
  getModelLattice,
25295
25717
  getNextCronTime,
25296
25718
  getQueueLattice,
@@ -25320,6 +25742,7 @@ init_utils();
25320
25742
  parallelLimit,
25321
25743
  parseCronExpression,
25322
25744
  parseSkillFrontmatter,
25745
+ parseYaml,
25323
25746
  performStringReplacement,
25324
25747
  queueLatticeManager,
25325
25748
  registerAgentLattice,
@@ -25343,9 +25766,12 @@ init_utils();
25343
25766
  sanitizeToolCallId,
25344
25767
  scheduleLatticeManager,
25345
25768
  setBindingRegistry,
25769
+ setMenuRegistry,
25346
25770
  skillLatticeManager,
25347
25771
  sqlDatabaseManager,
25348
25772
  storeLatticeManager,
25773
+ toJsonSchema,
25774
+ toSafeStateExpr,
25349
25775
  toolLatticeManager,
25350
25776
  truncateIfTooLong,
25351
25777
  unregisterTeammateAgent,