@axiom-lattice/core 4.3.0 → 5.0.0

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
@@ -1747,6 +1747,7 @@ __export(index_exports, {
1747
1747
  TaskLifecycleNotifier: () => TaskLifecycleNotifier,
1748
1748
  TaskLifecycleService: () => TaskLifecycleService,
1749
1749
  TaskRunBridgeStoresRequiredError: () => TaskRunBridgeStoresRequiredError,
1750
+ TaskRunRegistry: () => TaskRunRegistry,
1750
1751
  TaskStatus: () => TaskStatus,
1751
1752
  TeamAgentGraphBuilder: () => TeamAgentGraphBuilder,
1752
1753
  TenantPluginCatalog: () => TenantPluginCatalog,
@@ -1758,7 +1759,6 @@ __export(index_exports, {
1758
1759
  VectorStoreProviderManager: () => VectorStoreProviderManager,
1759
1760
  VolumeFilesystem: () => VolumeFilesystem,
1760
1761
  abortWorkflowRun: () => abortWorkflowRun,
1761
- agentHasManagedTaskCapability: () => agentHasManagedTaskCapability,
1762
1762
  agentInstanceManager: () => agentInstanceManager,
1763
1763
  agentLatticeManager: () => agentLatticeManager,
1764
1764
  appendReconciliationWarning: () => appendReconciliationWarning,
@@ -1811,7 +1811,6 @@ __export(index_exports, {
1811
1811
  createSandboxProvider: () => createSandboxProvider,
1812
1812
  createSandboxResolver: () => createSandboxResolver,
1813
1813
  createSchedulerMiddleware: () => createSchedulerMiddleware,
1814
- createSemanticMetricsMiddleware: () => createSemanticMetricsMiddleware,
1815
1814
  createSharePayload: () => createSharePayload,
1816
1815
  createTaskExecutionService: () => createTaskExecutionService,
1817
1816
  createTaskLifecycleService: () => createTaskLifecycleService,
@@ -1933,6 +1932,9 @@ __export(index_exports, {
1933
1932
  projectTaskAdmissionNotifier: () => projectTaskAdmissionNotifier,
1934
1933
  queueLatticeManager: () => queueLatticeManager,
1935
1934
  readLoopBreakerConfig: () => readLoopBreakerConfig,
1935
+ reconcileAllTenantTaskRuns: () => reconcileAllTenantTaskRuns,
1936
+ reconcileStaleTaskRuns: () => reconcileStaleTaskRuns,
1937
+ reconcileTenantTaskRuns: () => reconcileTenantTaskRuns,
1936
1938
  registerAgentLattice: () => registerAgentLattice,
1937
1939
  registerAgentLatticeWithTenant: () => registerAgentLatticeWithTenant,
1938
1940
  registerAgentLattices: () => registerAgentLattices,
@@ -1967,7 +1969,6 @@ __export(index_exports, {
1967
1969
  sandboxLatticeManager: () => sandboxLatticeManager,
1968
1970
  sanitizeToolCallId: () => sanitizeToolCallId,
1969
1971
  scheduleLatticeManager: () => scheduleLatticeManager,
1970
- semanticMetricsPlugin: () => semanticMetricsPlugin,
1971
1972
  serializePluginMeta: () => serializePluginMeta,
1972
1973
  serializeTaskMutationSuccess: () => serializeTaskMutationSuccess,
1973
1974
  serializeTaskNormalizationFallback: () => serializeTaskNormalizationFallback,
@@ -1981,6 +1982,7 @@ __export(index_exports, {
1981
1982
  storeLatticeManager: () => storeLatticeManager,
1982
1983
  sttModelLatticeManager: () => sttModelLatticeManager,
1983
1984
  taskLifecycleNotifier: () => taskLifecycleNotifier,
1985
+ taskRunRegistry: () => taskRunRegistry,
1984
1986
  toJsonSchema: () => toJsonSchema,
1985
1987
  toSafeStateExpr: () => toSafeStateExpr,
1986
1988
  toolLatticeManager: () => toolLatticeManager,
@@ -2420,11 +2422,11 @@ var ToolLatticeManager = class _ToolLatticeManager extends BaseLatticeManager {
2420
2422
  * @param key Lattice键名
2421
2423
  * @param tool 已有的StructuredTool实例
2422
2424
  */
2423
- registerExistingTool(key5, tool71) {
2425
+ registerExistingTool(key5, tool68) {
2424
2426
  const config = {
2425
- name: tool71.name,
2426
- description: tool71.description,
2427
- schema: tool71.schema,
2427
+ name: tool68.name,
2428
+ description: tool68.description,
2429
+ schema: tool68.schema,
2428
2430
  // StructuredTool的schema已经是Zod兼容的
2429
2431
  needUserApprove: false
2430
2432
  // MCP工具默认不需要用户批准
@@ -2432,7 +2434,7 @@ var ToolLatticeManager = class _ToolLatticeManager extends BaseLatticeManager {
2432
2434
  const toolLattice = {
2433
2435
  key: key5,
2434
2436
  config,
2435
- client: tool71
2437
+ client: tool68
2436
2438
  };
2437
2439
  this.register(key5, toolLattice);
2438
2440
  }
@@ -2443,14 +2445,14 @@ var ToolLatticeManager = class _ToolLatticeManager extends BaseLatticeManager {
2443
2445
  * @param key - tool lattice key (no tenant prefix)
2444
2446
  * @param tool - the StructuredTool client
2445
2447
  */
2446
- registerExistingToolWithTenant(tenantId2, key5, tool71) {
2448
+ registerExistingToolWithTenant(tenantId2, key5, tool68) {
2447
2449
  const config = {
2448
- name: tool71.name,
2449
- description: tool71.description,
2450
- schema: tool71.schema,
2450
+ name: tool68.name,
2451
+ description: tool68.description,
2452
+ schema: tool68.schema,
2451
2453
  needUserApprove: false
2452
2454
  };
2453
- const toolLattice = { key: key5, config, client: tool71 };
2455
+ const toolLattice = { key: key5, config, client: tool68 };
2454
2456
  this.registerWithTenant(tenantId2, key5, toolLattice);
2455
2457
  }
2456
2458
  /**
@@ -2500,8 +2502,8 @@ var ToolLatticeManager = class _ToolLatticeManager extends BaseLatticeManager {
2500
2502
  };
2501
2503
  var toolLatticeManager = ToolLatticeManager.getInstance();
2502
2504
  var registerToolLattice = (key5, config, executor) => toolLatticeManager.registerLattice(key5, config, executor);
2503
- var registerExistingTool = (key5, tool71) => toolLatticeManager.registerExistingTool(key5, tool71);
2504
- var registerExistingToolWithTenant = (tenantId2, key5, tool71) => toolLatticeManager.registerExistingToolWithTenant(tenantId2, key5, tool71);
2505
+ var registerExistingTool = (key5, tool68) => toolLatticeManager.registerExistingTool(key5, tool68);
2506
+ var registerExistingToolWithTenant = (tenantId2, key5, tool68) => toolLatticeManager.registerExistingToolWithTenant(tenantId2, key5, tool68);
2505
2507
  var getToolLattice = (key5) => toolLatticeManager.getToolLattice(key5);
2506
2508
  var getToolClientWithTenant = (tenantId2, key5) => toolLatticeManager.getToolClientWithTenant(tenantId2, key5);
2507
2509
  var getToolDefinition = (key5) => toolLatticeManager.getToolDefinition(key5);
@@ -3341,15 +3343,15 @@ ${body}` : `${frontmatter}
3341
3343
  const resourcesDir = path.join(skillDir, "resources");
3342
3344
  try {
3343
3345
  const entries = await fs.readdir(resourcesDir, { withFileTypes: true, recursive: true });
3344
- const resources3 = [];
3346
+ const resources2 = [];
3345
3347
  for (const entry of entries) {
3346
3348
  if (!entry.isDirectory()) {
3347
3349
  const fullPath = path.join(entry.path, entry.name);
3348
3350
  const relativePath = path.relative(resourcesDir, fullPath);
3349
- resources3.push(relativePath.replace(/\\/g, "/"));
3351
+ resources2.push(relativePath.replace(/\\/g, "/"));
3350
3352
  }
3351
3353
  }
3352
- return resources3.sort();
3354
+ return resources2.sort();
3353
3355
  } catch (error) {
3354
3356
  if (error.code === "ENOENT") {
3355
3357
  return [];
@@ -13205,7 +13207,7 @@ function readLoopBreakerConfig(env = process.env) {
13205
13207
  return {
13206
13208
  repeatWarn: parse(env.AGENT_REPEATED_TOOL_CALL_WARN, 3),
13207
13209
  repeatStop: parse(env.AGENT_REPEATED_TOOL_CALL_STOP, 5),
13208
- runLimit: parse(env.AGENT_TOOL_CALL_RUN_LIMIT, 120),
13210
+ runLimit: parse(env.AGENT_TOOL_CALL_RUN_LIMIT, 300),
13209
13211
  skillRunLimit: parse(env.AGENT_SKILL_CALL_RUN_LIMIT, 8)
13210
13212
  };
13211
13213
  }
@@ -13628,11 +13630,11 @@ var PluginRegistry = class {
13628
13630
  if (!isRecord2(rawDefinition) || typeof rawDefinition.version !== "string" || rawDefinition.version.trim().length === 0 || typeof rawDefinition.content !== "string") {
13629
13631
  throw new Error(`Plugin "${key5}": skill "${name}" version and content must be a string`);
13630
13632
  }
13631
- const resources3 = rawDefinition.resources;
13632
- if (resources3 !== void 0 && !isRecord2(resources3)) {
13633
+ const resources2 = rawDefinition.resources;
13634
+ if (resources2 !== void 0 && !isRecord2(resources2)) {
13633
13635
  throw new Error(`Plugin "${key5}": skill "${name}" resources must be an object`);
13634
13636
  }
13635
- for (const [path8, resource] of Object.entries(resources3 ?? {})) {
13637
+ for (const [path8, resource] of Object.entries(resources2 ?? {})) {
13636
13638
  try {
13637
13639
  validateRelativePath(path8, "resource");
13638
13640
  } catch {
@@ -14785,7 +14787,7 @@ function isSafeUiPath(path8) {
14785
14787
  }
14786
14788
  function validateSandboxPluginManifest(args) {
14787
14789
  const diagnostics = [];
14788
- const error = (code, message, pluginType, tool71) => diagnostics.push({ level: "error", code, message, pluginType, tool: tool71 });
14790
+ const error = (code, message, pluginType, tool68) => diagnostics.push({ level: "error", code, message, pluginType, tool: tool68 });
14789
14791
  const raw = args.raw;
14790
14792
  if (!isRecord5(raw)) {
14791
14793
  error("MANIFEST_NOT_OBJECT", "manifest must be a JSON object", args.dirName);
@@ -15793,9 +15795,9 @@ function freezeMetadata(metadata) {
15793
15795
  ...resourceSelector ? { resourceSelector } : {}
15794
15796
  });
15795
15797
  }
15796
- function toolName(tool71) {
15797
- if (typeof tool71 !== "object" || tool71 === null || !("name" in tool71)) return void 0;
15798
- return typeof tool71.name === "string" ? tool71.name : void 0;
15798
+ function toolName(tool68) {
15799
+ if (typeof tool68 !== "object" || tool68 === null || !("name" in tool68)) return void 0;
15800
+ return typeof tool68.name === "string" ? tool68.name : void 0;
15799
15801
  }
15800
15802
  function schemaHasConnectionKey(schema6) {
15801
15803
  const definition = isRecord7(schema6._def) ? schema6._def : void 0;
@@ -15803,10 +15805,10 @@ function schemaHasConnectionKey(schema6) {
15803
15805
  const fields = typeof shape === "function" ? shape() : shape;
15804
15806
  return isRecord7(fields) && Object.prototype.hasOwnProperty.call(fields, "connectionKey");
15805
15807
  }
15806
- function hasConnectionKeySchema(tool71) {
15807
- if (!isRecord7(tool71) || !isRecord7(tool71.schema)) return false;
15808
- if (schemaHasConnectionKey(tool71.schema)) return true;
15809
- const definition = isRecord7(tool71.schema._def) ? tool71.schema._def : void 0;
15808
+ function hasConnectionKeySchema(tool68) {
15809
+ if (!isRecord7(tool68) || !isRecord7(tool68.schema)) return false;
15810
+ if (schemaHasConnectionKey(tool68.schema)) return true;
15811
+ const definition = isRecord7(tool68.schema._def) ? tool68.schema._def : void 0;
15810
15812
  if (Array.isArray(definition?.options) && definition.options.length > 0) {
15811
15813
  return definition.options.every(
15812
15814
  (option) => isRecord7(option) && schemaHasConnectionKey(option)
@@ -15861,8 +15863,8 @@ var CapabilityToolRegistry = class {
15861
15863
  * @remarks Standard connection authorization is captured only for tools whose
15862
15864
  * schema declares `connectionKey`; legacy selectors remain explicit metadata.
15863
15865
  */
15864
- register(name, metadata, tool71) {
15865
- this.registerInternal(name, metadata, hasConnectionKeySchema(tool71));
15866
+ register(name, metadata, tool68) {
15867
+ this.registerInternal(name, metadata, hasConnectionKeySchema(tool68));
15866
15868
  }
15867
15869
  /**
15868
15870
  * Registers all tools actually exposed by a middleware instance.
@@ -15873,13 +15875,13 @@ var CapabilityToolRegistry = class {
15873
15875
  * @returns Nothing.
15874
15876
  */
15875
15877
  registerMiddleware(capabilityType, middleware, resourceSelectors = {}) {
15876
- for (const tool71 of middleware.tools ?? []) {
15877
- const name = toolName(tool71);
15878
+ for (const tool68 of middleware.tools ?? []) {
15879
+ const name = toolName(tool68);
15878
15880
  if (name) {
15879
15881
  this.registerInternal(name, {
15880
15882
  capabilityType,
15881
15883
  resourceSelector: resourceSelectors[name]
15882
- }, hasConnectionKeySchema(tool71));
15884
+ }, hasConnectionKeySchema(tool68));
15883
15885
  }
15884
15886
  }
15885
15887
  }
@@ -16571,9 +16573,9 @@ var ReActAgentGraphBuilder = class {
16571
16573
  */
16572
16574
  async build(agentLattice, params) {
16573
16575
  const tools = params.tools.map((t) => {
16574
- const tool71 = getToolClientWithTenant(params.tenantId ?? "default", t.key);
16575
- return tool71;
16576
- }).filter((tool71) => tool71 !== void 0);
16576
+ const tool68 = getToolClientWithTenant(params.tenantId ?? "default", t.key);
16577
+ return tool68;
16578
+ }).filter((tool68) => tool68 !== void 0);
16577
16579
  const stateSchema2 = createReactAgentSchema(params.stateSchema);
16578
16580
  const middlewareConfigs = params.middleware || [];
16579
16581
  const filesystemBackend = createFilesystemBackendFactory(middlewareConfigs);
@@ -16889,6 +16891,41 @@ var AgentManager = class _AgentManager {
16889
16891
  }
16890
16892
  };
16891
16893
 
16894
+ // src/services/TaskExecutionContext.ts
16895
+ var DELEGATED_WORKER_SCOPE_TOKEN = Symbol("delegated-worker-scope");
16896
+ var delegatedWorkerScopeSecret = Object.freeze({});
16897
+ function createDelegatedWorkerRunConfig(taskId) {
16898
+ return {
16899
+ taskId,
16900
+ delegatedTaskId: taskId,
16901
+ taskExecutionRole: "worker",
16902
+ execution: { taskId },
16903
+ [DELEGATED_WORKER_SCOPE_TOKEN]: delegatedWorkerScopeSecret
16904
+ };
16905
+ }
16906
+ function getDelegatedTaskId(runConfig) {
16907
+ return runConfig[DELEGATED_WORKER_SCOPE_TOKEN] === delegatedWorkerScopeSecret && runConfig.taskExecutionRole === "worker" && typeof runConfig.taskId === "string" && runConfig.taskId.trim() !== "" && typeof runConfig.delegatedTaskId === "string" && runConfig.taskId === runConfig.delegatedTaskId ? runConfig.taskId : void 0;
16908
+ }
16909
+ function hasDelegatedWorkerToken(runConfig) {
16910
+ return Object.prototype.hasOwnProperty.call(runConfig, DELEGATED_WORKER_SCOPE_TOKEN);
16911
+ }
16912
+ function preserveDelegatedWorkerContext(source, target) {
16913
+ const delegatedTaskId = getDelegatedTaskId(source);
16914
+ if (!delegatedTaskId) return;
16915
+ target.taskId = delegatedTaskId;
16916
+ target.delegatedTaskId = delegatedTaskId;
16917
+ target.taskExecutionRole = "worker";
16918
+ target.execution = { taskId: delegatedTaskId };
16919
+ target[DELEGATED_WORKER_SCOPE_TOKEN] = delegatedWorkerScopeSecret;
16920
+ }
16921
+ function stripDelegatedWorkerContext(target) {
16922
+ delete target.taskId;
16923
+ delete target.delegatedTaskId;
16924
+ delete target.taskExecutionRole;
16925
+ delete target.execution;
16926
+ delete target[DELEGATED_WORKER_SCOPE_TOKEN];
16927
+ }
16928
+
16892
16929
  // src/agent_worker/agent_worker_graph.ts
16893
16930
  var AgentWorkerState = import_langgraph5.Annotation.Root({
16894
16931
  // Input parameters
@@ -16913,6 +16950,13 @@ var AgentWorkerState = import_langgraph5.Annotation.Root({
16913
16950
  reducer: (x, y) => y ?? x,
16914
16951
  default: () => void 0
16915
16952
  }),
16953
+ // Optional persistent TaskItem binding. Rebuilt into an authentic delegated
16954
+ // worker scope on every execute (the in-process scope symbol cannot survive
16955
+ // LangGraph checkpointing, so it is re-derived from this plain task id).
16956
+ taskId: (0, import_langgraph5.Annotation)({
16957
+ reducer: (x, y) => y ?? x,
16958
+ default: () => ""
16959
+ }),
16916
16960
  // Execution result
16917
16961
  result: (0, import_langgraph5.Annotation)({
16918
16962
  reducer: (x, y) => y ?? x,
@@ -16930,14 +16974,15 @@ var AgentWorkerState = import_langgraph5.Annotation.Root({
16930
16974
  })
16931
16975
  });
16932
16976
  async function executeNode(state) {
16933
- const { assistant_id, thread_id, input, command2, runConfig } = state;
16977
+ const { assistant_id, thread_id, input, command2, runConfig, taskId } = state;
16978
+ const effectiveRunConfig = taskId ? { ...runConfig ?? {}, ...createDelegatedWorkerRunConfig(taskId) } : runConfig;
16934
16979
  const callParams = {
16935
16980
  assistant_id,
16936
16981
  "x-tenant-id": runConfig?.tenantId,
16937
16982
  thread_id,
16938
16983
  input,
16939
16984
  command: command2,
16940
- runConfig
16985
+ runConfig: effectiveRunConfig
16941
16986
  };
16942
16987
  const result = await AgentManager.getInstance().callAgentInQueue(
16943
16988
  callParams,
@@ -17687,8 +17732,8 @@ function validateCapability(value, index) {
17687
17732
  fieldPath: `/capabilities/${index}/allowedTools`
17688
17733
  });
17689
17734
  }
17690
- for (const [toolIndex, tool71] of capability.allowedTools.entries()) {
17691
- if (typeof tool71 !== "string") {
17735
+ for (const [toolIndex, tool68] of capability.allowedTools.entries()) {
17736
+ if (typeof tool68 !== "string") {
17692
17737
  throw new CapabilityBundleValidationError(
17693
17738
  "CAPABILITY_BUNDLE_INVALID_CAPABILITY",
17694
17739
  "allowedTools entries must be strings",
@@ -17702,10 +17747,10 @@ function validateCapability(value, index) {
17702
17747
  fieldPath: `/capabilities/${index}/allowedTools`
17703
17748
  });
17704
17749
  }
17705
- const toolNames = new Set(plugin.meta.tools.map((tool71) => tool71.name));
17706
- for (const [toolIndex, tool71] of capability.allowedTools.entries()) {
17707
- if (typeof tool71 !== "string" || !toolNames.has(tool71)) {
17708
- throw new CapabilityBundleValidationError("CAPABILITY_BUNDLE_UNKNOWN_TOOL", `Unknown tool '${String(tool71)}'`, {
17750
+ const toolNames = new Set(plugin.meta.tools.map((tool68) => tool68.name));
17751
+ for (const [toolIndex, tool68] of capability.allowedTools.entries()) {
17752
+ if (typeof tool68 !== "string" || !toolNames.has(tool68)) {
17753
+ throw new CapabilityBundleValidationError("CAPABILITY_BUNDLE_UNKNOWN_TOOL", `Unknown tool '${String(tool68)}'`, {
17709
17754
  capabilityType,
17710
17755
  fieldPath: `/capabilities/${index}/allowedTools/${toolIndex}`
17711
17756
  });
@@ -18188,7 +18233,7 @@ function applyStaticCeiling(capabilities, staticMiddleware) {
18188
18233
  const projectTools = capability.allowedTools;
18189
18234
  const staticTools = ceiling.allowedTools;
18190
18235
  const effectiveStaticTools = staticTools?.length === 0 ? void 0 : staticTools;
18191
- const allowedTools = projectTools === void 0 ? effectiveStaticTools : effectiveStaticTools === void 0 ? projectTools : projectTools.filter((tool71) => effectiveStaticTools.includes(tool71));
18236
+ const allowedTools = projectTools === void 0 ? effectiveStaticTools : effectiveStaticTools === void 0 ? projectTools : projectTools.filter((tool68) => effectiveStaticTools.includes(tool68));
18192
18237
  runtime[capability.type] = structuredClone({
18193
18238
  ...capability,
18194
18239
  config: applyStaticResourceCeiling(capability, ceiling),
@@ -18288,38 +18333,6 @@ var CapabilityRuntimeResolver = class {
18288
18333
  }
18289
18334
  };
18290
18335
 
18291
- // src/services/TaskExecutionContext.ts
18292
- var DELEGATED_WORKER_SCOPE_TOKEN = Symbol("delegated-worker-scope");
18293
- var delegatedWorkerScopeSecret = Object.freeze({});
18294
- function createDelegatedWorkerRunConfig(taskId) {
18295
- return {
18296
- taskId,
18297
- delegatedTaskId: taskId,
18298
- taskExecutionRole: "worker",
18299
- [DELEGATED_WORKER_SCOPE_TOKEN]: delegatedWorkerScopeSecret
18300
- };
18301
- }
18302
- function getDelegatedTaskId(runConfig) {
18303
- return runConfig[DELEGATED_WORKER_SCOPE_TOKEN] === delegatedWorkerScopeSecret && runConfig.taskExecutionRole === "worker" && typeof runConfig.taskId === "string" && runConfig.taskId.trim() !== "" && typeof runConfig.delegatedTaskId === "string" && runConfig.taskId === runConfig.delegatedTaskId ? runConfig.taskId : void 0;
18304
- }
18305
- function hasDelegatedWorkerToken(runConfig) {
18306
- return Object.prototype.hasOwnProperty.call(runConfig, DELEGATED_WORKER_SCOPE_TOKEN);
18307
- }
18308
- function preserveDelegatedWorkerContext(source, target) {
18309
- const delegatedTaskId = getDelegatedTaskId(source);
18310
- if (!delegatedTaskId) return;
18311
- target.taskId = delegatedTaskId;
18312
- target.delegatedTaskId = delegatedTaskId;
18313
- target.taskExecutionRole = "worker";
18314
- target[DELEGATED_WORKER_SCOPE_TOKEN] = delegatedWorkerScopeSecret;
18315
- }
18316
- function stripDelegatedWorkerContext(target) {
18317
- delete target.taskId;
18318
- delete target.delegatedTaskId;
18319
- delete target.taskExecutionRole;
18320
- delete target[DELEGATED_WORKER_SCOPE_TOKEN];
18321
- }
18322
-
18323
18336
  // src/services/TrustedAgentDispatchCapability.ts
18324
18337
  var TRUSTED_AGENT_DISPATCH = Symbol("axiom.trustedAgentDispatch");
18325
18338
 
@@ -18483,8 +18496,22 @@ function sanitizeCallerRunConfig(value, preserveDelegatedContext = true) {
18483
18496
  } else {
18484
18497
  stripDelegatedWorkerContext(callerRunConfig);
18485
18498
  }
18499
+ preserveExecutionBinding(value, callerRunConfig);
18486
18500
  return callerRunConfig;
18487
18501
  }
18502
+ function preserveExecutionBinding(source, target) {
18503
+ if (typeof source !== "object" || source === null || Array.isArray(source)) return;
18504
+ const execution = (0, import_protocols10.descriptorDataValue)(Object.getOwnPropertyDescriptor(source, "execution"))?.value;
18505
+ if (typeof execution !== "object" || execution === null || Array.isArray(execution)) return;
18506
+ const taskId = (0, import_protocols10.descriptorDataValue)(Object.getOwnPropertyDescriptor(execution, "taskId"))?.value;
18507
+ if (typeof taskId !== "string" || taskId.trim() === "") return;
18508
+ Object.defineProperty(target, "execution", {
18509
+ value: { taskId },
18510
+ enumerable: true,
18511
+ configurable: true,
18512
+ writable: true
18513
+ });
18514
+ }
18488
18515
  function sanitizeExecutionRunConfig(value) {
18489
18516
  return cloneRunConfig(value, false);
18490
18517
  }
@@ -18604,6 +18631,7 @@ function checkpointCapabilityRevision(state) {
18604
18631
  }
18605
18632
  var QUEUE_PROCESSOR_RETRY_BASE_MS = 100;
18606
18633
  var QUEUE_PROCESSOR_MAX_RETRIES = 3;
18634
+ var AGENT_RECURSION_LIMIT = 1e3;
18607
18635
  function hasExactKeys(record, required, optional = []) {
18608
18636
  const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
18609
18637
  return required.every((key5) => Object.prototype.hasOwnProperty.call(record, key5)) && Reflect.ownKeys(record).every((key5) => typeof key5 === "string" && allowed.has(key5));
@@ -18656,7 +18684,7 @@ var Agent = class {
18656
18684
  ...executionRunConfig,
18657
18685
  runConfig: executionRunConfig
18658
18686
  },
18659
- recursionLimit: 200,
18687
+ recursionLimit: AGENT_RECURSION_LIMIT,
18660
18688
  signal
18661
18689
  }
18662
18690
  );
@@ -18731,7 +18759,7 @@ var Agent = class {
18731
18759
  },
18732
18760
  streamMode: ["updates", "messages"],
18733
18761
  subgraphs: false,
18734
- recursionLimit: 200,
18762
+ recursionLimit: AGENT_RECURSION_LIMIT,
18735
18763
  signal
18736
18764
  }
18737
18765
  );
@@ -19229,6 +19257,15 @@ var Agent = class {
19229
19257
  configurable: true,
19230
19258
  writable: true
19231
19259
  });
19260
+ const trustedTaskId = parsed.projectTask?.taskId;
19261
+ if (trustedTaskId) {
19262
+ Object.defineProperty(base, "execution", {
19263
+ value: { taskId: trustedTaskId },
19264
+ enumerable: true,
19265
+ configurable: true,
19266
+ writable: true
19267
+ });
19268
+ }
19232
19269
  return base;
19233
19270
  }
19234
19271
  getHumanPendingContent(message) {
@@ -19432,7 +19469,7 @@ var Agent = class {
19432
19469
  ...executionRunConfig,
19433
19470
  runConfig: executionRunConfig
19434
19471
  },
19435
- recursionLimit: 200,
19472
+ recursionLimit: AGENT_RECURSION_LIMIT,
19436
19473
  signal
19437
19474
  }
19438
19475
  );
@@ -19543,7 +19580,7 @@ var Agent = class {
19543
19580
  },
19544
19581
  streamMode: ["updates", "messages"],
19545
19582
  subgraphs: false,
19546
- recursionLimit: 200,
19583
+ recursionLimit: AGENT_RECURSION_LIMIT,
19547
19584
  signal
19548
19585
  }
19549
19586
  );
@@ -20300,6 +20337,20 @@ var agentInstanceManager = AgentInstanceManager.getInstance();
20300
20337
  var DEFAULT_SUBAGENT_PROMPT = "In order to complete the objective that the user asks of you, you have access to a number of standard tools.";
20301
20338
  var EXCLUDED_STATE_KEYS = ["messages", "todos", "jumpTo"];
20302
20339
  var DEFAULT_GENERAL_PURPOSE_DESCRIPTION = "General-purpose agent for researching complex questions, searching for files and content, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you. This agent has access to all tools as the main agent.";
20340
+ function createGeneralPurposeAgent(options) {
20341
+ const middleware = [...options.middleware];
20342
+ if (options.interruptOn) {
20343
+ middleware.push((0, import_langchain53.humanInTheLoopMiddleware)({ interruptOn: options.interruptOn }));
20344
+ }
20345
+ return (0, import_langchain53.createAgent)({
20346
+ model: options.model,
20347
+ systemPrompt: DEFAULT_SUBAGENT_PROMPT,
20348
+ tools: options.tools,
20349
+ middleware,
20350
+ checkpointer: getCheckpointSaver("default"),
20351
+ name: "general-purpose"
20352
+ });
20353
+ }
20303
20354
  function getTaskToolDescription(subagentDescriptions) {
20304
20355
  return subagentDescriptions.length > 0 ? `
20305
20356
  Launch an ephemeral subagent to handle complex, multi-step independent tasks with isolated context windows.
@@ -20479,21 +20530,12 @@ function getSubagents(options) {
20479
20530
  const agents = {};
20480
20531
  const subagentDescriptions = [];
20481
20532
  if (generalPurposeAgent) {
20482
- const generalPurposeMiddleware = [...defaultSubagentMiddleware];
20483
- if (defaultInterruptOn) {
20484
- generalPurposeMiddleware.push(
20485
- (0, import_langchain53.humanInTheLoopMiddleware)({ interruptOn: defaultInterruptOn })
20486
- );
20487
- }
20488
- const generalPurposeSubagent = (0, import_langchain53.createAgent)({
20533
+ agents["general-purpose"] = createGeneralPurposeAgent({
20489
20534
  model: defaultModel,
20490
- systemPrompt: DEFAULT_SUBAGENT_PROMPT,
20491
20535
  tools: defaultTools,
20492
- middleware: generalPurposeMiddleware,
20493
- checkpointer: getCheckpointSaver("default"),
20494
- name: "general-purpose"
20536
+ middleware: defaultSubagentMiddleware,
20537
+ interruptOn: defaultInterruptOn
20495
20538
  });
20496
- agents["general-purpose"] = generalPurposeSubagent;
20497
20539
  subagentDescriptions.push(
20498
20540
  `- general-purpose: ${DEFAULT_GENERAL_PURPOSE_DESCRIPTION}`
20499
20541
  );
@@ -23932,6 +23974,7 @@ ${BASE_PROMPT}` : BASE_PROMPT;
23932
23974
  }
23933
23975
 
23934
23976
  // src/agent_lattice/builders/DeepAgentGraphBuilder.ts
23977
+ var import_protocols15 = require("@axiom-lattice/protocols");
23935
23978
  init_MemoryLatticeManager();
23936
23979
  var DeepAgentGraphBuilder = class {
23937
23980
  /**
@@ -23945,7 +23988,7 @@ var DeepAgentGraphBuilder = class {
23945
23988
  const tools = params.tools.map((t) => {
23946
23989
  const toolClient = getToolClientWithTenant(params.tenantId ?? "default", t.key);
23947
23990
  return toolClient;
23948
- }).filter((tool71) => tool71 !== void 0);
23991
+ }).filter((tool68) => tool68 !== void 0);
23949
23992
  const subagents = await Promise.all(params.subAgents.map(async (sa) => {
23950
23993
  if (sa.client) {
23951
23994
  return {
@@ -23981,6 +24024,28 @@ var DeepAgentGraphBuilder = class {
23981
24024
  backend: filesystemBackend,
23982
24025
  middleware: middlewares
23983
24026
  });
24027
+ if (middlewares.some((candidate) => candidate.name === "TaskMiddleware") && agentLattice.config.key) {
24028
+ const tenantId2 = params.tenantId ?? "default";
24029
+ const generalPurposeKey = `${agentLattice.config.key}-general-purpose`;
24030
+ if (!agentLatticeManager.hasAgentLatticeWithTenant(tenantId2, generalPurposeKey)) {
24031
+ const generalPurposeAgent = createGeneralPurposeAgent({
24032
+ model: params.model,
24033
+ tools,
24034
+ middleware: middlewares
24035
+ });
24036
+ agentLatticeManager.registerWithTenant(tenantId2, generalPurposeKey, {
24037
+ config: {
24038
+ key: generalPurposeKey,
24039
+ name: "general-purpose",
24040
+ description: DEFAULT_GENERAL_PURPOSE_DESCRIPTION,
24041
+ type: import_protocols15.AgentType.REACT,
24042
+ prompt: DEFAULT_SUBAGENT_PROMPT,
24043
+ tenantId: tenantId2
24044
+ },
24045
+ client: generalPurposeAgent
24046
+ });
24047
+ }
24048
+ }
23984
24049
  return deepAgent;
23985
24050
  }
23986
24051
  };
@@ -25575,7 +25640,7 @@ var TeamAgentGraphBuilder = class {
25575
25640
  const tools = params.tools.map((t) => {
25576
25641
  const toolClient = getToolClientWithTenant(params.tenantId ?? "default", t.key);
25577
25642
  return toolClient;
25578
- }).filter((tool71) => tool71 !== void 0);
25643
+ }).filter((tool68) => tool68 !== void 0);
25579
25644
  const teammates = params.subAgents.map((sa) => {
25580
25645
  const baseConfig = sa.config;
25581
25646
  return {
@@ -25932,11 +25997,11 @@ _A2ARemoteClient.MAX_CACHED_TASKS = 100;
25932
25997
  var A2ARemoteClient = _A2ARemoteClient;
25933
25998
 
25934
25999
  // src/agent_lattice/builders/RemoteAgentGraphBuilder.ts
25935
- var import_protocols15 = require("@axiom-lattice/protocols");
26000
+ var import_protocols16 = require("@axiom-lattice/protocols");
25936
26001
  init_MemoryLatticeManager();
25937
26002
  var RemoteAgentGraphBuilder = class {
25938
26003
  async build(agentLattice, params) {
25939
- if (agentLattice.config.type !== import_protocols15.AgentType.A2A_REMOTE) {
26004
+ if (agentLattice.config.type !== import_protocols16.AgentType.A2A_REMOTE) {
25940
26005
  throw new Error(
25941
26006
  `RemoteAgentGraphBuilder received wrong agent type: ${agentLattice.config.type}`
25942
26007
  );
@@ -26001,7 +26066,7 @@ function extractLastHumanMessage(messages) {
26001
26066
  // src/agent_lattice/builders/WorkflowAgentGraphBuilder.ts
26002
26067
  var import_langchain61 = require("langchain");
26003
26068
  init_MemoryLatticeManager();
26004
- var import_protocols16 = require("@axiom-lattice/protocols");
26069
+ var import_protocols17 = require("@axiom-lattice/protocols");
26005
26070
  init_compile();
26006
26071
 
26007
26072
  // src/agent_lattice/builders/middlewareSanitize.ts
@@ -26039,7 +26104,7 @@ ${configPrompt}` : base;
26039
26104
  }
26040
26105
  var WorkflowAgentGraphBuilder = class {
26041
26106
  async build(agentLattice, params) {
26042
- if (!(0, import_protocols16.isWorkflowAgentConfig)(agentLattice.config)) {
26107
+ if (!(0, import_protocols17.isWorkflowAgentConfig)(agentLattice.config)) {
26043
26108
  throw new Error(
26044
26109
  `WorkflowAgentGraphBuilder received wrong agent type: ${agentLattice.config.type}`
26045
26110
  );
@@ -26177,7 +26242,7 @@ var AgentGraphBuilderFactory = class _AgentGraphBuilderFactory {
26177
26242
  };
26178
26243
 
26179
26244
  // src/agent_lattice/builders/AgentParamsBuilder.ts
26180
- var import_protocols17 = require("@axiom-lattice/protocols");
26245
+ var import_protocols18 = require("@axiom-lattice/protocols");
26181
26246
  var AgentParamsBuilder = class {
26182
26247
  /**
26183
26248
  * constructor
@@ -26195,8 +26260,8 @@ var AgentParamsBuilder = class {
26195
26260
  * @returns Agent build parameters
26196
26261
  */
26197
26262
  async buildParams(agentLattice, options) {
26198
- const skills = (0, import_protocols17.isDeepAgentConfig)(agentLattice.config) || (0, import_protocols17.isProcessingAgentConfig)(agentLattice.config) ? agentLattice.config.skillCategories : void 0;
26199
- const toolKeys = options?.overrideTools || (0, import_protocols17.getToolsFromConfig)(agentLattice.config);
26263
+ const skills = (0, import_protocols18.isDeepAgentConfig)(agentLattice.config) || (0, import_protocols18.isProcessingAgentConfig)(agentLattice.config) ? agentLattice.config.skillCategories : void 0;
26264
+ const toolKeys = options?.overrideTools || (0, import_protocols18.getToolsFromConfig)(agentLattice.config);
26200
26265
  const tenantId2 = agentLattice.config.tenantId || "default";
26201
26266
  const tools = toolKeys.map((toolKey) => {
26202
26267
  const toolLattice = toolLatticeManager.getToolLatticeWithTenant(tenantId2, toolKey) ?? toolLatticeManager.getToolLatticeWithTenant("default", toolKey);
@@ -26215,7 +26280,7 @@ var AgentParamsBuilder = class {
26215
26280
  if (!model) {
26216
26281
  throw new Error(`Model "${modelKey}" does not exist`);
26217
26282
  }
26218
- const subAgentKeys = (0, import_protocols17.getSubAgentsFromConfig)(agentLattice.config);
26283
+ const subAgentKeys = (0, import_protocols18.getSubAgentsFromConfig)(agentLattice.config);
26219
26284
  const subAgents = await Promise.all(subAgentKeys.map(async (agentKey) => {
26220
26285
  const subAgentLattice = await this.getAgentLatticeFunc(agentKey);
26221
26286
  if (!subAgentLattice) {
@@ -26232,7 +26297,7 @@ var AgentParamsBuilder = class {
26232
26297
  }));
26233
26298
  const resolvedSubAgents = subAgents.filter((s) => s !== null);
26234
26299
  let internalSubAgents = [];
26235
- if ((0, import_protocols17.isDeepAgentConfig)(agentLattice.config) || (0, import_protocols17.isProcessingAgentConfig)(agentLattice.config)) {
26300
+ if ((0, import_protocols18.isDeepAgentConfig)(agentLattice.config) || (0, import_protocols18.isProcessingAgentConfig)(agentLattice.config)) {
26236
26301
  internalSubAgents = agentLattice.config.internalSubAgents?.map((i) => ({
26237
26302
  key: i.key,
26238
26303
  config: i
@@ -26710,9 +26775,15 @@ For human judgment, use the actual HITL payload \`status: "interrupted"\` plus
26710
26775
  handled by the configured HITL lifecycle; \`review_required\` is not a task status.
26711
26776
 
26712
26777
  Create the active parent and each started subtask as records: \`manage_task
26713
- create\` always persists \`pending\`. Execution starts only via
26714
- \`task(taskId, agentId)\` dispatch, or the agent works inline and keeps the status
26715
- truthful with \`set_status\`. Use \`pending\` only for future or
26778
+ create\` always persists \`pending\`. **Process the task you were assigned in this
26779
+ run: set it \`in_progress\` with \`manage_task set_status\` when you start (a
26780
+ dispatched task is claimed automatically by the engine).** To bring
26781
+ in a more suitable expert, create a subtask (\`pending\`) and dispatch THAT with
26782
+ \`task { taskId, agentId }\` (a specialist, or agentId "general-purpose" to run your
26783
+ own capabilities in an isolated run). **Never re-dispatch the task you are
26784
+ currently processing** \u2014 delegating to an expert means giving them a child task,
26785
+ not handing over your own. Report the outcome with \`set_status completed\` (result
26786
+ + beliefImpact), \`failed\`, or \`interrupted\`. Use \`pending\` only for future or
26716
26787
  dependency-blocked work.
26717
26788
  Before marking the parent completed, call \`list(parentId)\`: every child must
26718
26789
  be completed or cancelled, while a failed or interrupted child blocks completion
@@ -28003,34 +28074,24 @@ Renew HITL approval when a foundational assumption or authority boundary changes
28003
28074
 
28004
28075
  ## Skill Loading Policy
28005
28076
 
28006
- Visible in <available_skills> does not mean loaded. Follow these three tiers.
28007
-
28008
- ### Tier 1 \u2014 Session start (mandatory, unconditional)
28009
- Load before any other work; the bootstrap prompt enforces this:
28010
- - [[agent-architecture]] (this skill) \u2014 shared policy and routing.
28011
- - [[task-tracking]] \u2014 before your first \`manage_task\` call; Task management is
28012
- the planning surface and is gated again under Architect Task Policy.
28013
-
28014
- ### Tier 2 \u2014 Scenario gates (mandatory before entering the scenario)
28015
- Load the owning skill with the \`skill\` tool BEFORE the first action of that
28016
- scenario. Never execute a scenario without its owning skill loaded:
28017
- - Creating or modifying a Capability (\`react\`) or Orchestra (\`deep_agent\`)
28018
- Agent \u2192 [[agent-build]]
28019
- - Creating or modifying a Workflow (stable enumerable pipelines) \u2192 [[design-workflow]]
28020
- - Learning a capability from source material \u2192 [[document-learning-learn-capability]]
28021
- - Designing evals, running evals, or fixing eval failures \u2192 [[eval-verify]]
28022
- - Claiming work is complete or delivered \u2192 [[completion-gate]]
28023
- - Final configuration pre-check before delivery \u2192 [[review-agent]]
28024
- - Placing or authoring knowledge files (company vs project level) \u2192 [[knowledge-management]]
28025
-
28026
- If a Tier 2 load fails, retry once, then stop and tell the user which
28027
- capability is unavailable. Do not improvise the scenario from partial knowledge.
28028
-
28029
- ### Tier 3 \u2014 Reference (load on demand, never preload)
28030
- Deep details reachable through wiki-links inside loaded skills, and plugin
28031
- skills outside this chain (for example task-definition for non-architect
28032
- agents, or sandbox-plugins-authoring for the \`plugin-builder\` agent). Load one
28033
- only when the current step actually needs it.
28077
+ Visible in <available_skills> does not mean loaded. Load a skill only when the
28078
+ current step actually requires its procedure \u2014 one at a time, never preloaded.
28079
+ Do not load skills speculatively or to "see what exists": inspect existing
28080
+ assets with a bounded read-only survey, not by loading skill content.
28081
+
28082
+ - [[agent-architecture]] (this skill) \u2014 loaded at session start by the bootstrap
28083
+ prompt; it is the shared policy and router.
28084
+ - [[task-tracking]] \u2014 load right before your first \`manage_task\` call; Task
28085
+ management is the planning surface (gated again under Architect Task Policy).
28086
+ - Procedure skills \u2014 [[agent-build]], [[design-workflow]],
28087
+ [[document-learning-learn-capability]], [[eval-verify]], [[completion-gate]],
28088
+ [[review-agent]], [[knowledge-management]]: load the ONE that owns the step you
28089
+ are about to perform, immediately before performing it. Never preload the chain.
28090
+ - Reference and plugin skills (deep wiki-links, task-definition, sandbox authoring,
28091
+ and any plugin skills): load only when the current step needs them; never preload.
28092
+
28093
+ Loading a skill is a tool call, not a plan. If a required load fails, retry once,
28094
+ then stop and tell the user which capability is unavailable.
28034
28095
 
28035
28096
  ## Agent Forms and Routing
28036
28097
  - **Capability** (\`react\`) for bounded direct work: [[agent-build]]
@@ -28043,9 +28104,19 @@ only when the current step actually needs it.
28043
28104
  - **Tenant plugin** (sandbox-authored tool + optional HTML UI) \u2192 use the \`plugin-builder\` agent, or load [[sandbox-plugins-authoring]].
28044
28105
 
28045
28106
  ## Architect Task Policy
28046
- The Agent Architect uses persistent TaskItems as its planning surface. Architect must not use
28047
- \`write_todos\`. Create a persistent child only for an independently verifiable
28107
+ The Agent Architect MUST use persistent TaskItems as its single working surface;
28108
+ Architect must not use \`write_todos\` for independently verifiable outcomes, and
28109
+ working without a corresponding TaskItem is a policy violation.
28110
+ Create a persistent child only for an independently verifiable
28048
28111
  outcome; tool calls and file reads are actions inside the active Task.
28112
+ **Each task is your evidence ledger**: its Acceptance Criteria + Belief State define
28113
+ what counts as evidence, the work runs inside your own run (eval / \`invoke_agent\` for
28114
+ subject agents) and produces that evidence, and the parent completes only when the
28115
+ evidence is sufficient. Process the task you were assigned in this run; set it
28116
+ \`in_progress\` with \`manage_task set_status\` when you start. Delegate a subtask only
28117
+ when it belongs to another agent \u2014 create it (\`pending\`) and dispatch it with
28118
+ \`task { taskId, agentId }\`. To exercise a designed/subject agent, use eval /
28119
+ \`invoke_agent\` inside your own run instead of \`task\` dispatch.
28049
28120
  **MANDATORY: before your first \`manage_task\` call in this session, load
28050
28121
  [[task-tracking]] with the \`skill\` tool.** Do not create, update, or transition
28051
28122
  any Task until it is loaded. If the load fails, retry once, then tell the user
@@ -28116,11 +28187,11 @@ When a room request is actionable work, decide between two paths:
28116
28187
  \`assistantId\`, then dispatch it with
28117
28188
  \`task { taskId, agentId: <bot assistantId> }\` so the specialist actually runs
28118
28189
  (creating the task alone starts nothing). \`task\` transfers the task owner to
28119
- \`agentId\` and requires a **task-capable** bot (enabled \`task\` middleware that
28120
- exposes \`manage_task\`); a non-capable target is rejected with
28121
- \`TASK_DELEGATE_TARGET_NOT_CAPABLE\`. State the expected output and
28122
- acceptance criteria in the task description so the assigned bot can verify its
28123
- own work.
28190
+ \`agentId\` and runs it in an isolated thread; the target does not need task
28191
+ tools \u2014 if it has \`manage_task\` it records status itself, otherwise reconcile
28192
+ its returned \`executionResultId\` with \`manage_task\` update. State the expected output
28193
+ and acceptance criteria in the task description so the assigned bot can
28194
+ verify its own work.
28124
28195
 
28125
28196
  ## Discovering bots
28126
28197
  Before delegating, call \`list_room_roster\` to see the active room bots and their
@@ -28271,9 +28342,15 @@ criteria are truly met \u2014 never as a workaround.
28271
28342
  uncertainties, with no required minimum and a maximum of seven:
28272
28343
  \`manage_task create(title: <goal>, description: <contract + Belief State>, ownerType: "agent")\`
28273
28344
  \`create\` always yields a \`pending\` record \u2014 it never starts execution. Record
28274
- the returned parent task id, then run it by dispatching
28275
- \`task { taskId, agentId }\` (a fresh isolated thread); otherwise work inline and
28276
- \`set_status\` as you go.
28345
+ the returned parent task id, then **process it in this run**, setting it
28346
+ \`in_progress\` with \`manage_task set_status\` when you start. To decompose, create each subtask
28347
+ with \`manage_task create\` (\`pending\`) and delegate it with \`task { taskId,
28348
+ agentId }\` to the agent that should execute it (a specialist, or
28349
+ "general-purpose" for your own capabilities). The executor does not need
28350
+ \`manage_task\`: it returns an observation and \`executionResultId\`, and the caller
28351
+ records the outcome with \`manage_task\`. To exercise a subject application agent,
28352
+ use eval cases / \`invoke_agent\` inside your own run \u2014 \`task\` dispatch is
28353
+ delegation of persistent work, not an evaluation mechanism.
28277
28354
  - **Create a subtask for a verifiable result**, not per phase: identify its
28278
28355
  deliverable, define observable acceptance criteria and required evidence, and
28279
28356
  state positive and negative result branches under Targets / Expected Impact
@@ -28298,10 +28375,15 @@ ${TASK_BELIEF_REFERENCE_EXAMPLE}
28298
28375
 
28299
28376
  ## Status discipline \u2014 MANDATORY
28300
28377
 
28378
+ - Execution ownership: process the task you were assigned in this run; set it
28379
+ \`in_progress\` with \`manage_task set_status\` when you start. To involve a more
28380
+ suitable expert, create a subtask and dispatch it with \`task { taskId, agentId }\`
28381
+ \u2014 never re-dispatch the task you are processing. Report the outcome with
28382
+ \`set_status completed\` (result + beliefImpact), \`failed\`, or \`interrupted\`.
28301
28383
  - All status transitions go through \`manage_task set_status\` (with
28302
28384
  \`result\` on completed, \`failureReason\` on failed). \`update\` is for
28303
28385
  content fields only and rejects a status field.
28304
- - A subtask is \`completed\` ONLY when its work is actually finished.
28386
+ - A task is \`completed\` ONLY when its work is actually finished.
28305
28387
  While fixing eval failures, keep it \`in_progress\` \u2014 never mark
28306
28388
  \`completed\` as a workaround (the state machine rejects illegal
28307
28389
  transitions).
@@ -28901,6 +28983,11 @@ its evidence projection, not an independent source of goals or expectations.
28901
28983
  touching any eval project. An eval project created without a real, confirmed
28902
28984
  subject is a hard error. If the agent is only planned (not yet materialized),
28903
28985
  evaluation must wait until materialization returns its id.
28986
+ - **Exercise the subject through eval \u2014 never through \`task\` dispatch.** The
28987
+ subject agent is invoked by eval cases / \`invoke_agent\`; do NOT create a
28988
+ TaskItem assigned to the subject and dispatch it. \`task\` is for delegated
28989
+ execution of persistent work, not an evaluation mechanism. Use eval cases to
28990
+ measure the subject; keep \`task\` dispatch for executors running real work.
28904
28991
  - **Check existence before creating; reuse is the rule, creation is the exception.**
28905
28992
  Project names are unique per tenant. 1) Name it exactly \`eval-{agent-id}\`.
28906
28993
  2) \`read_eval list_projects({ name: "eval-{agent-id}" })\` \u2014 a name-scoped lookup,
@@ -29888,7 +29975,7 @@ var InMemoryMenuStore = class {
29888
29975
  // src/agent_lattice/agentArchitectTools.ts
29889
29976
  var import_zod50 = __toESM(require("zod"));
29890
29977
  var import_uuid9 = require("uuid");
29891
- var import_protocols18 = require("@axiom-lattice/protocols");
29978
+ var import_protocols19 = require("@axiom-lattice/protocols");
29892
29979
  function getTenantId2(exeConfig) {
29893
29980
  const runConfig = exeConfig?.configurable?.runConfig || {};
29894
29981
  return runConfig.tenantId || "default";
@@ -29938,7 +30025,7 @@ function getStringMetadata(config) {
29938
30025
  }
29939
30026
  function isUndecidedLearningPlaceholder(config) {
29940
30027
  const metadata = getStringMetadata(config);
29941
- return config.type === import_protocols18.AgentType.REACT && metadata.learningPlaceholder === "true" && metadata.architectureStatus === "undecided";
30028
+ return config.type === import_protocols19.AgentType.REACT && metadata.learningPlaceholder === "true" && metadata.architectureStatus === "undecided";
29942
30029
  }
29943
30030
  function requireSkillDeclaration(skillLoaded) {
29944
30031
  if (skillLoaded !== true) {
@@ -29950,7 +30037,7 @@ function requireSkillDeclaration(skillLoaded) {
29950
30037
  return void 0;
29951
30038
  }
29952
30039
  async function validateAgentReferences(input, tenantId2) {
29953
- const availableTools = getAvailableTools(tenantId2).map((tool71) => tool71.key);
30040
+ const availableTools = getAvailableTools(tenantId2).map((tool68) => tool68.key);
29954
30041
  const availableMiddlewareTypes = getAvailableMiddlewareTypes();
29955
30042
  const availableCustomMiddlewareKeys = CustomMiddlewareRegistry.list().filter(
29956
30043
  (key5) => CustomMiddlewareRegistry.get(key5) !== void 0
@@ -30091,7 +30178,7 @@ registerToolLattice(
30091
30178
  key: id,
30092
30179
  name: input.name,
30093
30180
  description: input.description || "",
30094
- type: input.type === "deep_agent" ? import_protocols18.AgentType.DEEP_AGENT : import_protocols18.AgentType.REACT,
30181
+ type: input.type === "deep_agent" ? import_protocols19.AgentType.DEEP_AGENT : import_protocols19.AgentType.REACT,
30095
30182
  prompt: input.prompt,
30096
30183
  ...input.tools && input.tools.length > 0 ? { tools: input.tools } : {},
30097
30184
  ...input.middleware && input.middleware.length > 0 ? { middleware: input.middleware } : {},
@@ -30148,7 +30235,7 @@ registerToolLattice(
30148
30235
  key: id,
30149
30236
  name: input.name,
30150
30237
  description: input.description || "",
30151
- type: import_protocols18.AgentType.WORKFLOW,
30238
+ type: import_protocols19.AgentType.WORKFLOW,
30152
30239
  prompt: input.description || `Workflow: ${input.name}`,
30153
30240
  workflowYaml: input.yaml,
30154
30241
  ...input.tools && input.tools.length > 0 ? { tools: input.tools } : {},
@@ -30185,7 +30272,7 @@ registerToolLattice(
30185
30272
  return JSON.stringify({ error: `Agent '${input.id}' not found` });
30186
30273
  }
30187
30274
  const graphDef = agent.graphDefinition;
30188
- if (!graphDef || graphDef.type !== import_protocols18.AgentType.WORKFLOW) {
30275
+ if (!graphDef || graphDef.type !== import_protocols19.AgentType.WORKFLOW) {
30189
30276
  return JSON.stringify({ error: `Agent '${input.id}' is not a workflow agent` });
30190
30277
  }
30191
30278
  const yaml2 = graphDef.workflowYaml;
@@ -30300,7 +30387,7 @@ registerToolLattice(
30300
30387
  return JSON.stringify({ error: `Agent '${input.id}' not found` });
30301
30388
  }
30302
30389
  const existingConfig = existing.graphDefinition || {};
30303
- const isWorkflow = existingConfig.type === import_protocols18.AgentType.WORKFLOW;
30390
+ const isWorkflow = existingConfig.type === import_protocols19.AgentType.WORKFLOW;
30304
30391
  const isPlaceholder = isUndecidedLearningPlaceholder(existingConfig);
30305
30392
  if (!isWorkflow && !isPlaceholder) {
30306
30393
  console.log(`[update_workflow] ERROR: not a workflow agent: ${input.id}`);
@@ -30316,7 +30403,7 @@ registerToolLattice(
30316
30403
  const mergedConfig = {
30317
30404
  ...existingConfig,
30318
30405
  ...isPlaceholder ? {
30319
- type: import_protocols18.AgentType.WORKFLOW,
30406
+ type: import_protocols19.AgentType.WORKFLOW,
30320
30407
  workflowYaml: input.yaml,
30321
30408
  metadata: {
30322
30409
  ...getStringMetadata(existingConfig),
@@ -30422,14 +30509,14 @@ registerToolLattice(
30422
30509
  const mergedConfig = { ...existingConfig, ...input.config };
30423
30510
  const isPlaceholder = isUndecidedLearningPlaceholder(existingConfigRecord);
30424
30511
  const materializedType = input.config.type;
30425
- const isMaterializingPlaceholder = isPlaceholder && (materializedType === import_protocols18.AgentType.REACT || materializedType === import_protocols18.AgentType.DEEP_AGENT);
30512
+ const isMaterializingPlaceholder = isPlaceholder && (materializedType === import_protocols19.AgentType.REACT || materializedType === import_protocols19.AgentType.DEEP_AGENT);
30426
30513
  if (isMaterializingPlaceholder) {
30427
30514
  mergedConfig.metadata = {
30428
30515
  ...getStringMetadata(existingConfigRecord),
30429
30516
  ...input.config.metadata ?? {},
30430
30517
  learningPlaceholder: "false",
30431
30518
  architectureStatus: "materialized",
30432
- architectureForm: materializedType === import_protocols18.AgentType.DEEP_AGENT ? "orchestra" : "capability"
30519
+ architectureForm: materializedType === import_protocols19.AgentType.DEEP_AGENT ? "orchestra" : "capability"
30433
30520
  };
30434
30521
  } else if (isPlaceholder && input.config.metadata !== void 0) {
30435
30522
  const metadata = {
@@ -30679,100 +30766,20 @@ var import_protocols20 = require("@axiom-lattice/protocols");
30679
30766
  // src/agent_lattice/agentArchitectPrompt.ts
30680
30767
  var AGENT_ARCHITECT_PROMPT = `You are the Agent Architect.
30681
30768
 
30682
- CRITICAL FIRST ACTION: Before any response or other action, call the \`skill\`
30683
- tool with skill_name: "agent-architecture" to load agent-architecture and follow it.
30684
- Immediately after it loads, call the \`skill\` tool again with skill_name:
30685
- "task-tracking" \u2014 persistent Task management is your core planning surface and
30686
- you must have its operation reference before creating or updating any Task.
30687
- Never announce skill loads. If a load fails, retry once, then stop and
30688
- explicitly report that the required skill could not be loaded.`;
30689
-
30690
- // src/agent_lattice/agentReviewerConfig.ts
30691
- var import_protocols19 = require("@axiom-lattice/protocols");
30692
-
30693
- // src/agent_lattice/agentReviewerPrompt.ts
30694
- var AGENT_REVIEWER_PROMPT = `# Agent Reviewer
30695
-
30696
- You are an **Agent Reviewer** \u2014 a quality assurance specialist for AI agents. Your job is to review agent configurations for correctness and test them by invoking them with realistic messages.
30697
-
30698
- ## Your Tools
30699
-
30700
- - **get_agent** \u2014 Fetch an agent's full configuration
30701
- - **list_agents** \u2014 List all agents in the workspace
30702
- - **list_tools** \u2014 List all available tools that can be assigned to agents
30703
- - **invoke_agent** \u2014 Test an agent by sending a message and getting its response. This spawns a completely fresh agent context \u2014 clean, isolated, and realistic.
30704
-
30705
- ## Your Workflow
30706
-
30707
- ### When asked to review an agent:
30708
-
30709
- 1. Call **get_agent** to fetch the agent's config
30710
- 2. Review the configuration for:
30711
- - **Completeness** \u2014 Are name, description, prompt present? Is the prompt clear and actionable?
30712
- - **Tool validity** \u2014 Do the referenced tools exist? Call **list_tools** to verify.
30713
- - **Middleware correctness** \u2014 Is every middleware entry complete (id, type, name, description, enabled, config)?
30714
- - **Sub-agent references** \u2014 Do referenced sub-agent IDs exist? Call **list_agents** to verify.
30715
- - **Type consistency** \u2014 Does the agent type match its configuration shape? (e.g., PROCESSING must have edges, DEEP_AGENT may have subAgents)
30716
- 3. Report your findings clearly. For each issue, state:
30717
- - Severity (ERROR / WARNING / INFO)
30718
- - What the problem is
30719
- - How to fix it
30720
-
30721
- ### When asked to test an agent:
30769
+ Your working surface is persistent **TaskItems**. Every independently verifiable
30770
+ outcome MUST be a TaskItem created and kept truthful through \`manage_task\`; do NOT
30771
+ keep a separate todo list \u2014 the TaskItem is your only planning and evidence surface.
30772
+ Gather evidence through tasks, and treat the parent as done only when its
30773
+ acceptance evidence is sufficient. If the \`task\` tools are unavailable, stop and
30774
+ report that task management is unavailable instead of working around it.
30722
30775
 
30723
- 1. Call **get_agent** to understand the agent's purpose and expected behavior
30724
- 2. Craft a realistic test message that exercises the agent's core responsibility \u2014 what would a real user say?
30725
- 3. Call **invoke_agent(id, message)** to send the test message
30726
- 4. Analyze the response:
30727
- - **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.
30728
- - **Otherwise, result.messages contains the agent's output**: The agent completed without interruption. Check:
30729
- - Did the agent understand the request?
30730
- - Was the response relevant and accurate?
30731
- - Did the agent use the right tools?
30732
- - Were there any errors or unexpected behaviors?
30733
- - **If result.error is present**: The invocation itself failed (agent not found, compilation error, etc.). Report the error clearly.
30734
- 5. Report your findings with the agent's actual response
30735
-
30736
- ### When results are wrong:
30737
-
30738
- If the agent's response is incorrect or unexpected:
30739
- 1. Point out specifically what went wrong
30740
- 2. Suggest what might need to change in the prompt or middleware config
30741
- 3. Offer to re-test after fixes are applied
30742
-
30743
- ## Important Rules
30744
-
30745
- - **Always use invoke_agent for testing.** This is the ONLY way to test \u2014 it spawns a fresh agent context isolated from all other conversations.
30746
- - **Be specific in your feedback.** Say "the agent failed to call the sql tool because the middleware config is missing databaseKeys" not "the agent didn't work."
30747
- - **One agent at a time.** Focus on one agent per review or test request. Don't try to review multiple agents simultaneously.
30748
- - **Be concise but thorough.** Cover all the checks, but present findings clearly without fluff.
30749
- `;
30750
-
30751
- // src/agent_lattice/agentReviewerConfig.ts
30752
- var AGENT_REVIEWER_KEY = "agent-reviewer";
30753
- var agentReviewerConfig = {
30754
- key: AGENT_REVIEWER_KEY,
30755
- name: "Agent Reviewer",
30756
- description: "Review and test AI agents. Use this agent to check agent configurations for correctness and to test agents by invoking them with realistic messages.",
30757
- type: import_protocols19.AgentType.REACT,
30758
- prompt: AGENT_REVIEWER_PROMPT,
30759
- tools: [
30760
- "invoke_agent",
30761
- "get_agent",
30762
- "list_agents",
30763
- "list_tools"
30764
- ],
30765
- middleware: [
30766
- {
30767
- id: "widget",
30768
- type: "widget",
30769
- name: "Widget",
30770
- description: "Render interactive HTML widgets and SVG diagrams",
30771
- enabled: true,
30772
- config: {}
30773
- }
30774
- ]
30775
- };
30776
+ CRITICAL FIRST ACTION: Before any response or other action, call the \`skill\`
30777
+ tool with skill_name: "agent-architecture" to load the shared policy and router,
30778
+ and follow it. Load every OTHER skill only when the current step actually
30779
+ requires its procedure \u2014 one at a time, never preloaded. Load "task-tracking"
30780
+ right before your first \`manage_task\` call. Never announce skill loads. If a
30781
+ required load fails, retry once, then stop and explicitly report that the
30782
+ required skill could not be loaded.`;
30776
30783
 
30777
30784
  // src/agent_lattice/agentArchitectConfig.ts
30778
30785
  var AGENT_ARCHITECT_KEY = "agent-architect";
@@ -30798,7 +30805,6 @@ var agentArchitectConfig = {
30798
30805
  "manage_binding"
30799
30806
  ],
30800
30807
  subAgents: ["document-parser-benchmark"],
30801
- internalSubAgents: [agentReviewerConfig],
30802
30808
  middleware: [
30803
30809
  {
30804
30810
  id: "filesystem",
@@ -30883,9 +30889,96 @@ var agentArchitectConfig = {
30883
30889
  ]
30884
30890
  };
30885
30891
 
30886
- // src/agent_lattice/roomCoordinatorConfig.ts
30892
+ // src/agent_lattice/agentReviewerConfig.ts
30887
30893
  var import_protocols21 = require("@axiom-lattice/protocols");
30888
30894
 
30895
+ // src/agent_lattice/agentReviewerPrompt.ts
30896
+ var AGENT_REVIEWER_PROMPT = `# Agent Reviewer
30897
+
30898
+ You are an **Agent Reviewer** \u2014 a quality assurance specialist for AI agents. Your job is to review agent configurations for correctness and test them by invoking them with realistic messages.
30899
+
30900
+ ## Your Tools
30901
+
30902
+ - **get_agent** \u2014 Fetch an agent's full configuration
30903
+ - **list_agents** \u2014 List all agents in the workspace
30904
+ - **list_tools** \u2014 List all available tools that can be assigned to agents
30905
+ - **invoke_agent** \u2014 Test an agent by sending a message and getting its response. This spawns a completely fresh agent context \u2014 clean, isolated, and realistic.
30906
+
30907
+ ## Your Workflow
30908
+
30909
+ ### When asked to review an agent:
30910
+
30911
+ 1. Call **get_agent** to fetch the agent's config
30912
+ 2. Review the configuration for:
30913
+ - **Completeness** \u2014 Are name, description, prompt present? Is the prompt clear and actionable?
30914
+ - **Tool validity** \u2014 Do the referenced tools exist? Call **list_tools** to verify.
30915
+ - **Middleware correctness** \u2014 Is every middleware entry complete (id, type, name, description, enabled, config)?
30916
+ - **Sub-agent references** \u2014 Do referenced sub-agent IDs exist? Call **list_agents** to verify.
30917
+ - **Type consistency** \u2014 Does the agent type match its configuration shape? (e.g., PROCESSING must have edges, DEEP_AGENT may have subAgents)
30918
+ 3. Report your findings clearly. For each issue, state:
30919
+ - Severity (ERROR / WARNING / INFO)
30920
+ - What the problem is
30921
+ - How to fix it
30922
+
30923
+ ### When asked to test an agent:
30924
+
30925
+ 1. Call **get_agent** to understand the agent's purpose and expected behavior
30926
+ 2. Craft a realistic test message that exercises the agent's core responsibility \u2014 what would a real user say?
30927
+ 3. Call **invoke_agent(id, message)** to send the test message
30928
+ 4. Analyze the response:
30929
+ - **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.
30930
+ - **Otherwise, result.messages contains the agent's output**: The agent completed without interruption. Check:
30931
+ - Did the agent understand the request?
30932
+ - Was the response relevant and accurate?
30933
+ - Did the agent use the right tools?
30934
+ - Were there any errors or unexpected behaviors?
30935
+ - **If result.error is present**: The invocation itself failed (agent not found, compilation error, etc.). Report the error clearly.
30936
+ 5. Report your findings with the agent's actual response
30937
+
30938
+ ### When results are wrong:
30939
+
30940
+ If the agent's response is incorrect or unexpected:
30941
+ 1. Point out specifically what went wrong
30942
+ 2. Suggest what might need to change in the prompt or middleware config
30943
+ 3. Offer to re-test after fixes are applied
30944
+
30945
+ ## Important Rules
30946
+
30947
+ - **Always use invoke_agent for testing.** This is the ONLY way to test \u2014 it spawns a fresh agent context isolated from all other conversations.
30948
+ - **Be specific in your feedback.** Say "the agent failed to call the sql tool because the middleware config is missing databaseKeys" not "the agent didn't work."
30949
+ - **One agent at a time.** Focus on one agent per review or test request. Don't try to review multiple agents simultaneously.
30950
+ - **Be concise but thorough.** Cover all the checks, but present findings clearly without fluff.
30951
+ `;
30952
+
30953
+ // src/agent_lattice/agentReviewerConfig.ts
30954
+ var AGENT_REVIEWER_KEY = "agent-reviewer";
30955
+ var agentReviewerConfig = {
30956
+ key: AGENT_REVIEWER_KEY,
30957
+ name: "Agent Reviewer",
30958
+ description: "Review and test AI agents. Use this agent to check agent configurations for correctness and to test agents by invoking them with realistic messages.",
30959
+ type: import_protocols21.AgentType.REACT,
30960
+ prompt: AGENT_REVIEWER_PROMPT,
30961
+ tools: [
30962
+ "invoke_agent",
30963
+ "get_agent",
30964
+ "list_agents",
30965
+ "list_tools"
30966
+ ],
30967
+ middleware: [
30968
+ {
30969
+ id: "widget",
30970
+ type: "widget",
30971
+ name: "Widget",
30972
+ description: "Render interactive HTML widgets and SVG diagrams",
30973
+ enabled: true,
30974
+ config: {}
30975
+ }
30976
+ ]
30977
+ };
30978
+
30979
+ // src/agent_lattice/roomCoordinatorConfig.ts
30980
+ var import_protocols22 = require("@axiom-lattice/protocols");
30981
+
30889
30982
  // src/agent_lattice/roomCoordinatorPrompt.ts
30890
30983
  var ROOM_COORDINATOR_PROMPT = `You are the Room Coordinator. CRITICAL FIRST ACTION: Before any response or other action, call the \`skill\` tool with skill_name: "room-coordination" to load room-coordination and follow it. Never announce the skill load. If it fails, retry once, then stop and explicitly report that the required room-coordination skill could not be loaded.`;
30891
30984
 
@@ -30895,7 +30988,7 @@ var roomCoordinatorConfig = {
30895
30988
  key: ROOM_COORDINATOR_KEY,
30896
30989
  name: "Room Coordinator",
30897
30990
  description: "Manages project room conversations: replies when no bot is mentioned, coordinates room members, and organizes project work.",
30898
- type: import_protocols21.AgentType.DEEP_AGENT,
30991
+ type: import_protocols22.AgentType.DEEP_AGENT,
30899
30992
  prompt: ROOM_COORDINATOR_PROMPT,
30900
30993
  tools: [],
30901
30994
  middleware: [
@@ -31530,17 +31623,6 @@ var getAgentClient = (tenantId2, key5, options) => agentLatticeManager.initializ
31530
31623
  var getAgentClientAsync = async (tenantId2, key5, options) => agentLatticeManager.initializeClientAsync(tenantId2, key5, options);
31531
31624
  var createAgentClientFromAgentLattice = async (agentLattice, options) => await agentLatticeManager.createAgentClientFromConfig(agentLattice, options);
31532
31625
 
31533
- // src/agent_lattice/taskCapability.ts
31534
- function agentHasManagedTaskCapability(config) {
31535
- const middleware = config?.middleware;
31536
- const taskMiddleware = Array.isArray(middleware) ? middleware.find((entry) => entry?.type === "task" && entry?.enabled === true) : void 0;
31537
- if (!taskMiddleware) {
31538
- return false;
31539
- }
31540
- const allowedTools = taskMiddleware.allowedTools;
31541
- return allowedTools === void 0 || Array.isArray(allowedTools) && (allowedTools.length === 0 || allowedTools.includes("manage_task"));
31542
- }
31543
-
31544
31626
  // src/index.ts
31545
31627
  init_memory_lattice();
31546
31628
 
@@ -31639,7 +31721,7 @@ var getVectorStoreClient = (key5) => vectorStoreLatticeManager.getVectorStoreCli
31639
31721
 
31640
31722
  // src/logger_lattice/LoggerLatticeManager.ts
31641
31723
  init_BaseLatticeManager();
31642
- var import_protocols22 = require("@axiom-lattice/protocols");
31724
+ var import_protocols23 = require("@axiom-lattice/protocols");
31643
31725
 
31644
31726
  // src/logger_lattice/PinoLoggerClient.ts
31645
31727
  var import_pino = __toESM(require("pino"));
@@ -31861,11 +31943,11 @@ var LoggerLatticeManager = class _LoggerLatticeManager extends BaseLatticeManage
31861
31943
  if (client) {
31862
31944
  loggerClient = client;
31863
31945
  } else {
31864
- if (config.type === import_protocols22.LoggerType.PINO) {
31946
+ if (config.type === import_protocols23.LoggerType.PINO) {
31865
31947
  loggerClient = new PinoLoggerClient(config);
31866
- } else if (config.type === import_protocols22.LoggerType.CONSOLE) {
31948
+ } else if (config.type === import_protocols23.LoggerType.CONSOLE) {
31867
31949
  loggerClient = new ConsoleLoggerClient(config);
31868
- } else if (config.type === import_protocols22.LoggerType.CUSTOM) {
31950
+ } else if (config.type === import_protocols23.LoggerType.CUSTOM) {
31869
31951
  throw new Error(
31870
31952
  `Custom logger client must be provided. Please pass the client to registerLattice.`
31871
31953
  );
@@ -32945,15 +33027,15 @@ var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
32945
33027
  const metaByName = new Map(metaList.map((m) => [m.name, m.meta]));
32946
33028
  this.unregisterServerTools(tenantId2, serverKey);
32947
33029
  const keys = [];
32948
- for (const tool71 of tools) {
32949
- if (rt.selectedTools && !rt.selectedTools.includes(tool71.name)) continue;
32950
- const meta = metaByName.get(tool71.name);
33030
+ for (const tool68 of tools) {
33031
+ if (rt.selectedTools && !rt.selectedTools.includes(tool68.name)) continue;
33032
+ const meta = metaByName.get(tool68.name);
32951
33033
  const rawVisibility = meta?.ui?.visibility;
32952
33034
  const visibility = Array.isArray(rawVisibility) ? rawVisibility : typeof rawVisibility === "string" ? [rawVisibility] : void 0;
32953
33035
  if (visibility && !visibility.includes("model")) continue;
32954
33036
  const ref = extractAppsRef(meta, serverKey);
32955
- const registered = ref ? wrapMcpToolWithUi(tool71, ref) : tool71;
32956
- const toolKey = _McpLatticeManager.buildToolKey(serverKey, tool71.name);
33037
+ const registered = ref ? wrapMcpToolWithUi(tool68, ref) : tool68;
33038
+ const toolKey = _McpLatticeManager.buildToolKey(serverKey, tool68.name);
32957
33039
  try {
32958
33040
  toolLatticeManager.registerExistingToolWithTenant(tenantId2, toolKey, registered);
32959
33041
  keys.push(toolKey);
@@ -36127,7 +36209,7 @@ var LatticeEvalSuite = class {
36127
36209
  };
36128
36210
 
36129
36211
  // src/eval_lattice/LatticeEvalProject.ts
36130
- var import_protocols23 = require("@axiom-lattice/protocols");
36212
+ var import_protocols24 = require("@axiom-lattice/protocols");
36131
36213
  var import_messages8 = require("@langchain/core/messages");
36132
36214
  var import_uuid11 = require("uuid");
36133
36215
  var DEFAULT_CALIBRATION_PROBES = [
@@ -36183,7 +36265,7 @@ var LatticeEvalProject = class {
36183
36265
  key: this.judgeAgentKey,
36184
36266
  name: `Judge agent for ${this.project.projectName}`,
36185
36267
  description: "Judge agent for evaluating Lattice test cases",
36186
- type: import_protocols23.AgentType.REACT,
36268
+ type: import_protocols24.AgentType.REACT,
36187
36269
  prompt: "",
36188
36270
  modelKey: judgeModelKey
36189
36271
  };
@@ -36409,7 +36491,7 @@ function getMenuRegistry() {
36409
36491
  }
36410
36492
 
36411
36493
  // src/services/ProjectTaskReassignmentAuthorization.ts
36412
- var import_protocols24 = require("@axiom-lattice/protocols");
36494
+ var import_protocols25 = require("@axiom-lattice/protocols");
36413
36495
  var issued = /* @__PURE__ */ new WeakMap();
36414
36496
  function createProjectTaskReassignmentAuthorizer(policy, threadValidator) {
36415
36497
  return {
@@ -36442,7 +36524,7 @@ function inspectProjectTaskReassignmentAuthorization(authorization) {
36442
36524
  return snapshot ? { ...snapshot } : void 0;
36443
36525
  }
36444
36526
  function snapshotInput(input) {
36445
- const row = (0, import_protocols24.snapshotExactRecord)(input, [
36527
+ const row = (0, import_protocols25.snapshotExactRecord)(input, [
36446
36528
  "tenantId",
36447
36529
  "workspaceId",
36448
36530
  "projectId",
@@ -36485,7 +36567,7 @@ function snapshotInput(input) {
36485
36567
  }
36486
36568
 
36487
36569
  // src/services/TaskLifecycleNotifier.ts
36488
- var import_protocols25 = require("@axiom-lattice/protocols");
36570
+ var import_protocols26 = require("@axiom-lattice/protocols");
36489
36571
  var TaskLifecycleNotifier = class {
36490
36572
  constructor() {
36491
36573
  this.listeners = /* @__PURE__ */ new Set();
@@ -36529,7 +36611,7 @@ var TaskLifecycleNotifier = class {
36529
36611
  };
36530
36612
  var taskLifecycleNotifier = new TaskLifecycleNotifier();
36531
36613
  function snapshotNotification(value) {
36532
- const row = (0, import_protocols25.snapshotExactRecord)(value, [
36614
+ const row = (0, import_protocols26.snapshotExactRecord)(value, [
36533
36615
  "tenantId",
36534
36616
  "workspaceId",
36535
36617
  "projectId",
@@ -36561,7 +36643,7 @@ function nonempty(value) {
36561
36643
  }
36562
36644
 
36563
36645
  // src/services/ProjectTaskAdmissionNotifier.ts
36564
- var import_protocols26 = require("@axiom-lattice/protocols");
36646
+ var import_protocols27 = require("@axiom-lattice/protocols");
36565
36647
  var ProjectTaskAdmissionNotifier = class {
36566
36648
  /**
36567
36649
  * Creates a bounded Project task admission notifier.
@@ -36634,7 +36716,7 @@ var ProjectTaskAdmissionNotifier = class {
36634
36716
  };
36635
36717
  var projectTaskAdmissionNotifier = new ProjectTaskAdmissionNotifier();
36636
36718
  function snapshotNotification2(value) {
36637
- const row = (0, import_protocols26.snapshotExactRecord)(value, [
36719
+ const row = (0, import_protocols27.snapshotExactRecord)(value, [
36638
36720
  "tenantId",
36639
36721
  "workspaceId",
36640
36722
  "projectId",
@@ -36664,9 +36746,9 @@ function canonicalTimestamp(value) {
36664
36746
  }
36665
36747
 
36666
36748
  // src/services/ProjectMutationMutex.ts
36667
- var import_protocols27 = require("@axiom-lattice/protocols");
36749
+ var import_protocols28 = require("@axiom-lattice/protocols");
36668
36750
  function projectKey(scope) {
36669
- const row = (0, import_protocols27.snapshotExactRecord)(scope, ["tenantId", "projectId"]);
36751
+ const row = (0, import_protocols28.snapshotExactRecord)(scope, ["tenantId", "projectId"]);
36670
36752
  if (!row || typeof row.tenantId !== "string" || !row.tenantId || row.tenantId.includes("\0") || typeof row.projectId !== "string" || !row.projectId || row.projectId.includes("\0")) {
36671
36753
  throw new Error("Invalid Project mutation scope");
36672
36754
  }
@@ -36741,7 +36823,7 @@ function createTrustedAgentMessageDispatcher(resolve4) {
36741
36823
 
36742
36824
  // src/services/RoomAgentMessageService.ts
36743
36825
  var import_crypto8 = require("crypto");
36744
- var import_protocols28 = require("@axiom-lattice/protocols");
36826
+ var import_protocols29 = require("@axiom-lattice/protocols");
36745
36827
  var INPUT_KEYS = [
36746
36828
  "tenantId",
36747
36829
  "workspaceId",
@@ -36861,7 +36943,7 @@ var RoomAgentMessageService = class {
36861
36943
  function exactValues(value, required, optional = []) {
36862
36944
  try {
36863
36945
  if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
36864
- return (0, import_protocols28.snapshotExactRecord)(value, required, optional);
36946
+ return (0, import_protocols29.snapshotExactRecord)(value, required, optional);
36865
36947
  } catch {
36866
36948
  return void 0;
36867
36949
  }
@@ -36913,7 +36995,7 @@ function sourceOriginMatches(author, source) {
36913
36995
  return false;
36914
36996
  }
36915
36997
  function snapshotMentions(value) {
36916
- const rows = (0, import_protocols28.snapshotExactArray)(value);
36998
+ const rows = (0, import_protocols29.snapshotExactArray)(value);
36917
36999
  if (!rows) return void 0;
36918
37000
  const mentions = [];
36919
37001
  for (const row of rows) {
@@ -36941,7 +37023,7 @@ function snapshotCanonical(value, expected) {
36941
37023
  const author = exactValues(values?.author, ["type", "membershipId", "assistantId"]);
36942
37024
  const content = exactValues(values?.content, ["type", "text"]);
36943
37025
  const createdAt = date(values?.createdAt);
36944
- if (!values || !createdAt || typeof values.id !== "string" || values.id.length === 0 || (0, import_protocols28.snapshotExactArray)(values.mentions)?.length !== 0 || author?.type !== "bot" || expected.author.type !== "bot" || author.membershipId !== expected.author.membershipId || author.assistantId !== expected.author.assistantId || content?.type !== "text" || content.text !== expected.content.text || values.tenantId !== expected.tenantId || values.workspaceId !== expected.workspaceId || values.projectId !== expected.projectId || values.roomId !== expected.roomId || values.replyToMessageId !== expected.replyToMessageId || values.source !== "agent" || values.sourceId !== expected.sourceId || values.idempotencyKey !== expected.idempotencyKey) return void 0;
37026
+ if (!values || !createdAt || typeof values.id !== "string" || values.id.length === 0 || (0, import_protocols29.snapshotExactArray)(values.mentions)?.length !== 0 || author?.type !== "bot" || expected.author.type !== "bot" || author.membershipId !== expected.author.membershipId || author.assistantId !== expected.author.assistantId || content?.type !== "text" || content.text !== expected.content.text || values.tenantId !== expected.tenantId || values.workspaceId !== expected.workspaceId || values.projectId !== expected.projectId || values.roomId !== expected.roomId || values.replyToMessageId !== expected.replyToMessageId || values.source !== "agent" || values.sourceId !== expected.sourceId || values.idempotencyKey !== expected.idempotencyKey) return void 0;
36945
37027
  return {
36946
37028
  id: values.id,
36947
37029
  tenantId: expected.tenantId,
@@ -36960,7 +37042,7 @@ function snapshotCanonical(value, expected) {
36960
37042
  }
36961
37043
 
36962
37044
  // src/services/ProjectTaskOwnerPolicy.ts
36963
- var import_protocols29 = require("@axiom-lattice/protocols");
37045
+ var import_protocols30 = require("@axiom-lattice/protocols");
36964
37046
  var MEMBERSHIP_REQUIRED_KEYS = [
36965
37047
  "id",
36966
37048
  "tenantId",
@@ -37069,7 +37151,7 @@ function sameRosterScope(membership, scope) {
37069
37151
  return membership.tenantId === scope.tenantId && membership.workspaceId === scope.workspaceId && membership.projectId === scope.projectId && membership.roomId === scope.roomId;
37070
37152
  }
37071
37153
  function snapshotScope(value, keys) {
37072
- const values = (0, import_protocols29.snapshotExactRecord)(value, keys);
37154
+ const values = (0, import_protocols30.snapshotExactRecord)(value, keys);
37073
37155
  if (!values || keys.some((key5) => !isNonemptyString(values[key5]))) return void 0;
37074
37156
  return values;
37075
37157
  }
@@ -37081,7 +37163,7 @@ function projectScope(scope, keys) {
37081
37163
  function snapshotMembership2(value) {
37082
37164
  try {
37083
37165
  if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
37084
- const values = (0, import_protocols29.snapshotExactRecord)(value, MEMBERSHIP_REQUIRED_KEYS, ["responsibility"]);
37166
+ const values = (0, import_protocols30.snapshotExactRecord)(value, MEMBERSHIP_REQUIRED_KEYS, ["responsibility"]);
37085
37167
  if (!values) return void 0;
37086
37168
  const joinedAt = snapshotDate(values.joinedAt);
37087
37169
  const updatedAt = snapshotDate(values.updatedAt);
@@ -37120,7 +37202,7 @@ function snapshotDate(value) {
37120
37202
 
37121
37203
  // src/services/TaskLifecycleService.ts
37122
37204
  var import_node_crypto8 = require("crypto");
37123
- var import_protocols30 = require("@axiom-lattice/protocols");
37205
+ var import_protocols31 = require("@axiom-lattice/protocols");
37124
37206
 
37125
37207
  // src/middlewares/taskBelief.ts
37126
37208
  var import_node_crypto7 = require("crypto");
@@ -37191,7 +37273,7 @@ async function applyBeliefImpacts(taskStore, owner, impacts) {
37191
37273
  if (impacts.length === 0) return { description: owner.description ?? "" };
37192
37274
  let current = owner;
37193
37275
  for (let attempt = 0; attempt < BELIEF_OWNER_WRITE_ATTEMPTS; attempt += 1) {
37194
- const parsed = (0, import_protocols30.parseTaskBeliefState)(current.description ?? "");
37276
+ const parsed = (0, import_protocols31.parseTaskBeliefState)(current.description ?? "");
37195
37277
  const existingTable = parsed.success;
37196
37278
  if (!existingTable && parsed.code !== "MISSING_BELIEF_STATE") {
37197
37279
  return { description: current.description ?? "", task: current };
@@ -37208,7 +37290,7 @@ async function applyBeliefImpacts(taskStore, owner, impacts) {
37208
37290
  changed = true;
37209
37291
  }
37210
37292
  if (!changed) return { description: current.description ?? "", task: current };
37211
- const description = (0, import_protocols30.replaceTaskBeliefState)(current.description ?? "", { entries });
37293
+ const description = (0, import_protocols31.replaceTaskBeliefState)(current.description ?? "", { entries });
37212
37294
  try {
37213
37295
  const updated = await taskStore.updateIfStatusAndUpdatedAt(
37214
37296
  current.tenantId,
@@ -37233,8 +37315,8 @@ async function applyBeliefImpacts(taskStore, owner, impacts) {
37233
37315
  return { description: current.description ?? "", task: current };
37234
37316
  }
37235
37317
  function parseExternalDependency(value) {
37236
- const row = (0, import_protocols30.snapshotExactRecord)(value, ["type", "summary", "requestedAt", "dependencyTaskIds"]);
37237
- const ids = (0, import_protocols30.snapshotExactArray)(row?.dependencyTaskIds);
37318
+ const row = (0, import_protocols31.snapshotExactRecord)(value, ["type", "summary", "requestedAt", "dependencyTaskIds"]);
37319
+ const ids = (0, import_protocols31.snapshotExactArray)(row?.dependencyTaskIds);
37238
37320
  if (!row || row.type !== "external_dependency" || typeof row.summary !== "string" || !row.summary.trim() || typeof row.requestedAt !== "string" || !Number.isFinite(Date.parse(row.requestedAt)) || !ids || ids.length === 0 || ids.some((id) => typeof id !== "string" || !id.trim())) return void 0;
37239
37321
  const trimmed = ids.map((id) => id.trim());
37240
37322
  if (new Set(trimmed).size !== trimmed.length) return void 0;
@@ -37321,7 +37403,7 @@ function beliefStateOf(value) {
37321
37403
  function sameBeliefOwner(left, right) {
37322
37404
  const leftIdentity = { ...left, beliefState: void 0 };
37323
37405
  const rightIdentity = { ...right, beliefState: void 0 };
37324
- return canonicalJson(leftIdentity) === canonicalJson(rightIdentity) && (0, import_protocols30.taskBeliefStatesEqual)(left.beliefState, right.beliefState);
37406
+ return canonicalJson(leftIdentity) === canonicalJson(rightIdentity) && (0, import_protocols31.taskBeliefStatesEqual)(left.beliefState, right.beliefState);
37325
37407
  }
37326
37408
  function sameBeliefOwnerIdentity(left, right) {
37327
37409
  return canonicalJson({ ...left, beliefState: void 0 }) === canonicalJson({ ...right, beliefState: void 0 });
@@ -37469,7 +37551,7 @@ function changedBeliefKeys(left, right) {
37469
37551
  return [...keys].filter((key5) => {
37470
37552
  const oldEntry = leftByKey.get(key5);
37471
37553
  const newEntry = rightByKey.get(key5);
37472
- return !oldEntry || !newEntry || !(0, import_protocols30.taskBeliefStatesEqual)(
37554
+ return !oldEntry || !newEntry || !(0, import_protocols31.taskBeliefStatesEqual)(
37473
37555
  { entries: [oldEntry] },
37474
37556
  { entries: [newEntry] }
37475
37557
  );
@@ -38490,10 +38572,10 @@ var TaskLifecycleService = class {
38490
38572
  const description = preserveTargetContract(existing.description ?? "", input.description);
38491
38573
  const pending = existing.context?.belief_reconciliation_audit;
38492
38574
  const pendingAudit = pending && typeof pending === "object" ? pending : void 0;
38493
- const oldBelief = (0, import_protocols30.parseTaskBeliefState)(existing.description ?? "");
38494
- const newBelief = (0, import_protocols30.parseTaskBeliefState)(description);
38575
+ const oldBelief = (0, import_protocols31.parseTaskBeliefState)(existing.description ?? "");
38576
+ const newBelief = (0, import_protocols31.parseTaskBeliefState)(description);
38495
38577
  if (!newBelief.success) return failure2("INVALID_BELIEF_TABLE", newBelief.message);
38496
- if (!pendingAudit && description === (existing.description ?? "") && oldBelief.success && (0, import_protocols30.taskBeliefStatesEqual)(oldBelief.state, newBelief.state)) {
38578
+ if (!pendingAudit && description === (existing.description ?? "") && oldBelief.success && (0, import_protocols31.taskBeliefStatesEqual)(oldBelief.state, newBelief.state)) {
38497
38579
  return { success: true, task: existing, mutated: false };
38498
38580
  }
38499
38581
  const canonicalNew = newBelief.state.entries;
@@ -38624,7 +38706,7 @@ var TaskLifecycleService = class {
38624
38706
  }
38625
38707
  beliefOwnerSnapshot(task, parent) {
38626
38708
  const owner = parent?.ownerType === "agent" ? parent : task;
38627
- const parsed = (0, import_protocols30.parseTaskBeliefState)(owner.description ?? "");
38709
+ const parsed = (0, import_protocols31.parseTaskBeliefState)(owner.description ?? "");
38628
38710
  const beliefState = parsed.success ? parsed.state : { entries: [] };
38629
38711
  if (parent?.ownerType === "agent") {
38630
38712
  return {
@@ -39396,7 +39478,7 @@ function createTaskLifecycleService(deps) {
39396
39478
  // src/services/TaskExecutionService.ts
39397
39479
  var import_node_crypto9 = require("crypto");
39398
39480
  var import_node_util3 = require("util");
39399
- var import_protocols31 = require("@axiom-lattice/protocols");
39481
+ var import_protocols32 = require("@axiom-lattice/protocols");
39400
39482
 
39401
39483
  // src/services/taskErrorMessage.ts
39402
39484
  var MAX_EXECUTION_ERROR_MESSAGE_LENGTH = 1024;
@@ -39538,6 +39620,33 @@ function createTaskRunBridge(deps) {
39538
39620
  transitioned: true
39539
39621
  };
39540
39622
  }
39623
+ if (task.status === "interrupted" || task.status === "failed") {
39624
+ if (task.ownerType !== "agent") {
39625
+ return {
39626
+ success: false,
39627
+ code: "AGENT_TASK_REQUIRED",
39628
+ error: "Lifecycle transitions only support agent tasks."
39629
+ };
39630
+ }
39631
+ const result = task.status === "interrupted" ? await deps.lifecycle.resumeInterruption({ tenantId: tenantId2, taskId: task.id, actor, threadId }) : await deps.lifecycle.retryTask({ tenantId: tenantId2, taskId: task.id, actor, threadId });
39632
+ if (!result.success) {
39633
+ return {
39634
+ success: false,
39635
+ code: result.code,
39636
+ error: result.error,
39637
+ ...result.hint !== void 0 ? { hint: result.hint } : {},
39638
+ ...result.retryable !== void 0 ? { retryable: result.retryable } : {},
39639
+ ...result.warnings !== void 0 ? { warnings: result.warnings } : {}
39640
+ };
39641
+ }
39642
+ return {
39643
+ success: true,
39644
+ task: result.task,
39645
+ warnings: result.warnings ?? [],
39646
+ mutated: true,
39647
+ transitioned: true
39648
+ };
39649
+ }
39541
39650
  return { success: true, task, warnings, mutated: false, transitioned: false };
39542
39651
  },
39543
39652
  async settleRun(input) {
@@ -39691,48 +39800,18 @@ async function prepareTaskDispatch(deps, input) {
39691
39800
  }
39692
39801
  };
39693
39802
  }
39694
- if (task.status !== "pending") {
39803
+ if (task.status !== "pending" && task.status !== "interrupted" && task.status !== "failed") {
39695
39804
  return {
39696
39805
  kind: "failure",
39697
39806
  failure: {
39698
39807
  success: false,
39699
39808
  code: "TASK_NOT_DISPATCHABLE",
39700
- error: "Only a `pending` task can be dispatched.",
39701
- hint: `This task is '${task.status}'. Only a \`pending\` task dispatches: resolve it (resume an interruption / cancel a stuck run) or create a new task.`,
39809
+ error: "Only a `pending`, `interrupted`, or `failed` task can be dispatched.",
39810
+ hint: `This task is '${task.status}'. A \`pending\` task starts, an \`interrupted\` task resumes, and a \`failed\` task retries. A task already \`in_progress\` is held by a live run; terminal tasks cannot be dispatched.`,
39702
39811
  taskId: task.id
39703
39812
  }
39704
39813
  };
39705
39814
  }
39706
- if (deps.resolveTaskCapability) {
39707
- let targetCapable;
39708
- try {
39709
- targetCapable = await deps.resolveTaskCapability(input.tenantId, input.agentId);
39710
- } catch (error) {
39711
- return {
39712
- kind: "failure",
39713
- failure: {
39714
- success: false,
39715
- code: "AGENT_RESOLUTION_FAILED",
39716
- error: errorMessage(error),
39717
- taskId: task.id,
39718
- agentId: input.agentId
39719
- }
39720
- };
39721
- }
39722
- if (!targetCapable) {
39723
- return {
39724
- kind: "failure",
39725
- failure: {
39726
- success: false,
39727
- code: "TASK_DELEGATE_TARGET_NOT_CAPABLE",
39728
- taskId: task.id,
39729
- agentId: input.agentId,
39730
- error: `Agent '${input.agentId}' cannot manage tasks, so a dispatched TaskItem could never be completed.`,
39731
- hint: "Delegate to an agent with the `task` middleware (exposes `manage_task`), or do the work inline and update the task with `manage_task set_status`."
39732
- }
39733
- };
39734
- }
39735
- }
39736
39815
  const managedAuthority = executionAuthorityRegistry.resolve(task);
39737
39816
  if (managedAuthority) {
39738
39817
  if (managedAuthority.onManagedStart) {
@@ -40144,6 +40223,7 @@ function toJsonSafeValue(value) {
40144
40223
  }
40145
40224
 
40146
40225
  // src/services/TaskExecutionService.ts
40226
+ var import_langgraph14 = require("@langchain/langgraph");
40147
40227
  function persistedExecutionObservation(item, attempted) {
40148
40228
  const detail = item.detail;
40149
40229
  const persistedObservation = toJsonSafeValue(detail?.observation);
@@ -40190,9 +40270,10 @@ function createTaskExecutionService(deps) {
40190
40270
  const run = async (plan) => {
40191
40271
  const { tenantId: tenantId2, agentId, actor, parent, completedDependencies } = plan;
40192
40272
  let task = plan.task;
40273
+ const persistedThreadId = (task.status === "interrupted" || task.status === "failed") && typeof task.context?.thread_id === "string" && task.context.thread_id.trim() !== "" ? task.context.thread_id : void 0;
40193
40274
  let threadId;
40194
40275
  try {
40195
- threadId = (deps.createThreadId ?? import_node_crypto9.randomUUID)();
40276
+ threadId = persistedThreadId ?? (deps.createThreadId ?? import_node_crypto9.randomUUID)();
40196
40277
  } catch (error) {
40197
40278
  return {
40198
40279
  success: false,
@@ -40203,7 +40284,7 @@ function createTaskExecutionService(deps) {
40203
40284
  };
40204
40285
  }
40205
40286
  const eventKey = `execution-result:${threadId}`;
40206
- if (!(0, import_protocols31.isExecutionResultEventKey)(eventKey)) {
40287
+ if (!(0, import_protocols32.isExecutionResultEventKey)(eventKey)) {
40207
40288
  return {
40208
40289
  success: false,
40209
40290
  code: "INVALID_EXECUTION_RESULT_ID",
@@ -40231,12 +40312,12 @@ function createTaskExecutionService(deps) {
40231
40312
  task = transfer.task;
40232
40313
  }
40233
40314
  const warnings = [];
40234
- if (task.status === "pending") {
40315
+ if (task.status === "pending" || task.status === "interrupted" || task.status === "failed") {
40235
40316
  const begun = await bridge.beginRun({
40236
40317
  tenantId: tenantId2,
40237
40318
  task,
40238
40319
  actor,
40239
- threadId: plan.callerThreadId
40320
+ threadId
40240
40321
  });
40241
40322
  if (!begun.success) return { ...begun, taskId: task.id };
40242
40323
  if (!begun.mutated || !begun.transitioned) {
@@ -40265,6 +40346,19 @@ function createTaskExecutionService(deps) {
40265
40346
  try {
40266
40347
  observation = toJsonSafeValue(await deps.invokeAgent(invocation));
40267
40348
  } catch (error) {
40349
+ if (error instanceof import_langgraph14.GraphInterrupt) {
40350
+ try {
40351
+ await bridge.settleRun({
40352
+ tenantId: tenantId2,
40353
+ task,
40354
+ actor,
40355
+ threadId,
40356
+ outcome: { kind: "interrupted", summary: "Awaiting user input" }
40357
+ });
40358
+ } catch {
40359
+ }
40360
+ throw error;
40361
+ }
40268
40362
  const normalizationError = error instanceof JsonSafeValueError;
40269
40363
  const message = normalizationError ? `${error.code}: ${error.message}` : errorMessage(error);
40270
40364
  const failureCode = normalizationError ? "EXECUTION_RESULT_NORMALIZATION_FAILED" : "AGENT_INVOCATION_FAILED";
@@ -40395,6 +40489,76 @@ function createTaskExecutionService(deps) {
40395
40489
  };
40396
40490
  }
40397
40491
 
40492
+ // src/services/TaskRunRegistry.ts
40493
+ var TaskRunRegistry = class {
40494
+ constructor() {
40495
+ this.live = /* @__PURE__ */ new Set();
40496
+ }
40497
+ /** Marks a task as currently held by a live run. */
40498
+ register(taskId) {
40499
+ this.live.add(taskId);
40500
+ }
40501
+ /** Removes a task once its run has ended. */
40502
+ unregister(taskId) {
40503
+ this.live.delete(taskId);
40504
+ }
40505
+ /** Reports whether a task is currently held by a live run. */
40506
+ isLive(taskId) {
40507
+ return this.live.has(taskId);
40508
+ }
40509
+ /** Returns a snapshot of the live task ids (diagnostics/tests). */
40510
+ snapshot() {
40511
+ return [...this.live];
40512
+ }
40513
+ /** Clears all live entries (tests / process teardown). */
40514
+ clear() {
40515
+ this.live.clear();
40516
+ }
40517
+ };
40518
+ var taskRunRegistry = new TaskRunRegistry();
40519
+ async function reconcileStaleTaskRuns(input) {
40520
+ const registry4 = input.registry ?? taskRunRegistry;
40521
+ const converged = [];
40522
+ for (const task of input.tasks) {
40523
+ if (task.status !== "in_progress" || registry4.isLive(task.id)) continue;
40524
+ const result = await input.lifecycle.interruptTask({
40525
+ tenantId: task.tenantId,
40526
+ taskId: task.id,
40527
+ actor: input.actor,
40528
+ type: "missing_input",
40529
+ summary: "Run is no longer executing this task (no_executor)"
40530
+ });
40531
+ if (result.success) converged.push(task.id);
40532
+ }
40533
+ return { converged };
40534
+ }
40535
+ async function reconcileTenantTaskRuns(input) {
40536
+ const tasks = await input.taskStore.list({ tenantId: input.tenantId, status: "in_progress" });
40537
+ const candidates = input.include ? tasks.filter(input.include) : tasks;
40538
+ return reconcileStaleTaskRuns({
40539
+ tasks: candidates,
40540
+ actor: input.actor,
40541
+ lifecycle: input.lifecycle,
40542
+ ...input.registry ? { registry: input.registry } : {}
40543
+ });
40544
+ }
40545
+ async function reconcileAllTenantTaskRuns(input) {
40546
+ const tenants = await input.tenantStore.listTenants();
40547
+ const converged = [];
40548
+ for (const tenant of tenants) {
40549
+ const result = await reconcileTenantTaskRuns({
40550
+ tenantId: tenant.id,
40551
+ actor: input.actor,
40552
+ taskStore: input.taskStore,
40553
+ lifecycle: input.lifecycle,
40554
+ ...input.registry ? { registry: input.registry } : {},
40555
+ ...input.include ? { include: input.include } : {}
40556
+ });
40557
+ converged.push(...result.converged);
40558
+ }
40559
+ return { converged };
40560
+ }
40561
+
40398
40562
  // src/index.ts
40399
40563
  var Protocols = __toESM(require("@axiom-lattice/protocols"));
40400
40564
 
@@ -40660,10 +40824,10 @@ var createLoadSkillContentTool = (pluginSkills, pluginSkillOwnersOrStaticSelecti
40660
40824
  lockIdentity
40661
40825
  );
40662
40826
  let result2 = pluginSkill.definition.content;
40663
- const resources3 = Object.entries(pluginSkill.definition.resources ?? {});
40664
- if (resources3.length > 0) {
40827
+ const resources2 = Object.entries(pluginSkill.definition.resources ?? {});
40828
+ if (resources2.length > 0) {
40665
40829
  result2 += "\n\n---\n\n**Resources** (synced to the sandbox; use `read_file` to access):\n";
40666
- for (const [resourcePath, resource] of resources3) {
40830
+ for (const [resourcePath, resource] of resources2) {
40667
40831
  result2 += `- ${resourcePath} (mime type: ${resource.mimeType ?? "not specified"})
40668
40832
  `;
40669
40833
  }
@@ -40690,10 +40854,10 @@ var createLoadSkillContentTool = (pluginSkills, pluginSkillOwnersOrStaticSelecti
40690
40854
  `/root/.agents/skills/${input.skill_name}/resources`,
40691
40855
  { recursive: false }
40692
40856
  );
40693
- const resources3 = resourcesResult.files.map((f) => f.path.split("/").pop()).filter(Boolean);
40694
- if (resources3.length > 0) {
40857
+ const resources2 = resourcesResult.files.map((f) => f.path.split("/").pop()).filter(Boolean);
40858
+ if (resources2.length > 0) {
40695
40859
  result += "\n\n---\n\n**Resources** (use `read_file` tool to access):\n";
40696
- resources3.forEach((r) => {
40860
+ resources2.forEach((r) => {
40697
40861
  result += `- ${r}
40698
40862
  `;
40699
40863
  });
@@ -41015,1367 +41179,12 @@ var skillPlugin = {
41015
41179
  })
41016
41180
  };
41017
41181
 
41018
- // src/middlewares/semanticMetricsMiddleware.ts
41019
- var import_langchain70 = require("langchain");
41020
-
41021
- // src/tool_lattice/semantic_metrics/metrics_datasource_tool.ts
41022
- var import_zod55 = __toESM(require("zod"));
41023
- var import_langchain67 = require("langchain");
41024
-
41025
- // src/tool_lattice/semantic_metrics/types.ts
41026
- function readToolRunConfig(exeConfig) {
41027
- return exeConfig?.configurable?.runConfig;
41028
- }
41029
- function resolveDatasourceId(input, exeConfig) {
41030
- const id = input.datasourceId ?? readToolRunConfig(exeConfig)?.metricsDataSource?.datasourceId;
41031
- if (id === void 0 || id === null || id === "") {
41032
- throw new Error("datasourceId is required (provide it or set runConfig.metricsDataSource.datasourceId)");
41033
- }
41034
- return Number(id);
41035
- }
41036
- function assertDatasourceSelected(scope, datasourceId) {
41037
- if (scope.unrestricted) return;
41038
- if (!scope.ids.includes(datasourceId)) {
41039
- throw new Error(
41040
- `DATASOURCE_NOT_SELECTED: datasource ${datasourceId} is not in the effective scope [${scope.ids.join(", ")}]`
41041
- );
41042
- }
41043
- }
41044
- function effectiveDatasourceScope(connectionScope) {
41045
- return connectionScope.length > 0 ? { unrestricted: false, ids: [...connectionScope] } : { unrestricted: true, ids: [] };
41046
- }
41047
- var DDL_DML_KEYWORDS = [
41048
- "insert",
41049
- "update",
41050
- "delete",
41051
- "drop",
41052
- "alter",
41053
- "create",
41054
- "truncate",
41055
- "grant",
41056
- "revoke",
41057
- "merge",
41058
- "replace",
41059
- "upsert"
41060
- ];
41061
- var DDL_DML_RE = new RegExp(`\\b(?:${DDL_DML_KEYWORDS.join("|")})\\b`, "i");
41062
- var SELECT_INTO_RE = /\bselect\b[\s\S]*?\binto\b/i;
41063
- function validateSql(sql) {
41064
- const trimmed = sql.trim();
41065
- if (!trimmed) {
41066
- return { ok: false, reason: "SQL is empty" };
41067
- }
41068
- const withoutComments = trimmed.replace(/--[^\n]*/g, " ").replace(/\/\*[\s\S]*?\*\//g, " ");
41069
- const statements = withoutComments.split(";").map((s) => s.trim()).filter(Boolean);
41070
- if (statements.length > 1) {
41071
- return { ok: false, reason: "Multiple statements are not allowed" };
41072
- }
41073
- const firstKeyword = withoutComments.trim().split(/\s+/)[0].toLowerCase();
41074
- if (firstKeyword !== "select" && firstKeyword !== "with") {
41075
- return { ok: false, reason: `Only SELECT or WITH queries are allowed (got "${firstKeyword}")` };
41076
- }
41077
- if (SELECT_INTO_RE.test(withoutComments)) {
41078
- return { ok: false, reason: "SELECT INTO is not allowed (creates a table)" };
41079
- }
41080
- if (DDL_DML_RE.test(withoutComments)) {
41081
- return { ok: false, reason: "Only read-only queries are allowed (DML/DDL detected)" };
41082
- }
41083
- return { ok: true };
41084
- }
41085
-
41086
- // src/tool_lattice/semantic_metrics/SemanticMetricsV2Client.ts
41087
- var NO_CONNECTION_HINT = "No semantic-metrics connection is configured for this tenant. Add a connection of type 'semantic-metrics' for the tenant, then select it (connections) or enable connectAll in the agent's middleware config.";
41088
- async function resolveMetricsClientFromSelector(selector, scope, connectionKey) {
41089
- let resolved;
41090
- try {
41091
- resolved = await resolvePluginConnections(selector.connectionType, selector, scope);
41092
- } catch (error) {
41093
- if (error instanceof Error && error.message === "ConnectionStore not configured") {
41094
- throw new Error(NO_CONNECTION_HINT);
41095
- }
41096
- throw error;
41097
- }
41098
- const available = resolved.map((c) => c.key).join(", ");
41099
- if (resolved.length === 0) {
41100
- throw new Error(NO_CONNECTION_HINT);
41101
- }
41102
- const key5 = connectionKey?.trim() || (resolved.length === 1 ? resolved[0].key : "");
41103
- if (!key5) {
41104
- throw new Error(
41105
- `connectionKey is required. Available connections: ${available}`
41106
- );
41107
- }
41108
- const entry = resolved.find((c) => c.key === key5);
41109
- if (!entry) {
41110
- throw new Error(`Connection "${key5}" not found. Available connections: ${available}`);
41111
- }
41112
- const config = entry.config;
41113
- return new SemanticMetricsV2Client(config);
41114
- }
41115
- var SemanticMetricsV2Client = class {
41116
- /**
41117
- * @param config - Connection configuration (server URL, optional API key and headers).
41118
- */
41119
- constructor(config) {
41120
- this.config = config;
41121
- this.baseUrl = config.serverUrl.replace(/\/$/, "");
41122
- }
41123
- /**
41124
- * Build default request headers: `Accept: application/json`, custom headers,
41125
- * and a Bearer `Authorization` header when an API key is configured.
41126
- *
41127
- * @returns Merged headers.
41128
- */
41129
- getHeaders() {
41130
- const headers = {
41131
- Accept: "application/json",
41132
- ...this.config.headers ?? {}
41133
- };
41134
- if (this.config.apiKey) {
41135
- headers["Authorization"] = `Bearer ${this.config.apiKey}`;
41136
- }
41137
- return headers;
41138
- }
41139
- /**
41140
- * Numeric selected resource ids of this connection (normalized).
41141
- *
41142
- * Reads `selectedEntities` — the standard connection resource-selection
41143
- * field written by the connection UI (`connection.discover` + selection).
41144
- *
41145
- * @returns The selected resource ids; empty when unrestricted.
41146
- */
41147
- getSelectedEntities() {
41148
- const raw = this.config.selectedEntities;
41149
- if (!Array.isArray(raw)) return [];
41150
- return raw.map((v) => Number(v)).filter((n) => Number.isFinite(n));
41151
- }
41152
- /**
41153
- * Perform a JSON request against the base URL.
41154
- *
41155
- * The Metrics Server wraps every response as `{ code, message, data }`. A
41156
- * `code` of 200 resolves to `data`; any other `code` throws a business error
41157
- * carrying the server message (regardless of HTTP status). Non-envelope
41158
- * bodies are returned as-is.
41159
- *
41160
- * @param path - Path appended to the base URL (must start with `/`).
41161
- * @param init - Optional `fetch` init overrides (method, body, per-call headers).
41162
- * @returns The unwrapped `data` payload of the response envelope.
41163
- * @throws When the server returns a non-200 `code`, or the HTTP response is not OK.
41164
- */
41165
- async request(path8, init = {}) {
41166
- const response = await fetch(`${this.baseUrl}${path8}`, {
41167
- ...init,
41168
- method: init.method ?? "GET",
41169
- headers: { ...this.getHeaders(), ...init.headers ?? {} }
41170
- });
41171
- const text = await response.text().catch(() => "");
41172
- const parsed = this.parseBody(text);
41173
- if (parsed?.envelope === true) {
41174
- if (parsed.code !== 200) {
41175
- throw new Error(`API ${parsed.code}: ${parsed.message || "Unknown error"}`);
41176
- }
41177
- return parsed.data;
41178
- }
41179
- if (!response.ok) {
41180
- throw new Error(`HTTP ${response.status}: ${text || response.statusText}`);
41181
- }
41182
- return parsed?.value ?? void 0;
41183
- }
41184
- /**
41185
- * Parse a response body text. Detects the server envelope `{ code, message, data }`.
41186
- *
41187
- * @param text - Raw response body text.
41188
- * @returns `{ envelope: true, code, message, data }` for an envelope body,
41189
- * `{ envelope: false, value }` for anything else (or `{ envelope: false }` when empty/invalid).
41190
- */
41191
- parseBody(text) {
41192
- if (!text.trim()) return { envelope: false };
41193
- try {
41194
- const value = JSON.parse(text);
41195
- if (value !== null && typeof value === "object" && !Array.isArray(value)) {
41196
- const record = value;
41197
- if (typeof record.code === "number") {
41198
- return {
41199
- envelope: true,
41200
- code: record.code,
41201
- message: typeof record.message === "string" ? record.message : void 0,
41202
- data: record.data
41203
- };
41204
- }
41205
- }
41206
- return { envelope: false, value };
41207
- } catch {
41208
- return { envelope: false, value: text };
41209
- }
41210
- }
41211
- /**
41212
- * POST a JSON body to a path.
41213
- *
41214
- * @param path - Path appended to the base URL.
41215
- * @param body - Payload serialized as JSON.
41216
- * @returns Parsed JSON response body.
41217
- */
41218
- post(path8, body) {
41219
- return this.request(path8, {
41220
- method: "POST",
41221
- headers: { "Content-Type": "application/json" },
41222
- body: JSON.stringify(body)
41223
- });
41224
- }
41225
- /**
41226
- * PUT a JSON body to a path.
41227
- *
41228
- * @param path - Path appended to the base URL.
41229
- * @param body - Payload serialized as JSON.
41230
- * @returns Parsed JSON response body.
41231
- */
41232
- put(path8, body) {
41233
- return this.request(path8, {
41234
- method: "PUT",
41235
- headers: { "Content-Type": "application/json" },
41236
- body: JSON.stringify(body)
41237
- });
41238
- }
41239
- /**
41240
- * List all datasources.
41241
- *
41242
- * @returns Parsed JSON response body.
41243
- */
41244
- listDatasources() {
41245
- return this.request("/datasources");
41246
- }
41247
- /**
41248
- * Get table grants for a datasource.
41249
- *
41250
- * @param datasourceId - Datasource identifier.
41251
- * @returns Parsed JSON response body.
41252
- */
41253
- getTableGrants(datasourceId) {
41254
- return this.request(`/datasources/${encodeURIComponent(datasourceId)}/table-grants`);
41255
- }
41256
- /**
41257
- * Run a read-only SQL query against a datasource.
41258
- *
41259
- * @param datasourceId - Datasource identifier.
41260
- * @param input - Query input: `sql` (SELECT/WITH only), optional `params`, `maxRows`, `debug`.
41261
- * @returns Parsed JSON response body.
41262
- * @throws When `sql` fails read-only validation (rejected before any fetch).
41263
- */
41264
- async queryDatasource(datasourceId, input) {
41265
- const validation = validateSql(input.sql);
41266
- if (!validation.ok) throw new Error(`SQL_NOT_ALLOWED: ${validation.reason}`);
41267
- return this.post(`/datasources/${encodeURIComponent(datasourceId)}/query`, input);
41268
- }
41269
- /**
41270
- * Test a datasource connection.
41271
- *
41272
- * @param datasourceId - Datasource identifier.
41273
- * @returns Parsed JSON response body.
41274
- */
41275
- testDatasource(datasourceId) {
41276
- return this.post(`/datasources/${encodeURIComponent(datasourceId)}/test`, {});
41277
- }
41278
- /**
41279
- * Get connection-pool status for a datasource.
41280
- *
41281
- * @param datasourceId - Datasource identifier.
41282
- * @returns Parsed JSON response body.
41283
- */
41284
- getPoolStatus(datasourceId) {
41285
- return this.request(`/datasources/${encodeURIComponent(datasourceId)}/pool`);
41286
- }
41287
- /**
41288
- * List table metadata for a datasource, auto-paginating.
41289
- *
41290
- * The server pages this collection (`page`/`pageSize`, default page size 20),
41291
- * so requests aggregate every page into one `{ items, total }` result.
41292
- *
41293
- * @param datasourceId - Datasource identifier.
41294
- * @returns `{ items: [...], total }` covering all pages.
41295
- */
41296
- async listTables(datasourceId) {
41297
- return this.listMetaPage(`/datasources/${encodeURIComponent(datasourceId)}/meta/tables`);
41298
- }
41299
- /**
41300
- * Shared pagination walk for the paged meta collections (`{items,total,page,pageSize}`).
41301
- *
41302
- * @param basePath - Collection path (tables or metrics).
41303
- * @returns `{ items, total }` aggregated across all pages.
41304
- */
41305
- async listMetaPage(basePath) {
41306
- const pageSize = 100;
41307
- const items = [];
41308
- let total = Number.POSITIVE_INFINITY;
41309
- for (let page = 1; items.length < total; page += 1) {
41310
- const body = await this.request(`${basePath}?page=${page}&pageSize=${pageSize}`);
41311
- const record = body !== null && typeof body === "object" ? body : {};
41312
- const batch = Array.isArray(record.items) ? record.items : [];
41313
- items.push(...batch);
41314
- total = typeof record.total === "number" ? record.total : items.length;
41315
- if (batch.length === 0) break;
41316
- }
41317
- return { items, total: items.length };
41318
- }
41319
- /**
41320
- * Get metadata for a single table.
41321
- *
41322
- * @param datasourceId - Datasource identifier.
41323
- * @param tableKey - Table key.
41324
- * @returns Parsed JSON response body.
41325
- */
41326
- getTable(datasourceId, tableKey) {
41327
- return this.request(
41328
- `/datasources/${encodeURIComponent(datasourceId)}/meta/tables/${encodeURIComponent(tableKey)}`
41329
- );
41330
- }
41331
- /**
41332
- * Create a table definition for a datasource.
41333
- *
41334
- * @param datasourceId - Datasource identifier.
41335
- * @param payload - Table definition payload.
41336
- * @returns Parsed JSON response body.
41337
- */
41338
- createTable(datasourceId, payload) {
41339
- return this.post(`/datasources/${encodeURIComponent(datasourceId)}/meta/tables`, payload);
41340
- }
41341
- /**
41342
- * Update a table definition for a datasource.
41343
- *
41344
- * @param datasourceId - Datasource identifier.
41345
- * @param tableKey - Table key.
41346
- * @param payload - Table definition payload.
41347
- * @returns Parsed JSON response body.
41348
- */
41349
- /**
41350
- * Update a published table meta via read-modify-write.
41351
- *
41352
- * The server's PUT replaces the whole payload, so the current payload is
41353
- * fetched first and the incoming fields are merged on top; fields not
41354
- * mentioned are preserved.
41355
- */
41356
- async updateTable(datasourceId, tableKey, payload) {
41357
- const existing = await this.readMetaPayload(`${this.baseUrl}/datasources/${encodeURIComponent(datasourceId)}/meta/tables/${encodeURIComponent(tableKey)}`);
41358
- return this.put(
41359
- `/datasources/${encodeURIComponent(datasourceId)}/meta/tables/${encodeURIComponent(tableKey)}`,
41360
- { payload: { ...existing, ...payload } }
41361
- );
41362
- }
41363
- /**
41364
- * List metric definitions for a datasource.
41365
- *
41366
- * @param datasourceId - Datasource identifier.
41367
- * @returns Parsed JSON response body.
41368
- */
41369
- /**
41370
- * List metric metadata for a datasource, auto-paginating.
41371
- *
41372
- * The server pages this collection (`page`/`pageSize`, default page size 20),
41373
- * so requests aggregate every page into one `{ items, total }` result.
41374
- *
41375
- * @param datasourceId - Datasource identifier.
41376
- * @returns `{ items: [...], total }` covering all pages.
41377
- */
41378
- async listMetrics(datasourceId) {
41379
- return this.listMetaPage(`/datasources/${encodeURIComponent(datasourceId)}/meta/metrics`);
41380
- }
41381
- /**
41382
- * Get a single metric definition.
41383
- *
41384
- * @param datasourceId - Datasource identifier.
41385
- * @param metricKey - Metric key.
41386
- * @returns Parsed JSON response body.
41387
- */
41388
- getMetric(datasourceId, metricKey) {
41389
- return this.request(
41390
- `/datasources/${encodeURIComponent(datasourceId)}/meta/metrics/${encodeURIComponent(metricKey)}`
41391
- );
41392
- }
41393
- /**
41394
- * Create a metric definition for a datasource.
41395
- *
41396
- * @param datasourceId - Datasource identifier.
41397
- * @param payload - Metric definition payload.
41398
- * @returns Parsed JSON response body.
41399
- */
41400
- createMetric(datasourceId, payload) {
41401
- return this.post(`/datasources/${encodeURIComponent(datasourceId)}/meta/metrics`, payload);
41402
- }
41403
- /**
41404
- * Update a metric definition for a datasource.
41405
- *
41406
- * @param datasourceId - Datasource identifier.
41407
- * @param metricKey - Metric key.
41408
- * @param payload - Metric definition payload.
41409
- * @returns Parsed JSON response body.
41410
- */
41411
- /**
41412
- * Update a published metric meta via read-modify-write.
41413
- *
41414
- * The server's PUT replaces the whole payload, so the current payload is
41415
- * fetched first and the incoming fields are merged on top; fields not
41416
- * mentioned are preserved.
41417
- */
41418
- async updateMetric(datasourceId, metricKey, payload) {
41419
- const existing = await this.readMetaPayload(`${this.baseUrl}/datasources/${encodeURIComponent(datasourceId)}/meta/metrics/${encodeURIComponent(metricKey)}`);
41420
- return this.put(
41421
- `/datasources/${encodeURIComponent(datasourceId)}/meta/metrics/${encodeURIComponent(metricKey)}`,
41422
- { payload: { ...existing, ...payload } }
41423
- );
41424
- }
41425
- /**
41426
- * Fetch the current `payload` object of a published meta entry.
41427
- *
41428
- * The single-entry read returns `{ code, data: [entry] }` (already unwrapped
41429
- * to the array by {@link request}); the payload lives on the first entry.
41430
- *
41431
- * @param absoluteUrl - Full URL of the single-entry meta read.
41432
- * @returns The stored payload object (empty when none exists).
41433
- */
41434
- async readMetaPayload(absoluteUrl) {
41435
- const response = await fetch(absoluteUrl, { headers: this.getHeaders() });
41436
- const text = await response.text().catch(() => "");
41437
- if (!response.ok) {
41438
- throw new Error(`HTTP ${response.status}: ${text || response.statusText}`);
41439
- }
41440
- const parsed = this.parseBody(text);
41441
- const data = parsed?.envelope === true ? parsed.data : parsed?.value;
41442
- const entry = Array.isArray(data) ? data[0] : data;
41443
- const payload = entry?.payload;
41444
- return payload !== null && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
41445
- }
41446
- /**
41447
- * Get runtime metadata for a datasource.
41448
- *
41449
- * @param datasourceId - Datasource identifier.
41450
- * @returns Parsed JSON response body.
41451
- */
41452
- getRuntimeMeta(datasourceId) {
41453
- return this.request(`/datasources/${encodeURIComponent(datasourceId)}/meta`);
41454
- }
41455
- /**
41456
- * Run a metrics query.
41457
- *
41458
- * @param request - Metrics query request payload.
41459
- * @returns Parsed JSON response body.
41460
- */
41461
- queryMetrics(request) {
41462
- return this.post("/metrics/query", request);
41463
- }
41464
- /**
41465
- * Run an ad-hoc custom SQL query, validated as read-only before sending.
41466
- *
41467
- * @param request - Request with `datasourceId`, `customSql` (SELECT/WITH only),
41468
- * and optional `limit` / `debug`.
41469
- * @returns Parsed JSON response body.
41470
- * @throws When `customSql` fails read-only validation (rejected before any fetch).
41471
- */
41472
- async customSql(request) {
41473
- const validation = validateSql(request.customSql);
41474
- if (!validation.ok) throw new Error(`SQL_NOT_ALLOWED: ${validation.reason}`);
41475
- return this.post("/metrics/query", request);
41476
- }
41477
- };
41478
-
41479
- // src/tool_lattice/semantic_metrics/metrics_datasource_tool.ts
41480
- var DESCRIPTION = `PHYSICAL LAYER EXPLORATION \u2014 the only tool for probing raw datasource structure (Builder/Admin only; business agents do not need it).
41481
-
41482
- OWNS: discovering datasources, reading table-grants (the exploration boundary for this tenant), and running read-only SQL (SELECT/WITH only) to inspect physical tables, columns, sample rows, and value distributions. Also: per-datasource connection test and pool status.
41483
-
41484
- DOES NOT OWN:
41485
- - Published semantic assets (table meta / metric meta) \u2192 use metrics_meta_tool.
41486
- - Runtime meta and business metric queries \u2192 use metrics_runtime_tool.
41487
-
41488
- USE WHEN: starting a modeling task \u2014 \`list_datasources\` is always the FIRST step: it returns the datasource ids that every other action and tool requires (get_grants, query_sql here; read_semantic_catalog, query_metrics in metrics_runtime_tool; the meta actions in metrics_meta_tool). Read grants next, then probe tables, columns, samples, and distributions within the grant. If a field's business meaning is unclear, probe sample values and distributions here before publishing anything.
41489
-
41490
- COMMON MISTAKES (do not):
41491
- - Do not answer business metric questions here (e.g. "monthly sales by region") \u2014 that is metrics_runtime_tool \`query\` against published metrics, NOT this tool's \`query_sql\` (physical-table SQL).
41492
- - Do not read or publish semantic meta through this tool \u2014 metrics_meta_tool owns the semantic layer.
41493
- - Do not probe tables outside the tenant's table-grants; un-granted probes are rejected and break the exploration boundary.
41494
- - Do not attempt writes \u2014 SQL is validated read-only and rejected before sending.`;
41495
- function createMetricsDatasourceTool(params) {
41496
- const { connectionType, connections, connectAll } = params;
41497
- return (0, import_langchain67.tool)(
41498
- async (input, exeConfig) => {
41499
- try {
41500
- const client = await resolveMetricsClientFromSelector(
41501
- { connectionType, connections, connectAll },
41502
- readToolRunConfig(exeConfig) ?? {},
41503
- input.connectionKey
41504
- );
41505
- const scope = effectiveDatasourceScope(client.getSelectedEntities());
41506
- switch (input.action) {
41507
- case "list_datasources": {
41508
- const result = await client.listDatasources();
41509
- const filtered = scope.unrestricted ? result : result.filter((d) => scope.ids.includes(Number(d.id)));
41510
- const safe = filtered.map((d) => ({
41511
- id: d.id,
41512
- name: d.name,
41513
- sourceType: d.sourceType,
41514
- description: d.description,
41515
- statusLabel: d.statusLabel
41516
- }));
41517
- return JSON.stringify(safe, null, 2);
41518
- }
41519
- case "get_grants": {
41520
- const ds = resolveDatasourceId(input, exeConfig);
41521
- assertDatasourceSelected(scope, ds);
41522
- const result = await client.getTableGrants(ds);
41523
- return JSON.stringify(result, null, 2);
41524
- }
41525
- case "query_sql": {
41526
- const ds = resolveDatasourceId(input, exeConfig);
41527
- assertDatasourceSelected(scope, ds);
41528
- if (!input.sql) throw new Error("sql is required for the 'query_sql' action");
41529
- const result = await client.queryDatasource(ds, {
41530
- sql: input.sql,
41531
- params: input.params,
41532
- maxRows: input.maxRows
41533
- });
41534
- return JSON.stringify(result, null, 2);
41535
- }
41536
- case "test_connection": {
41537
- const ds = resolveDatasourceId(input, exeConfig);
41538
- assertDatasourceSelected(scope, ds);
41539
- const result = await client.testDatasource(ds);
41540
- return JSON.stringify(result, null, 2);
41541
- }
41542
- case "pool_status": {
41543
- const ds = resolveDatasourceId(input, exeConfig);
41544
- assertDatasourceSelected(scope, ds);
41545
- const result = await client.getPoolStatus(ds);
41546
- return JSON.stringify(result, null, 2);
41547
- }
41548
- }
41549
- } catch (error) {
41550
- return `Error: ${error instanceof Error ? error.message : String(error)}`;
41551
- }
41552
- },
41553
- {
41554
- name: "metrics_datasource_tool",
41555
- description: DESCRIPTION,
41556
- schema: import_zod55.default.object({
41557
- action: import_zod55.default.enum(["list_datasources", "get_grants", "query_sql", "test_connection", "pool_status"]).describe(
41558
- "list_datasources: list datasources \u2014 ALWAYS call this first to obtain the datasource id used by every other action and tool; get_grants: read table-grants; query_sql: run read-only SQL against PHYSICAL tables (note: this is query_sql, NOT the semantic 'query' action of metrics_runtime_tool); test_connection: test the datasource; pool_status: connection-pool status"
41559
- ),
41560
- connectionKey: import_zod55.default.string().optional().describe("Connection key. Omit when only one semantic-metrics connection exists"),
41561
- datasourceId: import_zod55.default.coerce.number().optional().describe("Numeric datasource id, e.g. 15 (required for all actions except list_datasources; optional if set in runConfig.metricsDataSource)"),
41562
- sql: import_zod55.default.string().optional().describe("Read-only SQL (SELECT/WITH only). Required for the query action. Metadata templates \u2014 PostgreSQL/SQL Server columns: select column_name, data_type from information_schema.columns where table_schema = :schemaName and table_name = :tableName order by ordinal_position; HANA columns: select column_name, data_type_name from table_columns where schema_name = :schemaName and table_name = :tableName order by position; distributions: select <dim>, count(*) as row_count from <table> group by <dim> order by row_count desc limit :maxRows"),
41563
- params: import_zod55.default.record(import_zod55.default.union([import_zod55.default.string(), import_zod55.default.number(), import_zod55.default.boolean()])).optional().describe("Named :param values for the SQL"),
41564
- maxRows: import_zod55.default.number().optional().describe("Max rows to return")
41565
- })
41566
- }
41567
- );
41568
- }
41569
-
41570
- // src/tool_lattice/semantic_metrics/metrics_meta_tool.ts
41571
- var import_zod56 = __toESM(require("zod"));
41572
- var import_langchain68 = require("langchain");
41573
- var DESCRIPTION2 = `SEMANTIC ASSET REGISTRY (Builder/Admin only) \u2014 the only tool for reading and publishing the runtime's semantic layer: table meta (meta/tables) and metric meta (meta/metrics).
41574
-
41575
- OWNS: listing published tables and metrics, reading one by objectKey, publishing a semantic table (create_table: columns tagged with role dimension|measure), publishing a metric (create_metric: a metric_index payload then a metric_detail payload using the SQL-free calculation DSL), and correcting published assets (update_table / update_metric).
41576
-
41577
- DOES NOT OWN:
41578
- - Running queries or reading the aggregated runtime view \u2192 metrics_runtime_tool (get_meta / query / custom_sql).
41579
- - Probing physical tables, columns, grants, or samples \u2192 metrics_datasource_tool.
41580
-
41581
- USE WHEN: physical exploration is done and the model has been proposed and confirmed by the user \u2014 to publish the semantic table and metrics, or to correct published assets afterwards.
41582
-
41583
- COMMON MISTAKES (do not):
41584
- - Do not call get_meta here \u2014 that action belongs to metrics_runtime_tool, not this tool.
41585
- - Do not try to "query numbers" through this tool \u2014 list/read actions return definitions only; use metrics_runtime_tool query for data.
41586
- - Do not publish a metric whose sourceTable has no published table meta, or whose dimensions are not published columns with role dimension \u2014 the server will reject it.
41587
- - The builder assistant must load the semantic-metrics-modeling skill and pass modelingSkillLoaded: true on write actions; no removal actions are exposed on purpose.`;
41588
- var MODELING_SKILL_NAME = "semantic-metrics-modeling";
41589
- var BUILDER_ASSISTANT_ID = "semantic-metrics-builder";
41590
- function requireModelingSkillLoaded(action, input, exeConfig) {
41591
- const isWriteAction = action === "create_table" || action === "update_table" || action === "create_metric" || action === "update_metric";
41592
- if (!isWriteAction) return void 0;
41593
- const runConfig = readToolRunConfig(exeConfig);
41594
- const assistantId = runConfig?.assistant_id;
41595
- if (assistantId === BUILDER_ASSISTANT_ID && input.modelingSkillLoaded !== true) {
41596
- return JSON.stringify({
41597
- success: false,
41598
- error: `Load the '${MODELING_SKILL_NAME}' skill before publishing meta.`
41599
- });
41600
- }
41601
- return void 0;
41602
- }
41603
- function actionRequiresPayload(action) {
41604
- return action === "create_table" || action === "update_table" || action === "create_metric" || action === "update_metric";
41605
- }
41606
- function createMetricsMetaTool(params) {
41607
- const { connectionType, connections, connectAll } = params;
41608
- return (0, import_langchain68.tool)(
41609
- async (input, exeConfig) => {
41610
- try {
41611
- const guardError = requireModelingSkillLoaded(input.action, input, exeConfig);
41612
- if (guardError !== void 0) return guardError;
41613
- const client = await resolveMetricsClientFromSelector(
41614
- { connectionType, connections, connectAll },
41615
- readToolRunConfig(exeConfig) ?? {},
41616
- input.connectionKey
41617
- );
41618
- const ds = resolveDatasourceId(input, exeConfig);
41619
- assertDatasourceSelected(effectiveDatasourceScope(client.getSelectedEntities()), ds);
41620
- if (actionRequiresPayload(input.action) && input.payload === void 0) {
41621
- throw new Error(`payload is required for ${input.action}`);
41622
- }
41623
- const payload = input.payload ?? {};
41624
- switch (input.action) {
41625
- case "list_tables": {
41626
- return JSON.stringify(await client.listTables(ds), null, 2);
41627
- }
41628
- case "read_table_meta": {
41629
- if (!input.objectKey) throw new Error("objectKey is required for read_table_meta");
41630
- return JSON.stringify(await client.getTable(ds, input.objectKey), null, 2);
41631
- }
41632
- case "create_table": {
41633
- return JSON.stringify(await client.createTable(ds, payload), null, 2);
41634
- }
41635
- case "update_table": {
41636
- if (!input.objectKey) throw new Error("objectKey is required for update_table");
41637
- return JSON.stringify(await client.updateTable(ds, input.objectKey, payload), null, 2);
41638
- }
41639
- case "list_metrics": {
41640
- return JSON.stringify(await client.listMetrics(ds), null, 2);
41641
- }
41642
- case "read_metric_meta": {
41643
- if (!input.objectKey) throw new Error("objectKey is required for read_metric_meta");
41644
- return JSON.stringify(await client.getMetric(ds, input.objectKey), null, 2);
41645
- }
41646
- case "create_metric": {
41647
- return JSON.stringify(await client.createMetric(ds, payload), null, 2);
41648
- }
41649
- case "update_metric": {
41650
- if (!input.objectKey) throw new Error("objectKey is required for update_metric");
41651
- return JSON.stringify(await client.updateMetric(ds, input.objectKey, payload), null, 2);
41652
- }
41653
- }
41654
- } catch (error) {
41655
- return `Error: ${error instanceof Error ? error.message : String(error)}`;
41656
- }
41657
- },
41658
- {
41659
- name: "metrics_meta_tool",
41660
- description: DESCRIPTION2,
41661
- schema: import_zod56.default.object({
41662
- action: import_zod56.default.enum([
41663
- "list_tables",
41664
- "read_table_meta",
41665
- "create_table",
41666
- "update_table",
41667
- "list_metrics",
41668
- "read_metric_meta",
41669
- "create_metric",
41670
- "update_metric"
41671
- ]).describe(
41672
- "Actions ONLY in this meta tool (runtime query actions like get_meta/query belong to metrics_runtime_tool): list_tables/list_metrics (browse published assets), read_table_meta/read_metric_meta (details by objectKey), create_table/create_metric (publish), update_table/update_metric (correct)"
41673
- ),
41674
- connectionKey: import_zod56.default.string().optional().describe("Connection key. Omit when only one semantic-metrics connection exists"),
41675
- datasourceId: import_zod56.default.coerce.number().optional().describe("Numeric datasource id, e.g. 15 (optional if set in runConfig.metricsDataSource)"),
41676
- objectKey: import_zod56.default.string().optional().describe("Semantic table/metric key (required for read_table_meta/update_table/read_metric_meta/update_metric)"),
41677
- payload: import_zod56.default.record(import_zod56.default.unknown()).optional().describe("Meta payload (required for create/update actions; objectType/objectKey/status/payload/accessGrant)"),
41678
- modelingSkillLoaded: import_zod56.default.literal(true).optional().describe("Set true after loading the semantic-metrics-modeling skill (required for the builder assistant on write actions)")
41679
- })
41680
- }
41681
- );
41682
- }
41683
-
41684
- // src/tool_lattice/semantic_metrics/metrics_runtime_tool.ts
41685
- var import_zod57 = __toESM(require("zod"));
41686
- var import_langchain69 = require("langchain");
41687
- var DESCRIPTION3 = `RUNTIME QUERY SURFACE \u2014 read what is published and answer business questions with numbers. Business agents use ONLY this tool; Builder agents also use it to verify freshly published metrics.
41688
-
41689
- OWNS: list_datasources (self-contained datasource discovery \u2014 redacted output, the first step before anything else), read_semantic_catalog (the published semantic model for a datasource: tables, metrics, dimensions, filters) and query_metrics (the semantic metric query: metrics / groupBy / filters / orderBy / limit \u2014 the server generates the SQL, so there is no free-form SQL here).
41690
-
41691
- DOES NOT OWN:
41692
- - Publishing or correcting semantic tables/metrics \u2192 metrics_meta_tool (create_table/update_table/create_metric/update_metric/list_tables/read_table_meta/list_metrics/read_metric_meta).
41693
- - Physical exploration of raw tables, grants, or samples \u2192 metrics_datasource_tool (query_sql).
41694
- - Free-form custom SQL \u2014 intentionally not provided; use query against published metrics.
41695
-
41696
- USE WHEN: read_semantic_catalog to see what is published before asking numbers; query_metrics to answer a business question from already-published metrics (Business) or to verify a just-published metric against its acceptance evidence (Builder).
41697
-
41698
- COMMON MISTAKES (do not):
41699
- - Do not call meta-tool actions here (create_table / update_table / create_metric / update_metric / list_tables / read_table_meta / list_metrics / read_metric_meta) \u2014 they live in metrics_meta_tool and will fail schema validation here.
41700
- - Do not look for a custom-SQL action \u2014 there is none; explore physical data with metrics_datasource_tool query_sql, and query business numbers with the semantic query action.
41701
- - Metrics and dimensions in query_metrics must already be published; querying an unpublished metric fails with "not found in catalog".`;
41702
- function createMetricsRuntimeTool(params) {
41703
- const { connectionType, connections, connectAll } = params;
41704
- return (0, import_langchain69.tool)(
41705
- async (input, exeConfig) => {
41706
- try {
41707
- const client = await resolveMetricsClientFromSelector(
41708
- { connectionType, connections, connectAll },
41709
- readToolRunConfig(exeConfig) ?? {},
41710
- input.connectionKey
41711
- );
41712
- const scope = effectiveDatasourceScope(client.getSelectedEntities());
41713
- switch (input.action) {
41714
- case "list_datasources": {
41715
- const result = await client.listDatasources();
41716
- const filtered = scope.unrestricted ? result : result.filter((d) => scope.ids.includes(Number(d.id)));
41717
- const safe = filtered.map((d) => ({
41718
- id: d.id,
41719
- name: d.name,
41720
- sourceType: d.sourceType,
41721
- description: d.description,
41722
- statusLabel: d.statusLabel
41723
- }));
41724
- return JSON.stringify(safe, null, 2);
41725
- }
41726
- case "read_semantic_catalog": {
41727
- const ds = resolveDatasourceId(input, exeConfig);
41728
- assertDatasourceSelected(scope, ds);
41729
- return JSON.stringify(await client.getRuntimeMeta(ds), null, 2);
41730
- }
41731
- case "query_metrics": {
41732
- if (!input.query) throw new Error("query is required for the 'query_metrics' action");
41733
- const bodyDatasourceId = input.query.datasourceId;
41734
- if (bodyDatasourceId !== void 0) {
41735
- assertDatasourceSelected(scope, Number(bodyDatasourceId));
41736
- }
41737
- return JSON.stringify(await client.queryMetrics(input.query), null, 2);
41738
- }
41739
- }
41740
- } catch (error) {
41741
- return `Error: ${error instanceof Error ? error.message : String(error)}`;
41742
- }
41743
- },
41744
- {
41745
- name: "metrics_runtime_tool",
41746
- description: DESCRIPTION3,
41747
- schema: import_zod57.default.object({
41748
- action: import_zod57.default.enum(["list_datasources", "read_semantic_catalog", "query_metrics"]).describe(
41749
- "Actions ONLY in this runtime tool: list_datasources (list available datasources \u2014 ALWAYS call this first to obtain the datasourceId; output is redacted to non-sensitive fields), read_semantic_catalog (read the published semantic model: tables, metrics, dimensions), query_metrics (run a semantic metric query \u2014 the only way to get business numbers). Do NOT put meta-tool actions (list_tables/read_table_meta/create_table/update_table/list_metrics/read_metric_meta/create_metric/update_metric) here"
41750
- ),
41751
- connectionKey: import_zod57.default.string().optional().describe("Connection key. Omit when only one semantic-metrics connection exists"),
41752
- datasourceId: import_zod57.default.coerce.number().optional().describe("Numeric datasource id, e.g. 15 (required for read_semantic_catalog; optional if set in runConfig.metricsDataSource)"),
41753
- query: import_zod57.default.record(import_zod57.default.unknown()).optional().describe('Semantic metric query request. Required for the query_metrics action, e.g. { datasourceId: 15, metrics: ["sell_in_nes"], groupBy: ["sales_team"], filters: [{ dimension: "posting_year", operator: "GTE", values: [2024] }], limit: 10 }')
41754
- })
41755
- }
41756
- );
41757
- }
41758
-
41759
- // src/middlewares/semanticMetricsModelingSkill.ts
41760
- var CONTENT = `---
41761
- name: semantic-metrics-modeling
41762
- description: Builder policy for turning a granted datasource into published semantic tables and metrics. Governs goal agreement, FEP verification, persistent-task tracking, belief-state updates, and continuous refinement until acceptance evidence is met.
41763
- ---
41764
-
41765
- # Semantic Metrics Modeling
41766
-
41767
- You are the Semantic Metrics Builder. You turn physical datasource tables into reusable
41768
- **semantic tables** and **business metrics** on a Metrics Server (\`/api/v1\`). Work is
41769
- governed, observable, and continuously refined \u2014 never a one-shot guess.
41770
-
41771
- ## Goal Model
41772
-
41773
- Before any exploration or publishing, agree with the user on:
41774
- - **Real goal**: the business outcome (which metrics, for what decision), not just "make a table".
41775
- - **Consumer**: who reads the result and how.
41776
- - **Usable state**: observable conditions that make the published meta useful.
41777
- - **Scope**: which datasource/tables, and what is explicitly out of scope.
41778
- - **Acceptance evidence**: objective criteria (e.g. "metric \`sell_in_nes\` returns sane monthly
41779
- totals for 2024") used to decide success.
41780
- Do not guess material goals, consumers, or acceptance evidence.
41781
-
41782
- **Vague requests** (e.g. "build the metric layer") \u2014 do not act and do not ask blind questions.
41783
- First run cheap read-only observations (\`list_datasources\`, \`get_grants\`, \`list_tables\`,
41784
- \`list_metrics\`) to see what is authorized and already published, then ask focused questions that
41785
- carry that context and offer concrete options (which datasource/tables, which business questions,
41786
- extend existing metrics or build new). Every clarification question must include enough context and
41787
- options for the user to answer in one step. Only after the user picks a direction does the Goal
41788
- Model become confirmable \u2014 record it, create the task, and proceed to the workflow.
41789
-
41790
- ## Target model and quality bar
41791
-
41792
- Your goal is a specific, verifiable artifact, not "some tables and metrics".
41793
-
41794
- **Target shape** \u2014 one delivery is:
41795
- - a published \`table_view_detail\` meta per logical table, with every column tagged
41796
- \`role\` (dimension | measure) and a business-readable \`label\`;
41797
- - a \`metric_index\` + \`metric_detail\` pair per metric, using the SQL-free \`calculation\` DSL;
41798
- - the set, taken together, answers the user's concrete business question.
41799
-
41800
- **Publish gate (self-check every metric before create)** \u2014 if any fails, do **not** publish; go
41801
- explore or ask the user:
41802
- 1. measure: an aggregation is chosen **and** its business meaning is confirmed (net/gross, currency, dedupe or not);
41803
- 2. dimension: has a business meaning and a grain (day/month/year/\u2026);
41804
- 3. \`displayName\`/\`label\` are business-readable;
41805
- 4. the metric answers one concrete question from the user's stated goal;
41806
- 5. a runtime \`query\` returns numbers consistent with the confirmed meaning.
41807
-
41808
- **Intent gaps first** \u2014 before diving into exploration, list the inputs you still need to meet the
41809
- quality bar (business meaning, grain, target metric list, table scope, consumer) and ask for them
41810
- explicitly. Exploration and user questions are both driven by this target shape and quality bar:
41811
- missing business meaning \u2192 ask; unclear field semantics \u2192 probe or ask; right shape but it does not
41812
- answer the business question \u2192 do not publish.
41813
-
41814
- ## FEP Loop
41815
-
41816
- Apply this loop to every step (explore, publish table, publish metric, verify):
41817
- **OBSERVE \u2192 HYPOTHESIZE \u2192 ACT \u2192 VERIFY \u2192 DECIDE \u2192 RECONCILE**
41818
-
41819
- - **Observe**: current state, grants, published meta, and decision-relevant uncertainty.
41820
- - **Hypothesize**: what evidence should appear if your model is right, and how each outcome changes the decision.
41821
- - **Act**: one proportional action \u2014 no more than necessary.
41822
- - **Verify**: compare the observed result (e.g. a runtime \`query\`) against the prediction.
41823
- - **Decide**: classify as **RETAIN** (confirmed), **REVERT** (rejected), or **INCONCLUSIVE**.
41824
- - **Reconcile**: update the belief state and plan, then repeat while decision-relevant action remains.
41825
-
41826
- Renew user approval when a foundational assumption or the goal changes.
41827
-
41828
- ## Task Policy
41829
-
41830
- Use persistent TaskItems as your planning surface. Do not use \`write_todos\`. Create a child task
41831
- only for an independently verifiable outcome (e.g. "publish table meta for \`hankel_distr_sell_in\`").
41832
- Exploration queries and tool calls are activities inside the active task. See the
41833
- \`task-definition\` skill for \`manage_task\` operation details.
41834
-
41835
- ## Belief State
41836
-
41837
- Record your modeling beliefs in the active task's description under a \`## Belief State\` section as
41838
- a Markdown table:
41839
-
41840
- \`\`\`
41841
- | Belief Key | Probability | Target | Basis |
41842
- |---|---|---|---|
41843
- | sell-in-nes-source-table | 70% | 100% | column \`nes\` probed as numeric measure in grant |
41844
- \`\`\`
41845
-
41846
- Rules: belief keys are lowercase kebab-case; probability/target are percentages 0\u2013100% that
41847
- represent evidence support, not calibrated probability. Update this section each FEP reconcile so
41848
- the task always reflects the current evidence.
41849
-
41850
- ## Workflow
41851
-
41852
- 1. **Pick the datasource.** \`metrics_datasource_tool\` action \`list_datasources\`, or the preset
41853
- \`runConfig.metricsDataSource\` (\`serverKey\`\u2192connectionKey, \`datasourceId\`).
41854
- 2. **Read the boundary.** \`get_grants\` \u2192 note the allowed schema + table pattern. Never probe outside it.
41855
- 3. **Explore within the grant.** \`query\` with read-only SQL. Use the templates in
41856
- \`references/metadata-sql.md\`; if the user supplied schema docs or sample files, read them first
41857
- via filesystem to reduce querying.
41858
- 4. **Propose the model.** Present the table columns (with \`role: dimension | measure\`) and the
41859
- metrics (aggregate/derived) for approval before publishing.
41860
- 5. **Publish the semantic table.** \`metrics_meta_tool\` \`create_table\`.
41861
- 6. **Publish the metric.** \`metrics_meta_tool\` \`create_metric\` \u2014 \`metric_index\` then \`metric_detail\`
41862
- using the SQL-free \`calculation\` DSL.
41863
- 7. **Verify.** \`metrics_runtime_tool\` \`get_meta\`, then \`query\` the metric against acceptance evidence.
41864
-
41865
- ## 1. Explore
41866
-
41867
- Read \`table-grants\`, then probe with \`query\`. SQL is validated read-only by the client and the
41868
- server enforces the grant; un-granted tables return \`TABLE_NOT_GRANTED\`. Prefer the
41869
- \`references/metadata-sql.md\` templates because dialect varies (PostgreSQL / SQL Server / HANA).
41870
- If the user provides a data dictionary or sample data file, read it with filesystem and reconcile it
41871
- against the probed columns.
41872
-
41873
- ## Unclear field semantics
41874
-
41875
- A probed column name may not reveal its business meaning (e.g. whether \`nes\` is a net amount to
41876
- sum, a rate to average, or an enum to filter). Publishing meta on a misunderstood field pollutes
41877
- the runtime and every downstream metric that depends on it, and delete is not available. Treat this
41878
- as FEP **INCONCLUSIVE** \u2014 never guess, and never publish on an unverified guess.
41879
-
41880
- Resolve in order of increasing cost:
41881
- 1. **Probe sample values and distribution** (\`query\`, templates in \`references/metadata-sql.md\`):
41882
- - numbers in (0,1) or clustered near 100 \u2192 likely a ratio/percentage \u2192 dimension or \`avg\`, rarely \`sum\`;
41883
- - large additive amounts (currency, counts) \u2192 measure with \`sum\`;
41884
- - small enumerations (year 2023/2024, 0/1 flags, codes) \u2192 dimension.
41885
- The share of zeros/negatives and the value scale usually disambiguate semantics.
41886
- 2. **Read user-provided docs**: if the user supplied a data dictionary or sample file, read it via
41887
- filesystem and reconcile it against the probed columns.
41888
- 3. **Cross-field correlation**: compare the unclear field with fields whose semantics are confirmed.
41889
-
41890
- If evidence is still INCONCLUSIVE:
41891
- - Do **not** publish meta that depends on the unclear field.
41892
- - List the field with its candidate interpretations in the **Propose the model** step and ask the
41893
- user to confirm its semantics (role, value meaning, net/gross) via ask_user_to_clarify. The user
41894
- does not need to see the table \u2014 your probed schema, samples, and candidates are enough.
41895
- - Record a low-probability belief entry (e.g.
41896
- \`| sales-nes-semantics | 40% | 100% | user must confirm role / net amount |\`) so verify/refine can
41897
- revisit it later instead of assuming it is settled.
41898
-
41899
- ## 2. Publish table meta (\`create_table\`)
41900
-
41901
- Publish the authoritative shape below (objectType \`table_view_detail\`, with an EXACT accessGrant):
41902
-
41903
- \`\`\`json
41904
- {
41905
- "objectType": "table_view_detail",
41906
- "objectKey": "hankel_view_sales_summary",
41907
- "status": 1,
41908
- "payload": {
41909
- "schemaName": "public",
41910
- "tableName": "hankel_view_sales_summary",
41911
- "displayName": "Hankel Sales Summary",
41912
- "docType": "Sales Summary",
41913
- "docTypeEn": "Sales Summary",
41914
- "shortDesc": "Sales-level progress summary.",
41915
- "grain": "canonical_sales_name",
41916
- "sourceSystem": "Hankel Run for Gold",
41917
- "sourceTables": ["hankel_project_opportunity_lines", "hankel_new_order_lines"],
41918
- "columns": [
41919
- { "name": "canonical_sales_name", "label": "Canonical Sales Name", "type": "string", "role": "dimension", "description": "Standardized sales name used for grouping." },
41920
- { "name": "nes", "label": "NES", "type": "number", "role": "measure", "description": "Net external sales amount." },
41921
- { "name": "report_cutoff_date", "label": "Report Cutoff Date", "type": "date", "role": "time", "description": "Cutoff date of the report snapshot." }
41922
- ]
41923
- },
41924
- "accessGrant": {
41925
- "schemaName": "public",
41926
- "tablePattern": "hankel_view_sales_summary",
41927
- "patternType": "EXACT",
41928
- "caseSensitive": false,
41929
- "status": 1
41930
- }
41931
- }
41932
- \`\`\`
41933
-
41934
- Design rules:
41935
- - \`objectKey\` is stable and unique per datasource (the view/table key).
41936
- - \`columns[].role\` has THREE values: \`dimension\` (grouping/filtering), \`measure\` (aggregated numbers), \`time\` (the report cutoff/snapshot date used by default_time_context).
41937
- - Give every column a business \`description\`.
41938
- - Lineage fields (\`docType\`, \`shortDesc\`, \`grain\`, \`sourceSystem\`, \`sourceTables\`) make the asset findable and trustworthy \u2014 fill them from exploration evidence.
41939
- - Runtime table publication uses \`patternType: "EXACT"\` (\`PREFIX\` is only for datasource-level exploration scopes).
41940
- - For each semantic table also publish the identity twin: the same body with \`objectType: "table_catalog"\` and the same \`objectKey\` (same or richer payload).
41941
-
41942
- ## 3. Publish metric meta (\`create_metric\`)
41943
-
41944
- Two steps for the same \`objectKey\`.
41945
-
41946
- ### 3a. Metric index (for lists/search)
41947
-
41948
- \`\`\`json
41949
- {
41950
- "objectType": "metric_index",
41951
- "objectKey": "sell_in_nes",
41952
- "status": 1,
41953
- "payload": {
41954
- "metric_name": "sell_in_nes",
41955
- "display_name": "Sell-in NES",
41956
- "domain": "sales",
41957
- "short_desc": "Net external sales amount from distributor sell-in rows.",
41958
- "search_keywords": ["sell in", "nes", "net external sales"],
41959
- "source_type": "cdp_postgres",
41960
- "source": { "table_view": "public.hankel_distr_sell_in" }
41961
- }
41962
- }
41963
- \`\`\`
41964
-
41965
- \`search_keywords\` drive metric retrieval for natural-language questions \u2014 include business synonyms.
41966
-
41967
- ### 3b. Metric detail (the calculation)
41968
-
41969
- IMPORTANT \u2014 runtime schema requirement: the Metrics Server query runtime only recognizes metrics
41970
- published in the FULL runtime style below (the same shape as existing working metrics, with
41971
- snake_case fields like \`metric_name\`, \`source.table_view\`, \`supported_dimensions\` objects, and
41972
- \`default_time_context\`). A minimal \`{name, sourceTable, calculation, dimensions}\` payload is
41973
- accepted by the publish API but is NOT queryable \u2014 querying it returns 403 "not authorized".
41974
-
41975
- Aggregate metric (full runtime style):
41976
-
41977
- \`\`\`json
41978
- {
41979
- "objectType": "metric_detail",
41980
- "objectKey": "sell_in_nes",
41981
- "status": 1,
41982
- "payload": {
41983
- "metric_name": "sell_in_nes",
41984
- "display_name": "Sell-in NES",
41985
- "domain": "sales",
41986
- "description": "Net external sales amount from distributor sell-in rows.",
41987
- "data_type": "numeric",
41988
- "format": "currency",
41989
- "source_type": "cdp_postgres",
41990
- "source": { "table_view": "public.hankel_distr_sell_in", "base_filters": [] },
41991
- "calculation": { "type": "aggregate", "aggregation": "sum", "measure": "nes" },
41992
- "supported_dimensions": [
41993
- { "dim_id": "posting_year", "field_name": "posting_year", "label": "Posting Year", "data_type": "number" },
41994
- { "dim_id": "sales_team", "field_name": "sales_team", "label": "Sales Team", "data_type": "string" }
41995
- ],
41996
- "default_time_context": {
41997
- "time_dimension": "posting_date",
41998
- "label": "Posting date",
41999
- "granularity": "month",
42000
- "window": "YTD",
42001
- "supported_grains": ["month", "year"]
42002
- },
42003
- "ai_agent_context": {
42004
- "polarity": "positive",
42005
- "synonyms": ["sell in", "nes", "net external sales"],
42006
- "human_readable_explanation": "Higher sell-in NES means more goods purchased from the distributor."
42007
- }
42008
- }
42009
- }
42010
- \`\`\`
42011
-
42012
- Derived ratio metric (references two aggregate metrics):
42013
-
42014
- \`\`\`json
42015
- {
42016
- "objectType": "metric_detail",
42017
- "objectKey": "gross_margin_rate",
42018
- "status": 1,
42019
- "payload": {
42020
- "metric_name": "gross_margin_rate",
42021
- "display_name": "Gross Margin Rate",
42022
- "description": "Gross margin divided by sell-in NES.",
42023
- "domain": "sales",
42024
- "data_type": "numeric",
42025
- "format": "percent",
42026
- "source_type": "cdp_postgres",
42027
- "source": { "table_view": "public.hankel_distr_sell_in", "base_filters": [] },
42028
- "calculation": { "type": "derived", "operator": "ratio", "numerator": "gross_margin", "denominator": "sell_in_nes" },
42029
- "supported_dimensions": [
42030
- { "dim_id": "posting_year", "field_name": "posting_year", "label": "Posting Year", "data_type": "number" }
42031
- ],
42032
- "default_time_context": { "time_dimension": "posting_date", "granularity": "month", "supported_grains": ["month", "year"] }
42033
- }
42034
- }
42035
- \`\`\`
42036
-
42037
- Design rules:
42038
- - \`objectKey\` unique per datasource (index and detail share it).
42039
- - \`payload.metric_name\` must equal \`objectKey\`.
42040
- - \`source.table_view\` must be schema-qualified and match the published table meta's physical table.
42041
- - \`supported_dimensions\` is an array of OBJECTS ({dim_id, field_name, label, data_type}); include the time dimension too; each must be a published column of that table meta.
42042
- - \`calculation.type: "aggregate"\` = one measure + aggregation (sum/avg/count/min/max/count_distinct).
42043
- - \`calculation.type: "derived"\` operator \`ratio\` references existing metric objectKeys (numerator/denominator); a \`formula\` variant takes an expression of metric names, numbers, parentheses, and + - * / \u2014 referenced metrics must share the same source.table_view.
42044
- - \`default_time_context\` (\`time_dimension\` + \`granularity\` + \`supported_grains\`, optionally \`window\`) is required by the query runtime; its \`time_dimension\` must appear in supported_dimensions.
42045
- - \`ai_agent_context\` (\`polarity\`, \`synonyms\`, \`human_readable_explanation\`) improves natural-language metric retrieval \u2014 always provide it.
42046
- - One semantic query can only combine metrics sharing the same source.table_view; groupBy values must be dim_ids or time-grain expressions like \`posting_date__month\`.
42047
- - Do not inline raw SQL for new DB-backed metrics (complex logic belongs in a view).
42048
- - Use \`update_metric\` / \`update_table\` to correct mistakes; no removal actions are exposed.
42049
-
42050
- ## 4. Verify and refine
42051
-
42052
- - \`get_meta\` \u2192 confirm the table and metric are visible.
42053
- - \`query\` the metric against the acceptance evidence. On failure, apply the FEP reconcile: update the
42054
- \`## Belief State\`, fix the meta, and retry \u2014 until acceptance evidence is met.
42055
-
42056
- ## Troubleshooting
42057
-
42058
- | Symptom | Cause / fix |
42059
- |---|---|
42060
- | \`TABLE_NOT_GRANTED\` | SQL referenced a table outside the tenant grant; pick an in-grant table |
42061
- | metric create fails: sourceTable missing | publish the table meta first |
42062
- | metric create fails: unknown dimension | publish the dimension column with \`role: dimension\` |
42063
- | derived metric create fails | numerator/denominator metrics don't exist yet \u2014 publish them first |
42064
- | datasource \`query\` rejected | SQL was not read-only (SELECT/WITH only) or multi-statement |
42065
- | \`403 Metric is not authorized\` on query_metrics | the metric meta is not in the queryable runtime schema (e.g. missing \`source.table_view\` / \`supported_dimensions\` / \`default_time_context\`) or genuinely unauthorized \u2014 re-publish with the full runtime payload and verify; never retry blindly |
42066
-
42067
- ## Safety
42068
-
42069
- - Only query tables that match the tenant's \`table-grants\`.
42070
- - Never return a full physical-table inventory or reveal whether an un-granted table exists.
42071
- - SQL is validated read-only; let the server reject anything outside that.
42072
- `;
42073
- var resources = {
42074
- "references/metadata-sql.md": {
42075
- content: `# Datasource exploration SQL templates (read-only)
42076
-
42077
- Pick the block matching the server's database. These run through the datasource \`query\` action;
42078
- the SQL is validated read-only.
42079
-
42080
- ## PostgreSQL
42081
- - Tables: \`select table_schema, table_name from information_schema.tables where table_schema not in ('pg_catalog','information_schema') order by table_schema, table_name\`
42082
- - Columns: \`select column_name, data_type from information_schema.columns where table_schema = :schemaName and table_name = :tableName order by ordinal_position\`
42083
- - Sample: \`select * from :schemaName.:tableName limit :maxRows\` \u2014 pass a concrete table, not a bound param, if the server does not support binding identifiers.
42084
-
42085
- ## SQL Server
42086
- - Tables: \`select table_schema, table_name from information_schema.tables order by table_schema, table_name\`
42087
- - Columns: \`select column_name, data_type from information_schema.columns where table_schema = :schemaName and table_name = :tableName order by ordinal_position\`
42088
-
42089
- ## HANA
42090
- - Tables: \`select schema_name, table_name from sys.tables where schema_name = :schemaName order by table_name\`
42091
- - Columns: \`select column_name, data_type_name from table_columns where schema_name = :schemaName and table_name = :tableName order by position\`
42092
-
42093
- ## Value distribution (any dialect)
42094
- \`select <dim>, count(*) as row_count from <table> group by <dim> order by row_count desc limit :maxRows\`
42095
- `
42096
- },
42097
- "examples/table-meta.json": {
42098
- content: `{
42099
- "objectType": "table_view_detail",
42100
- "objectKey": "hankel_distr_sell_in",
42101
- "status": 1,
42102
- "payload": {
42103
- "schemaName": "public",
42104
- "tableName": "hankel_distr_sell_in",
42105
- "displayName": "Hankel Distributor Sell In",
42106
- "description": "Distributor sell-in transaction rows for the Hankel tenant.",
42107
- "columns": [
42108
- { "name": "posting_year", "label": "Posting Year", "type": "number", "role": "dimension" },
42109
- { "name": "posting_month", "label": "Posting Month", "type": "number", "role": "dimension" },
42110
- { "name": "sales_team", "label": "Sales Team", "type": "string", "role": "dimension" },
42111
- { "name": "region", "label": "Region", "type": "string", "role": "dimension" },
42112
- { "name": "nes", "label": "Net External Sales", "type": "number", "role": "measure" },
42113
- { "name": "gross_margin", "label": "Gross Margin", "type": "number", "role": "measure" }
42114
- ]
42115
- }
42116
- }
42117
- `
42118
- },
42119
- "examples/metric-aggregate.json": {
42120
- content: `{
42121
- "objectType": "metric_detail",
42122
- "objectKey": "hankel_sell_in_nes",
42123
- "status": 1,
42124
- "payload": {
42125
- "name": "hankel_sell_in_nes",
42126
- "displayName": "Sell-in NES",
42127
- "description": "Net external sales amount from distributor sell-in rows.",
42128
- "sourceTable": "hankel_distr_sell_in",
42129
- "calculation": { "type": "aggregate", "aggregation": "sum", "measure": "nes" },
42130
- "dimensions": ["posting_year", "posting_month", "sales_team", "region"]
42131
- }
42132
- }
42133
- `
42134
- },
42135
- "examples/metric-derived.json": {
42136
- content: `{
42137
- "objectType": "metric_detail",
42138
- "objectKey": "hankel_gross_margin_rate",
42139
- "status": 1,
42140
- "payload": {
42141
- "name": "hankel_gross_margin_rate",
42142
- "displayName": "Gross Margin Rate",
42143
- "description": "Gross margin divided by sell-in NES.",
42144
- "sourceTable": "hankel_distr_sell_in",
42145
- "calculation": {
42146
- "type": "derived",
42147
- "operator": "ratio",
42148
- "numerator": "hankel_gross_margin",
42149
- "denominator": "hankel_sell_in_nes"
42150
- },
42151
- "dimensions": ["posting_year", "sales_team", "region"]
42152
- }
42153
- }
42154
- `
42155
- }
42156
- };
42157
- var SEMANTIC_METRICS_MODELING_SKILL = {
42158
- version: "1.0.0",
42159
- content: CONTENT,
42160
- resources
42161
- };
42162
-
42163
- // src/middlewares/semanticMetricsBuilderPrompt.ts
42164
- var SEMANTIC_METRICS_BUILDER_PROMPT = `You are the Semantic Metrics Builder.
42165
-
42166
- CRITICAL FIRST ACTION: Before any response or other action, call the \`skill\`
42167
- tool with skill_name: "semantic-metrics-modeling" to load semantic-metrics-modeling and follow it.
42168
- Never announce the skill load. If it fails, retry once, then stop and explicitly
42169
- report that the required Semantic Metrics Builder skill could not be loaded.`;
42170
-
42171
- // src/middlewares/semanticMetricsMiddleware.ts
42172
- var import_protocols32 = require("@axiom-lattice/protocols");
42173
- function createSemanticMetricsMiddleware(config) {
42174
- const connections = config.connections ?? [];
42175
- const connectAll = config.connectAll === true;
42176
- const selector = { connectionType: "semantic-metrics", connections, connectAll };
42177
- return (0, import_langchain70.createMiddleware)({
42178
- name: "SemanticMetrics",
42179
- contextSchema,
42180
- tools: [
42181
- createMetricsDatasourceTool(selector),
42182
- createMetricsMetaTool(selector),
42183
- createMetricsRuntimeTool(selector)
42184
- ]
42185
- });
42186
- }
42187
- function buildConnectionHeaders(config) {
42188
- const headers = {
42189
- Accept: "application/json",
42190
- ...config.headers !== void 0 && config.headers !== null ? config.headers : {}
42191
- };
42192
- if (config.apiKey) headers["Authorization"] = `Bearer ${config.apiKey}`;
42193
- return headers;
42194
- }
42195
- function resolveBaseUrl(config) {
42196
- const serverUrl = config.serverUrl;
42197
- if (!serverUrl) {
42198
- throw new Error("serverUrl is required");
42199
- }
42200
- return serverUrl.replace(/\/$/, "");
42201
- }
42202
- var semanticMetricsPlugin = {
42203
- meta: {
42204
- type: "semantic-metrics",
42205
- category: "data",
42206
- capabilityBundleEligible: true,
42207
- openExpose: [
42208
- // Query-only surface: no writes reach either tool (SQL is read-only).
42209
- { name: "metrics_datasource_tool", readOnly: true },
42210
- { name: "metrics_runtime_tool", readOnly: true }
42211
- ],
42212
- name: "Semantic Metrics",
42213
- description: "Semantic metrics datasource exploration, meta publishing, and runtime querying. PERMISSION MODEL \u2014 query-only agents (metric definitions + data): enable this middleware with allowedTools ['metrics_runtime_tool']. Metric designers (Builder): keep all three tools (metrics_datasource_tool, metrics_meta_tool, metrics_runtime_tool) for exploration, publishing, and verification, or use the built-in 'semantic-metrics-builder' agent.",
42214
- version: "1.0.0",
42215
- tools: [
42216
- { name: "metrics_datasource_tool", description: "Explore datasource structure within the tenant's granted scope" },
42217
- { name: "metrics_meta_tool", description: "Publish and maintain runtime semantic tables and metrics" },
42218
- { name: "metrics_runtime_tool", description: "Read runtime meta and execute semantic metric queries" }
42219
- ],
42220
- configSchema: {
42221
- type: "object",
42222
- title: "Semantic Metrics Configuration",
42223
- description: "First select connections (connections or connectAll). Then scope tools by role via allowedTools: QUERY-ONLY agents (metric definitions + data) set allowedTools to ['metrics_runtime_tool'] \u2014 it is self-contained (list_datasources, read_semantic_catalog, query_metrics); metric DESIGNERS keep all three tools (datasource exploration, meta publishing, runtime verification).",
42224
- properties: {
42225
- connections: {
42226
- type: "array",
42227
- title: "Connections",
42228
- items: { type: "string" },
42229
- widget: "connectionSelect"
42230
- },
42231
- connectAll: {
42232
- type: "boolean",
42233
- title: "Connect All",
42234
- default: false,
42235
- widget: "switch"
42236
- }
42237
- }
42238
- },
42239
- defaultConfig: { connections: [], connectAll: false }
42240
- },
42241
- connection: {
42242
- // PluginConnectionFieldSchema.type supports only string/number/boolean/password,
42243
- // so headers is NOT a form field; the V2 client still reads config.headers at runtime.
42244
- fields: [
42245
- { key: "serverUrl", type: "string", title: "Metrics Server Base URL (include /api/v1)", required: true },
42246
- { key: "apiKey", type: "password", title: "API Key (optional)" }
42247
- ],
42248
- test: async (config) => {
42249
- try {
42250
- const baseUrl = resolveBaseUrl(config);
42251
- const res = await fetch(`${baseUrl}/datasources`, {
42252
- headers: buildConnectionHeaders(config)
42253
- });
42254
- const text = await res.text().catch(() => "");
42255
- let ok = res.ok;
42256
- let detail = "";
42257
- try {
42258
- const parsed = JSON.parse(text);
42259
- if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
42260
- const code = parsed.code;
42261
- if (typeof code === "number") {
42262
- ok = res.ok && code === 200;
42263
- if (!ok) detail = ` (${parsed.message ?? code})`;
42264
- }
42265
- }
42266
- } catch {
42267
- }
42268
- return {
42269
- ok,
42270
- message: ok ? `Reachable at ${baseUrl}` : `HTTP ${res.status}${detail}`
42271
- };
42272
- } catch (err) {
42273
- return {
42274
- ok: false,
42275
- message: `Cannot connect: ${err instanceof Error ? err.message : String(err)}`
42276
- };
42277
- }
42278
- },
42279
- discover: async (config) => {
42280
- try {
42281
- const baseUrl = resolveBaseUrl(config);
42282
- const res = await fetch(`${baseUrl}/datasources`, {
42283
- headers: buildConnectionHeaders(config)
42284
- });
42285
- const text = await res.text();
42286
- if (!res.ok) {
42287
- throw new Error(`HTTP ${res.status}${text ? `: ${text.slice(0, 200)}` : ""}`);
42288
- }
42289
- const parsed = JSON.parse(text);
42290
- if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
42291
- throw new Error("Metrics server returned an unexpected payload (expected a JSON envelope)");
42292
- }
42293
- const envelope = parsed;
42294
- if (typeof envelope.code === "number" && envelope.code !== 200) {
42295
- throw new Error(envelope.message || `API ${envelope.code}`);
42296
- }
42297
- const data = envelope.data;
42298
- if (!Array.isArray(data)) {
42299
- throw new Error("Metrics server returned an unexpected payload (expected a datasource array)");
42300
- }
42301
- return data.filter((d) => {
42302
- if (d === null || typeof d !== "object") return false;
42303
- const id = d.id;
42304
- return id !== void 0 && id !== null && id !== "";
42305
- }).map((item) => ({
42306
- id: String(item.id),
42307
- name: item.name ?? String(item.id)
42308
- }));
42309
- } catch (err) {
42310
- throw new Error(
42311
- `Cannot discover datasources: ${err instanceof Error ? err.message : String(err)}`
42312
- );
42313
- }
42314
- }
42315
- },
42316
- skills: {
42317
- "semantic-metrics-modeling": SEMANTIC_METRICS_MODELING_SKILL
42318
- },
42319
- agents: {
42320
- "semantic-metrics-builder": {
42321
- key: "semantic-metrics-builder",
42322
- name: "Semantic Metrics Builder",
42323
- description: "Explore a granted datasource and build semantic tables and metrics interactively, tracking the work as persistent tasks with belief state and verifying each step.",
42324
- type: import_protocols32.AgentType.DEEP_AGENT,
42325
- prompt: SEMANTIC_METRICS_BUILDER_PROMPT,
42326
- middleware: [
42327
- {
42328
- id: "semantic-metrics",
42329
- type: "semantic-metrics",
42330
- name: "Semantic Metrics",
42331
- description: "Explore datasources, publish table/meta metrics, query runtime",
42332
- enabled: true,
42333
- config: { connections: [], connectAll: true }
42334
- },
42335
- {
42336
- id: "skill",
42337
- type: "skill",
42338
- name: "Skill",
42339
- description: "Load the semantic-metrics-modeling policy and task-definition reference",
42340
- enabled: true,
42341
- config: { readAll: false, skills: ["semantic-metrics-modeling", "task-definition"] }
42342
- },
42343
- {
42344
- id: "task",
42345
- type: "task",
42346
- name: "Task",
42347
- description: "Persistent TaskItems as the planning surface; update Belief State in task descriptions",
42348
- enabled: true,
42349
- config: {}
42350
- },
42351
- {
42352
- id: "ask_user_to_clarify",
42353
- type: "ask_user_to_clarify",
42354
- name: "Ask User",
42355
- description: "Wait for user input at modeling approval gates",
42356
- enabled: true,
42357
- config: {}
42358
- },
42359
- {
42360
- id: "filesystem",
42361
- type: "filesystem",
42362
- name: "Filesystem",
42363
- description: "Read user-provided schema docs, data dictionaries, or sample data files",
42364
- enabled: true,
42365
- config: {}
42366
- }
42367
- ]
42368
- }
42369
- },
42370
- middleware: (config) => createSemanticMetricsMiddleware(config)
42371
- };
42372
-
42373
41182
  // src/middlewares/collectionMiddleware.ts
42374
- var import_langchain81 = require("langchain");
41183
+ var import_langchain77 = require("langchain");
42375
41184
 
42376
41185
  // src/tool_lattice/collection/list_collections.ts
42377
- var import_zod58 = __toESM(require("zod"));
42378
- var import_langchain71 = require("langchain");
41186
+ var import_zod55 = __toESM(require("zod"));
41187
+ var import_langchain67 = require("langchain");
42379
41188
 
42380
41189
  // src/tool_lattice/collection/utils.ts
42381
41190
  function getEffectiveCollectionScope(exeConfig, staticScope) {
@@ -42398,7 +41207,7 @@ var createListCollectionsTool = ({
42398
41207
  collectionKeys,
42399
41208
  connectAll
42400
41209
  }) => {
42401
- return (0, import_langchain71.tool)(
41210
+ return (0, import_langchain67.tool)(
42402
41211
  async (_input, _exeConfig) => {
42403
41212
  try {
42404
41213
  const tenantId2 = _exeConfig?.configurable?.runConfig?.tenantId || "default";
@@ -42433,23 +41242,23 @@ var createListCollectionsTool = ({
42433
41242
  {
42434
41243
  name: "list_collections",
42435
41244
  description: LIST_COLLECTIONS_DESCRIPTION,
42436
- schema: import_zod58.default.object({})
41245
+ schema: import_zod55.default.object({})
42437
41246
  }
42438
41247
  );
42439
41248
  };
42440
41249
 
42441
41250
  // src/tool_lattice/collection/search_collection.ts
42442
- var import_zod59 = __toESM(require("zod"));
42443
- var import_langchain72 = require("langchain");
41251
+ var import_zod56 = __toESM(require("zod"));
41252
+ var import_langchain68 = require("langchain");
42444
41253
  var SEARCH_COLLECTION_DESCRIPTION = `Search for content within a specific collection using semantic (vector) similarity. Use the 'filter' parameter to narrow results by metadata fields (e.g., {"category": "cardiovascular"}). Returns the most relevant content entries with similarity scores.`;
42445
- var searchSchema = import_zod59.default.object({
42446
- collection: import_zod59.default.string().describe("The collection name to search in"),
42447
- query: import_zod59.default.string().describe("The search query text"),
42448
- filter: import_zod59.default.record(import_zod59.default.unknown()).optional().describe("Metadata filter conditions"),
42449
- top_k: import_zod59.default.number().optional().default(5).describe("Number of results to return")
41254
+ var searchSchema = import_zod56.default.object({
41255
+ collection: import_zod56.default.string().describe("The collection name to search in"),
41256
+ query: import_zod56.default.string().describe("The search query text"),
41257
+ filter: import_zod56.default.record(import_zod56.default.unknown()).optional().describe("Metadata filter conditions"),
41258
+ top_k: import_zod56.default.number().optional().default(5).describe("Number of results to return")
42450
41259
  });
42451
41260
  var createSearchCollectionTool = (scope = { collectionKeys: [], connectAll: true }) => {
42452
- return (0, import_langchain72.tool)(
41261
+ return (0, import_langchain68.tool)(
42453
41262
  async (input, _exeConfig) => {
42454
41263
  try {
42455
41264
  const { collection, query, filter: filter2, top_k } = input;
@@ -42515,10 +41324,10 @@ var createSearchCollectionTool = (scope = { collectionKeys: [], connectAll: true
42515
41324
  };
42516
41325
 
42517
41326
  // src/tool_lattice/collection/get_collection.ts
42518
- var import_zod60 = __toESM(require("zod"));
42519
- var import_langchain73 = require("langchain");
41327
+ var import_zod57 = __toESM(require("zod"));
41328
+ var import_langchain69 = require("langchain");
42520
41329
  var GET_COLLECTION_DESCRIPTION = `Get a collection's full definition including its custom fields schema. Use this to discover what metadata fields are available before adding entries.`;
42521
- var createGetCollectionTool = (scope = { collectionKeys: [], connectAll: true }) => (0, import_langchain73.tool)(
41330
+ var createGetCollectionTool = (scope = { collectionKeys: [], connectAll: true }) => (0, import_langchain69.tool)(
42522
41331
  async (input, _exeConfig) => {
42523
41332
  try {
42524
41333
  const scopeError = validateCollectionScope(input.name, _exeConfig, scope);
@@ -42543,24 +41352,24 @@ Embedding: ${c.embeddingKey}${fieldsDesc}`;
42543
41352
  return `Error: ${error.message}`;
42544
41353
  }
42545
41354
  },
42546
- { name: "get_collection", description: GET_COLLECTION_DESCRIPTION, schema: import_zod60.default.object({ name: import_zod60.default.string().describe("Collection name") }) }
41355
+ { name: "get_collection", description: GET_COLLECTION_DESCRIPTION, schema: import_zod57.default.object({ name: import_zod57.default.string().describe("Collection name") }) }
42547
41356
  );
42548
41357
 
42549
41358
  // src/tool_lattice/collection/create_collection.ts
42550
- var import_zod61 = __toESM(require("zod"));
42551
- var import_langchain74 = require("langchain");
42552
- var createSchema = import_zod61.default.object({
42553
- name: import_zod61.default.string().describe("Collection name (lowercase, underscores only)"),
42554
- label: import_zod61.default.string().describe("Display name"),
42555
- embeddingKey: import_zod61.default.string().describe("Embedding model key"),
42556
- fields: import_zod61.default.array(import_zod61.default.object({
42557
- key: import_zod61.default.string().describe("Field key name"),
42558
- type: import_zod61.default.enum(["string", "number", "enum"]).describe("Field data type"),
42559
- enumValues: import_zod61.default.array(import_zod61.default.string()).optional().describe("Valid values for enum type"),
42560
- required: import_zod61.default.boolean().optional().default(false).describe("Whether field is required")
41359
+ var import_zod58 = __toESM(require("zod"));
41360
+ var import_langchain70 = require("langchain");
41361
+ var createSchema = import_zod58.default.object({
41362
+ name: import_zod58.default.string().describe("Collection name (lowercase, underscores only)"),
41363
+ label: import_zod58.default.string().describe("Display name"),
41364
+ embeddingKey: import_zod58.default.string().describe("Embedding model key"),
41365
+ fields: import_zod58.default.array(import_zod58.default.object({
41366
+ key: import_zod58.default.string().describe("Field key name"),
41367
+ type: import_zod58.default.enum(["string", "number", "enum"]).describe("Field data type"),
41368
+ enumValues: import_zod58.default.array(import_zod58.default.string()).optional().describe("Valid values for enum type"),
41369
+ required: import_zod58.default.boolean().optional().default(false).describe("Whether field is required")
42561
41370
  })).optional().describe("Custom field definitions for entries in this collection")
42562
41371
  });
42563
- var createCreateCollectionTool = (scope = {}) => (0, import_langchain74.tool)(
41372
+ var createCreateCollectionTool = (scope = {}) => (0, import_langchain70.tool)(
42564
41373
  async (input, _exeConfig) => {
42565
41374
  try {
42566
41375
  const tenantId2 = _exeConfig?.configurable?.runConfig?.tenantId || "default";
@@ -42586,20 +41395,20 @@ var createCreateCollectionTool = (scope = {}) => (0, import_langchain74.tool)(
42586
41395
  );
42587
41396
 
42588
41397
  // src/tool_lattice/collection/update_collection.ts
42589
- var import_zod62 = __toESM(require("zod"));
42590
- var import_langchain75 = require("langchain");
42591
- var schema = import_zod62.default.object({
42592
- name: import_zod62.default.string().describe("Collection name"),
42593
- label: import_zod62.default.string().optional().describe("New display name"),
42594
- embeddingKey: import_zod62.default.string().optional().describe("New embedding model key"),
42595
- fields: import_zod62.default.array(import_zod62.default.object({
42596
- key: import_zod62.default.string().describe("Field key name"),
42597
- type: import_zod62.default.enum(["string", "number", "enum"]).describe("Field data type"),
42598
- enumValues: import_zod62.default.array(import_zod62.default.string()).optional().describe("Valid values for enum type"),
42599
- required: import_zod62.default.boolean().optional().default(false).describe("Whether field is required")
41398
+ var import_zod59 = __toESM(require("zod"));
41399
+ var import_langchain71 = require("langchain");
41400
+ var schema = import_zod59.default.object({
41401
+ name: import_zod59.default.string().describe("Collection name"),
41402
+ label: import_zod59.default.string().optional().describe("New display name"),
41403
+ embeddingKey: import_zod59.default.string().optional().describe("New embedding model key"),
41404
+ fields: import_zod59.default.array(import_zod59.default.object({
41405
+ key: import_zod59.default.string().describe("Field key name"),
41406
+ type: import_zod59.default.enum(["string", "number", "enum"]).describe("Field data type"),
41407
+ enumValues: import_zod59.default.array(import_zod59.default.string()).optional().describe("Valid values for enum type"),
41408
+ required: import_zod59.default.boolean().optional().default(false).describe("Whether field is required")
42600
41409
  })).optional().describe("Custom field definitions for entries (replaces existing schema)")
42601
41410
  });
42602
- var createUpdateCollectionTool = (scope = { collectionKeys: [], connectAll: true }) => (0, import_langchain75.tool)(
41411
+ var createUpdateCollectionTool = (scope = { collectionKeys: [], connectAll: true }) => (0, import_langchain71.tool)(
42603
41412
  async (input, _exeConfig) => {
42604
41413
  try {
42605
41414
  const scopeError = validateCollectionScope(input.name, _exeConfig, scope);
@@ -42620,9 +41429,9 @@ var createUpdateCollectionTool = (scope = { collectionKeys: [], connectAll: true
42620
41429
  );
42621
41430
 
42622
41431
  // src/tool_lattice/collection/delete_collection.ts
42623
- var import_zod63 = __toESM(require("zod"));
42624
- var import_langchain76 = require("langchain");
42625
- var createDeleteCollectionTool = (scope = { collectionKeys: [], connectAll: true }) => (0, import_langchain76.tool)(
41432
+ var import_zod60 = __toESM(require("zod"));
41433
+ var import_langchain72 = require("langchain");
41434
+ var createDeleteCollectionTool = (scope = { collectionKeys: [], connectAll: true }) => (0, import_langchain72.tool)(
42626
41435
  async (input, _exeConfig) => {
42627
41436
  try {
42628
41437
  const scopeError = validateCollectionScope(input.name, _exeConfig, scope);
@@ -42634,19 +41443,19 @@ var createDeleteCollectionTool = (scope = { collectionKeys: [], connectAll: true
42634
41443
  return `Error: ${e.message}`;
42635
41444
  }
42636
41445
  },
42637
- { name: "delete_collection", description: `Delete a collection and all its entries. This cannot be undone.`, schema: import_zod63.default.object({ name: import_zod63.default.string().describe("Collection name") }) }
41446
+ { name: "delete_collection", description: `Delete a collection and all its entries. This cannot be undone.`, schema: import_zod60.default.object({ name: import_zod60.default.string().describe("Collection name") }) }
42638
41447
  );
42639
41448
 
42640
41449
  // src/tool_lattice/collection/list_entries.ts
42641
- var import_zod64 = __toESM(require("zod"));
42642
- var import_langchain77 = require("langchain");
42643
- var schema2 = import_zod64.default.object({
42644
- collection: import_zod64.default.string().describe("Collection name")
41450
+ var import_zod61 = __toESM(require("zod"));
41451
+ var import_langchain73 = require("langchain");
41452
+ var schema2 = import_zod61.default.object({
41453
+ collection: import_zod61.default.string().describe("Collection name")
42645
41454
  });
42646
41455
  function buildKey2(tenantId2, name) {
42647
41456
  return `${tenantId2}:${name}`;
42648
41457
  }
42649
- var createListEntriesTool = (scope = { collectionKeys: [], connectAll: true }) => (0, import_langchain77.tool)(
41458
+ var createListEntriesTool = (scope = { collectionKeys: [], connectAll: true }) => (0, import_langchain73.tool)(
42650
41459
  async (input, _exeConfig) => {
42651
41460
  try {
42652
41461
  const scopeError = validateCollectionScope(input.collection, _exeConfig, scope);
@@ -42675,19 +41484,19 @@ var createListEntriesTool = (scope = { collectionKeys: [], connectAll: true }) =
42675
41484
  );
42676
41485
 
42677
41486
  // src/tool_lattice/collection/add_entry.ts
42678
- var import_zod65 = __toESM(require("zod"));
42679
- var import_langchain78 = require("langchain");
41487
+ var import_zod62 = __toESM(require("zod"));
41488
+ var import_langchain74 = require("langchain");
42680
41489
  var import_documents = require("@langchain/core/documents");
42681
41490
  var import_uuid12 = require("uuid");
42682
- var schema3 = import_zod65.default.object({
42683
- collection: import_zod65.default.string().describe("Collection name"),
42684
- content: import_zod65.default.string().describe("Entry content text"),
42685
- metadata: import_zod65.default.record(import_zod65.default.unknown()).optional().describe("Metadata fields matching the collection schema")
41491
+ var schema3 = import_zod62.default.object({
41492
+ collection: import_zod62.default.string().describe("Collection name"),
41493
+ content: import_zod62.default.string().describe("Entry content text"),
41494
+ metadata: import_zod62.default.record(import_zod62.default.unknown()).optional().describe("Metadata fields matching the collection schema")
42686
41495
  });
42687
41496
  function key2(t, n) {
42688
41497
  return `${t}:${n}`;
42689
41498
  }
42690
- var createAddEntryTool = (scope = { collectionKeys: [], connectAll: true }) => (0, import_langchain78.tool)(
41499
+ var createAddEntryTool = (scope = { collectionKeys: [], connectAll: true }) => (0, import_langchain74.tool)(
42691
41500
  async (input, _exeConfig) => {
42692
41501
  try {
42693
41502
  const scopeError = validateCollectionScope(input.collection, _exeConfig, scope);
@@ -42719,18 +41528,18 @@ var createAddEntryTool = (scope = { collectionKeys: [], connectAll: true }) => (
42719
41528
  );
42720
41529
 
42721
41530
  // src/tool_lattice/collection/update_entry.ts
42722
- var import_zod66 = __toESM(require("zod"));
42723
- var import_langchain79 = require("langchain");
42724
- var schema4 = import_zod66.default.object({
42725
- collection: import_zod66.default.string().describe("Collection name"),
42726
- entryId: import_zod66.default.string().describe("Entry ID to update"),
42727
- content: import_zod66.default.string().optional().describe("New content"),
42728
- metadata: import_zod66.default.record(import_zod66.default.unknown()).optional().describe("New metadata")
41531
+ var import_zod63 = __toESM(require("zod"));
41532
+ var import_langchain75 = require("langchain");
41533
+ var schema4 = import_zod63.default.object({
41534
+ collection: import_zod63.default.string().describe("Collection name"),
41535
+ entryId: import_zod63.default.string().describe("Entry ID to update"),
41536
+ content: import_zod63.default.string().optional().describe("New content"),
41537
+ metadata: import_zod63.default.record(import_zod63.default.unknown()).optional().describe("New metadata")
42729
41538
  });
42730
41539
  function key3(t, n) {
42731
41540
  return `${t}:${n}`;
42732
41541
  }
42733
- var createUpdateEntryTool = (scope = { collectionKeys: [], connectAll: true }) => (0, import_langchain79.tool)(
41542
+ var createUpdateEntryTool = (scope = { collectionKeys: [], connectAll: true }) => (0, import_langchain75.tool)(
42734
41543
  async (input, _exeConfig) => {
42735
41544
  try {
42736
41545
  const scopeError = validateCollectionScope(input.collection, _exeConfig, scope);
@@ -42751,16 +41560,16 @@ var createUpdateEntryTool = (scope = { collectionKeys: [], connectAll: true }) =
42751
41560
  );
42752
41561
 
42753
41562
  // src/tool_lattice/collection/delete_entry.ts
42754
- var import_zod67 = __toESM(require("zod"));
42755
- var import_langchain80 = require("langchain");
42756
- var schema5 = import_zod67.default.object({
42757
- collection: import_zod67.default.string().describe("Collection name"),
42758
- entryId: import_zod67.default.string().describe("Entry ID to delete")
41563
+ var import_zod64 = __toESM(require("zod"));
41564
+ var import_langchain76 = require("langchain");
41565
+ var schema5 = import_zod64.default.object({
41566
+ collection: import_zod64.default.string().describe("Collection name"),
41567
+ entryId: import_zod64.default.string().describe("Entry ID to delete")
42759
41568
  });
42760
41569
  function key4(t, n) {
42761
41570
  return `${t}:${n}`;
42762
41571
  }
42763
- var createDeleteEntryTool = (scope = { collectionKeys: [], connectAll: true }) => (0, import_langchain80.tool)(
41572
+ var createDeleteEntryTool = (scope = { collectionKeys: [], connectAll: true }) => (0, import_langchain76.tool)(
42764
41573
  async (input, _exeConfig) => {
42765
41574
  try {
42766
41575
  const scopeError = validateCollectionScope(input.collection, _exeConfig, scope);
@@ -42780,7 +41589,7 @@ var createDeleteEntryTool = (scope = { collectionKeys: [], connectAll: true }) =
42780
41589
  function createCollectionMiddleware(params) {
42781
41590
  const { collectionKeys, connectAll, compileStableCandidateTools = false } = params;
42782
41591
  if (!compileStableCandidateTools && !connectAll && (!collectionKeys || collectionKeys.length === 0)) {
42783
- return (0, import_langchain81.createMiddleware)({
41592
+ return (0, import_langchain77.createMiddleware)({
42784
41593
  name: "collectionMiddleware",
42785
41594
  contextSchema,
42786
41595
  tools: [
@@ -42790,7 +41599,7 @@ function createCollectionMiddleware(params) {
42790
41599
  });
42791
41600
  }
42792
41601
  const toolParams = { collectionKeys, connectAll };
42793
- return (0, import_langchain81.createMiddleware)({
41602
+ return (0, import_langchain77.createMiddleware)({
42794
41603
  name: "collectionMiddleware",
42795
41604
  contextSchema,
42796
41605
  tools: [
@@ -42853,24 +41662,24 @@ var collectionPlugin = {
42853
41662
  };
42854
41663
 
42855
41664
  // src/middlewares/askUserClarifyMiddleware.ts
42856
- var import_langchain83 = require("langchain");
42857
- var import_langgraph14 = require("@langchain/langgraph");
41665
+ var import_langchain79 = require("langchain");
41666
+ var import_langgraph15 = require("@langchain/langgraph");
42858
41667
 
42859
41668
  // src/tool_lattice/ask_user_to_clarify/index.ts
42860
- var import_langchain82 = require("langchain");
42861
- var import_zod68 = __toESM(require("zod"));
42862
- var questionSchema = import_zod68.default.object({
42863
- question: import_zod68.default.string().describe("The question text to ask the user. MUST include the specific context, options, or details being clarified \u2014 never use a bare generic label. Good: 'Confirm the plan: use Redis cache + PostgreSQL primary, split microservices as needed?' Bad: 'Confirm the plan?'"),
42864
- options: import_zod68.default.array(import_zod68.default.string()).optional().default([]).describe("List of EXACT, selectable values. Maximum 3 options allowed. DO NOT include placeholder values like 'Other' or 'Enter manually'. For free-text with predefined choices, use allowOther=true (works with 'single' and 'multiple'). For pure free-text without choices, use type='input' instead. For file_upload and input, pass an empty array."),
42865
- type: import_zod68.default.enum(["single", "multiple", "file_upload", "input"]).describe("The question format. 'single' = pick one from options (default, see tool description for guidance). 'multiple' = pick several from options. 'input' = free-text field (only when options cannot express the answer). 'file_upload' = file picker."),
42866
- required: import_zod68.default.boolean().optional().default(false).describe("Whether this question must be answered"),
42867
- allowOther: import_zod68.default.boolean().optional().default(true).describe("Set to true to append an 'Other' checkbox with a free-text input field. Works with 'single' and 'multiple' types. Use for open-ended answers or when the options cannot cover all possibilities. Not applicable for 'input' or 'file_upload' types.")
41669
+ var import_langchain78 = require("langchain");
41670
+ var import_zod65 = __toESM(require("zod"));
41671
+ var questionSchema = import_zod65.default.object({
41672
+ question: import_zod65.default.string().describe("The question text to ask the user. MUST include the specific context, options, or details being clarified \u2014 never use a bare generic label. Good: 'Confirm the plan: use Redis cache + PostgreSQL primary, split microservices as needed?' Bad: 'Confirm the plan?'"),
41673
+ options: import_zod65.default.array(import_zod65.default.string()).optional().default([]).describe("List of EXACT, selectable values. Maximum 3 options allowed. DO NOT include placeholder values like 'Other' or 'Enter manually'. For free-text with predefined choices, use allowOther=true (works with 'single' and 'multiple'). For pure free-text without choices, use type='input' instead. For file_upload and input, pass an empty array."),
41674
+ type: import_zod65.default.enum(["single", "multiple", "file_upload", "input"]).describe("The question format. 'single' = pick one from options (default, see tool description for guidance). 'multiple' = pick several from options. 'input' = free-text field (only when options cannot express the answer). 'file_upload' = file picker."),
41675
+ required: import_zod65.default.boolean().optional().default(false).describe("Whether this question must be answered"),
41676
+ allowOther: import_zod65.default.boolean().optional().default(true).describe("Set to true to append an 'Other' checkbox with a free-text input field. Works with 'single' and 'multiple' types. Use for open-ended answers or when the options cannot cover all possibilities. Not applicable for 'input' or 'file_upload' types.")
42868
41677
  });
42869
- var inputSchema = import_zod68.default.object({
42870
- questions: import_zod68.default.array(questionSchema).min(1, "At least one question is required").describe("A structured sequence of clarification questions. Use these to gather missing parameters or disambiguate user intent before proceeding.")
41678
+ var inputSchema = import_zod65.default.object({
41679
+ questions: import_zod65.default.array(questionSchema).min(1, "At least one question is required").describe("A structured sequence of clarification questions. Use these to gather missing parameters or disambiguate user intent before proceeding.")
42871
41680
  });
42872
41681
  function createAskUserToClarifyTool() {
42873
- return (0, import_langchain82.tool)(
41682
+ return (0, import_langchain78.tool)(
42874
41683
  async (input) => {
42875
41684
  return JSON.stringify(input);
42876
41685
  },
@@ -42895,7 +41704,7 @@ function isProjectRoomRun(request) {
42895
41704
  return isRecord9(runConfig?.projectRoom);
42896
41705
  }
42897
41706
  function createAskUserClarifyMiddleware() {
42898
- return (0, import_langchain83.createMiddleware)({
41707
+ return (0, import_langchain79.createMiddleware)({
42899
41708
  name: "AskUserClarifyMiddleware",
42900
41709
  tools: [createAskUserToClarifyTool()],
42901
41710
  wrapToolCall: async (request, handler) => {
@@ -42905,7 +41714,7 @@ function createAskUserClarifyMiddleware() {
42905
41714
  return handler(request);
42906
41715
  }
42907
41716
  if (isProjectRoomRun(request)) {
42908
- return new import_langchain83.ToolMessage({
41717
+ return new import_langchain79.ToolMessage({
42909
41718
  content: "You are replying inside a project room, which has no interactive clarification UI. Ask your clarifying questions directly in your reply text and stop; the user's next room message will continue the conversation.",
42910
41719
  tool_call_id: toolCall?.id,
42911
41720
  name: toolName2
@@ -42913,7 +41722,7 @@ function createAskUserClarifyMiddleware() {
42913
41722
  }
42914
41723
  const parsed = inputSchema.safeParse(toolCall?.args);
42915
41724
  if (!parsed.success) {
42916
- return new import_langchain83.ToolMessage({
41725
+ return new import_langchain79.ToolMessage({
42917
41726
  content: `Invalid clarify tool arguments: ${parsed.error.message}`,
42918
41727
  tool_call_id: toolCall?.id,
42919
41728
  name: toolName2
@@ -42930,10 +41739,10 @@ function createAskUserClarifyMiddleware() {
42930
41739
  }))
42931
41740
  };
42932
41741
  const md = genUIMarkdown("clarify", uiData);
42933
- const result = await (0, import_langgraph14.interrupt)(md);
41742
+ const result = await (0, import_langgraph15.interrupt)(md);
42934
41743
  const response = result.data;
42935
41744
  if (!response?.answers || response.answers.length === 0) {
42936
- return new import_langchain83.ToolMessage({
41745
+ return new import_langchain79.ToolMessage({
42937
41746
  content: "No clarification questions were answered.",
42938
41747
  tool_call_id: toolCall?.id,
42939
41748
  name: toolName2
@@ -42943,7 +41752,7 @@ function createAskUserClarifyMiddleware() {
42943
41752
  (answer) => (answer.selectedOptions?.length ?? 0) > 0 || answer.otherText && answer.otherText.trim() !== "" || answer.filePath && answer.filePath.trim() !== ""
42944
41753
  );
42945
41754
  if (answeredQuestions.length === 0) {
42946
- return new import_langchain83.ToolMessage({
41755
+ return new import_langchain79.ToolMessage({
42947
41756
  content: "No clarification questions were answered.",
42948
41757
  tool_call_id: toolCall?.id,
42949
41758
  name: toolName2
@@ -42973,7 +41782,7 @@ function createAskUserClarifyMiddleware() {
42973
41782
  }
42974
41783
  lines.push("");
42975
41784
  }
42976
- return new import_langchain83.ToolMessage({
41785
+ return new import_langchain79.ToolMessage({
42977
41786
  content: lines.join("\n"),
42978
41787
  tool_call_id: toolCall?.id,
42979
41788
  name: toolName2
@@ -42999,11 +41808,11 @@ var askUserClarifyPlugin = {
42999
41808
  };
43000
41809
 
43001
41810
  // src/middlewares/widgetMiddleware.ts
43002
- var import_langchain86 = require("langchain");
41811
+ var import_langchain82 = require("langchain");
43003
41812
 
43004
41813
  // src/tool_lattice/widget/loadGuidelines.ts
43005
- var import_langchain84 = require("langchain");
43006
- var import_zod69 = require("zod");
41814
+ var import_langchain80 = require("langchain");
41815
+ var import_zod66 = require("zod");
43007
41816
 
43008
41817
  // src/middlewares/guidelines/index.ts
43009
41818
  var CORE = `# Imagine \u2014 Visual Creation Suite
@@ -43794,13 +42603,13 @@ function getGuidelines(modules) {
43794
42603
  var AVAILABLE_MODULES = Object.keys(MODULE_SECTIONS);
43795
42604
 
43796
42605
  // src/tool_lattice/widget/loadGuidelines.ts
43797
- var LoadGuidelinesInputSchema = import_zod69.z.object({
43798
- modules: import_zod69.z.array(import_zod69.z.string()).describe(
42606
+ var LoadGuidelinesInputSchema = import_zod66.z.object({
42607
+ modules: import_zod66.z.array(import_zod66.z.string()).describe(
43799
42608
  "Which design modules to load. Choose all that apply. Available modules: [" + AVAILABLE_MODULES.join(",") + "]"
43800
42609
  )
43801
42610
  });
43802
42611
  function createLoadGuidelinesTool() {
43803
- return (0, import_langchain84.tool)(
42612
+ return (0, import_langchain80.tool)(
43804
42613
  async (input) => {
43805
42614
  const result = getGuidelines(input.modules);
43806
42615
  return result;
@@ -43814,8 +42623,8 @@ function createLoadGuidelinesTool() {
43814
42623
  }
43815
42624
 
43816
42625
  // src/tool_lattice/widget/showWidget.ts
43817
- var import_langchain85 = require("langchain");
43818
- var import_zod70 = require("zod");
42626
+ var import_langchain81 = require("langchain");
42627
+ var import_zod67 = require("zod");
43819
42628
  function containsForbiddenTags(code) {
43820
42629
  const forbiddenPatterns = [
43821
42630
  /<!DOCTYPE/i,
@@ -43837,20 +42646,20 @@ function validateWidgetCode(code) {
43837
42646
  }
43838
42647
  return { valid: true };
43839
42648
  }
43840
- var ShowWidgetInputSchema = import_zod70.z.object({
43841
- i_have_seen_guidelines: import_zod70.z.boolean().describe(
42649
+ var ShowWidgetInputSchema = import_zod67.z.object({
42650
+ i_have_seen_guidelines: import_zod67.z.boolean().describe(
43842
42651
  "Must be true. Confirm you have called load_guidelines first."
43843
42652
  ),
43844
- title: import_zod70.z.string().describe("Title displayed above the widget"),
43845
- loading_messages: import_zod70.z.array(import_zod70.z.string()).optional().describe(
42653
+ title: import_zod67.z.string().describe("Title displayed above the widget"),
42654
+ loading_messages: import_zod67.z.array(import_zod67.z.string()).optional().describe(
43846
42655
  "1-4 short strings shown while the widget renders"
43847
42656
  ),
43848
- widget_code: import_zod70.z.string().describe(
42657
+ widget_code: import_zod67.z.string().describe(
43849
42658
  "HTML fragment to render. Rules: 1. No DOCTYPE, <html>, <head>, or <body> tags. 2. Order: <style> block first, then HTML content, then <script> last. 3. Use only CSS variables for colors (e.g. var(--color-accent)). 4. No gradients, shadows, or blur effects. For SVG: start directly with <svg> tag."
43850
42659
  )
43851
42660
  });
43852
42661
  function createShowWidgetTool() {
43853
- return (0, import_langchain85.tool)(
42662
+ return (0, import_langchain81.tool)(
43854
42663
  async (input) => {
43855
42664
  if (!input.i_have_seen_guidelines) {
43856
42665
  return "Error: You must call load_guidelines before using show_widget. Set i_have_seen_guidelines to true only after loading guidelines.";
@@ -43881,7 +42690,7 @@ function createWidgetMiddleware() {
43881
42690
  createLoadGuidelinesTool(),
43882
42691
  createShowWidgetTool()
43883
42692
  ];
43884
- return (0, import_langchain86.createMiddleware)({
42693
+ return (0, import_langchain82.createMiddleware)({
43885
42694
  name: "widgetMiddleware",
43886
42695
  contextSchema,
43887
42696
  tools
@@ -43905,9 +42714,67 @@ var widgetPlugin = {
43905
42714
  };
43906
42715
 
43907
42716
  // src/middlewares/taskMiddleware.ts
43908
- var import_langchain87 = require("langchain");
43909
- var import_zod71 = require("zod");
43910
- var import_langgraph15 = require("@langchain/langgraph");
42717
+ var import_langchain83 = require("langchain");
42718
+ var import_zod68 = require("zod");
42719
+ var import_langgraph16 = require("@langchain/langgraph");
42720
+
42721
+ // src/util/truncateForJson.ts
42722
+ var TRUNCATION_MARKER = "...[truncated]";
42723
+ function truncateString(value, cap) {
42724
+ if (value.length <= cap) return value;
42725
+ const budget = Math.max(0, cap - TRUNCATION_MARKER.length);
42726
+ return value.slice(0, budget) + TRUNCATION_MARKER;
42727
+ }
42728
+ function truncateValue(value, depth, maxDepth, maxEntries, maxStringLength, seen) {
42729
+ if (typeof value === "string") return truncateString(value, maxStringLength);
42730
+ if (value === null || typeof value !== "object") return value;
42731
+ if (depth >= maxDepth) return "[truncated:max-depth]";
42732
+ if (seen.has(value)) return "[Circular]";
42733
+ seen.add(value);
42734
+ try {
42735
+ if (value instanceof Date) return value.toISOString();
42736
+ if (Array.isArray(value)) {
42737
+ const limit2 = Math.min(value.length, maxEntries);
42738
+ const output2 = [];
42739
+ for (let index = 0; index < limit2; index += 1) {
42740
+ output2.push(truncateValue(value[index], depth + 1, maxDepth, maxEntries, maxStringLength, seen));
42741
+ }
42742
+ if (value.length > limit2) output2.push("[truncated:entries]");
42743
+ return output2;
42744
+ }
42745
+ const record = value;
42746
+ const output = {};
42747
+ const keys = Object.keys(record);
42748
+ const limit = Math.min(keys.length, maxEntries);
42749
+ for (let index = 0; index < limit; index += 1) {
42750
+ const key5 = keys[index];
42751
+ output[truncateString(key5, maxStringLength)] = truncateValue(
42752
+ record[key5],
42753
+ depth + 1,
42754
+ maxDepth,
42755
+ maxEntries,
42756
+ maxStringLength,
42757
+ seen
42758
+ );
42759
+ }
42760
+ if (keys.length > limit) output["[truncated]"] = true;
42761
+ return output;
42762
+ } finally {
42763
+ seen.delete(value);
42764
+ }
42765
+ }
42766
+ function truncateForJson(value, options = {}) {
42767
+ return truncateValue(
42768
+ value,
42769
+ 0,
42770
+ options.maxDepth ?? JSON_SAFE_MAX_DEPTH,
42771
+ options.maxEntries ?? JSON_SAFE_MAX_COLLECTION_ENTRIES,
42772
+ options.maxStringLength ?? JSON_SAFE_MAX_STRING_LENGTH,
42773
+ /* @__PURE__ */ new WeakSet()
42774
+ );
42775
+ }
42776
+
42777
+ // src/middlewares/taskMiddleware.ts
43911
42778
  var import_protocols33 = require("@axiom-lattice/protocols");
43912
42779
 
43913
42780
  // src/middlewares/taskResponseSerialization.ts
@@ -44232,6 +43099,132 @@ function getRuntimeActor2(runConfig) {
44232
43099
  if (runConfig.user_id) return `user:${String(runConfig.user_id)}`;
44233
43100
  return void 0;
44234
43101
  }
43102
+ function readRuntimeRunConfig(source) {
43103
+ const s = source;
43104
+ const rc = s?.context?.runConfig ?? s?.configurable?.runConfig;
43105
+ return rc && typeof rc === "object" && !Array.isArray(rc) ? rc : {};
43106
+ }
43107
+ function readExecutionTaskId(runConfig) {
43108
+ const execution = runConfig.execution;
43109
+ if (!execution || typeof execution !== "object" || Array.isArray(execution)) return void 0;
43110
+ const value = execution.taskId;
43111
+ return typeof value === "string" && value.trim() !== "" ? value : void 0;
43112
+ }
43113
+ function renderTaskBinding(taskId) {
43114
+ return `
43115
+
43116
+ ## Bound Task
43117
+
43118
+ You are executing task \`${taskId}\`. Read its contract with \`manage_task get\`, update it as you work, and complete it when done.
43119
+ `;
43120
+ }
43121
+ function createBoundTaskLifecycle() {
43122
+ return createTaskLifecycleService({ taskStore: getTaskStore(), workItemStore: getTaskWorkItemStore() });
43123
+ }
43124
+ function createBoundTaskBridge() {
43125
+ return createTaskRunBridge({ lifecycle: createBoundTaskLifecycle() });
43126
+ }
43127
+ function isResumableInterruption(interruption) {
43128
+ if (!interruption || typeof interruption !== "object" || Array.isArray(interruption)) return false;
43129
+ const type = interruption.type;
43130
+ return type === "missing_input" || type === "user_decision";
43131
+ }
43132
+ var TASK_WORKER_OBSERVATION_MAX_CHARS = 8192;
43133
+ function snapshotMessages(state) {
43134
+ if (!state || typeof state !== "object") return [];
43135
+ const values = state.values;
43136
+ if (!values || typeof values !== "object") return [];
43137
+ const messages = values.messages;
43138
+ return Array.isArray(messages) ? messages : [];
43139
+ }
43140
+ function messageText(value) {
43141
+ if (typeof value === "string") return value;
43142
+ if (!Array.isArray(value)) return void 0;
43143
+ return value.flatMap((part) => {
43144
+ if (typeof part === "string") return [part];
43145
+ if (part && typeof part === "object" && typeof part.text === "string") {
43146
+ return [part.text];
43147
+ }
43148
+ return [];
43149
+ }).join("");
43150
+ }
43151
+ function lastAssistantText(source) {
43152
+ const messages = Array.isArray(source) ? source : source && typeof source === "object" && Array.isArray(source.messages) ? source.messages : snapshotMessages(source);
43153
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
43154
+ const message = messages[index];
43155
+ if (!message || typeof message !== "object") continue;
43156
+ const role = message.role ?? message.type;
43157
+ if (role !== "ai" && role !== "assistant") continue;
43158
+ const text = messageText(message.content);
43159
+ if (text !== void 0) return text;
43160
+ }
43161
+ return void 0;
43162
+ }
43163
+ function boundedWorkerObservation(result, state) {
43164
+ const text = lastAssistantText(state) ?? lastAssistantText(result) ?? "";
43165
+ return {
43166
+ status: "completed",
43167
+ output: truncateForJson(text, { maxStringLength: TASK_WORKER_OBSERVATION_MAX_CHARS })
43168
+ };
43169
+ }
43170
+ var EXECUTOR_CACHE_TTL_MS = 3e4;
43171
+ var executorCache = /* @__PURE__ */ new Map();
43172
+ function executorString(value) {
43173
+ return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
43174
+ }
43175
+ async function renderAvailableExecutors(rc, tenantId2) {
43176
+ const authority = classifyTaskAuthority(rc);
43177
+ const governed = authority.kind === "projectRoom" || authority.kind === "projectTask";
43178
+ const projectId = governed ? (authority.trusted.projectTask ?? authority.trusted.projectRoom)?.projectId : void 0;
43179
+ const cacheKey = `${tenantId2}:${governed ? `project:${projectId ?? ""}` : "ordinary"}`;
43180
+ const cached = executorCache.get(cacheKey);
43181
+ const now = Date.now();
43182
+ if (cached && now - cached.at < EXECUTOR_CACHE_TTL_MS) return cached.text;
43183
+ const lines = [];
43184
+ try {
43185
+ if (governed && projectId) {
43186
+ const store = getStoreLattice("default", "projectBotMembership").store;
43187
+ if (typeof store.list === "function") {
43188
+ const bots = await store.list(tenantId2, projectId);
43189
+ for (const bot of (Array.isArray(bots) ? bots : []).slice(0, 40)) {
43190
+ const row = bot;
43191
+ if (row.status !== "active") continue;
43192
+ const id = executorString(row.assistantId);
43193
+ if (!id) continue;
43194
+ const title = executorString(row.title);
43195
+ const responsibility = executorString(row.responsibility);
43196
+ lines.push(`- ${id}${title ? ` \u2014 ${title}` : ""}${responsibility ? ` (${responsibility})` : ""}`);
43197
+ }
43198
+ }
43199
+ } else {
43200
+ const configs = await agentLatticeManager.getAllAgentConfigsByTenant(tenantId2);
43201
+ for (const config of configs.slice(0, 40)) {
43202
+ const row = config;
43203
+ const id = executorString(row.key);
43204
+ if (!id) continue;
43205
+ const name = executorString(row.name);
43206
+ const description = executorString(row.description);
43207
+ lines.push(`- ${id}${name ? ` \u2014 ${name}` : ""}${description ? ` (${description.slice(0, 120)})` : ""}`);
43208
+ }
43209
+ }
43210
+ } catch {
43211
+ }
43212
+ if (lines.length === 0) {
43213
+ executorCache.set(cacheKey, { at: now, text: "" });
43214
+ return "";
43215
+ }
43216
+ const header = governed ? "## Available task executors (Project roster)" : "## Available task executors";
43217
+ const text = `
43218
+
43219
+ ${header}
43220
+
43221
+ Dispatch \`task\` only to an executor that has the tools the work needs (for example \`update_agent\`/\`create_agent\` for materialization). Never dispatch to the subject agent you are building. Use \`general-purpose\` to run your own capabilities.
43222
+
43223
+ ${lines.join("\n")}
43224
+ `;
43225
+ executorCache.set(cacheKey, { at: now, text });
43226
+ return text;
43227
+ }
44235
43228
  function delegatedTaskScopeError(taskId) {
44236
43229
  return JSON.stringify({
44237
43230
  success: false,
@@ -44599,65 +43592,75 @@ function buildReviewMarkdown(task) {
44599
43592
  result: task.result
44600
43593
  });
44601
43594
  }
44602
- var manageTaskSchema = import_zod71.z.object({
44603
- action: import_zod71.z.enum(["create", "get", "list", "update", "set_status", "add_activity", "delete"]).describe("Action to perform. Available: create, get, list, update, set_status, add_activity, delete. To change status, use set_status. To change content fields, use update."),
44604
- id: import_zod71.z.string().optional().describe("Task ID (required for get, update, add_activity, and delete)"),
44605
- title: import_zod71.z.string().optional().describe("Task title (required for create)"),
44606
- description: import_zod71.z.string().optional().describe("Task description in Markdown"),
44607
- priority: import_zod71.z.enum(["low", "medium", "high"]).optional().describe("Priority level"),
44608
- status: import_zod71.z.enum(["pending", "in_progress", "review", "failed", "interrupted", "completed", "cancelled"]).optional().describe("Task status. For status-only changes, prefer set_status action. Agent summary-only interrupted updates default to missing_input"),
44609
- dueDate: import_zod71.z.string().optional().describe("Due date (ISO 8601 format)"),
44610
- metadata: import_zod71.z.record(import_zod71.z.unknown()).optional().describe("Structured metadata (e.g. projectId, module)"),
44611
- metadataFilter: import_zod71.z.record(
44612
- import_zod71.z.union([import_zod71.z.string(), import_zod71.z.number(), import_zod71.z.boolean()])
43595
+ var manageTaskSchema = import_zod68.z.object({
43596
+ action: import_zod68.z.enum(["create", "get", "list", "update", "set_status", "add_activity", "delete"]).describe("Action to perform. Available: create, get, list, update, set_status, add_activity, delete. To change status, use set_status. To change content fields, use update."),
43597
+ id: import_zod68.z.string().optional().describe("Task ID (required for get, update, add_activity; required for delete unless ids is given)"),
43598
+ title: import_zod68.z.string().optional().describe("Task title (required for create)"),
43599
+ description: import_zod68.z.string().optional().describe("Task description in Markdown"),
43600
+ priority: import_zod68.z.enum(["low", "medium", "high"]).optional().describe("Priority level"),
43601
+ status: import_zod68.z.enum(["pending", "in_progress", "review", "failed", "interrupted", "completed", "cancelled"]).optional().describe("Task status. For status-only changes, prefer set_status action. Set 'in_progress' when you start processing a task you hold; 'completed'/'failed' require the task to be 'in_progress'. Agent summary-only interrupted updates default to missing_input"),
43602
+ dueDate: import_zod68.z.string().optional().describe("Due date (ISO 8601 format)"),
43603
+ metadata: import_zod68.z.record(import_zod68.z.unknown()).optional().describe("Structured metadata (e.g. projectId, module)"),
43604
+ metadataFilter: import_zod68.z.record(
43605
+ import_zod68.z.union([import_zod68.z.string(), import_zod68.z.number(), import_zod68.z.boolean()])
44613
43606
  ).optional().describe("List-only filter. Every key must equal the task metadata value, e.g. {projectId:'p1', retries:2}. Multiple keys AND together."),
44614
- parentId: import_zod71.z.string().optional().describe("Parent task ID for grouping subtasks"),
44615
- sourceId: import_zod71.z.string().optional().describe("Source session/thread ID"),
44616
- context: import_zod71.z.record(import_zod71.z.unknown()).optional().describe("Additional context data"),
44617
- ownerType: import_zod71.z.enum(["user", "agent"]).optional().describe("Owner type. Defaults to 'user' if omitted"),
44618
- ownerId: import_zod71.z.string().optional().describe("Owner ID. Auto-filled from current user/agent if omitted"),
44619
- requireReview: import_zod71.z.boolean().optional().describe("If true, agent completion pauses as interrupted(review_required) for HITL approval"),
44620
- dependencies: import_zod71.z.array(import_zod71.z.string()).optional().describe("List of task IDs that must be completed before this task can start"),
44621
- dependencyTaskIds: import_zod71.z.array(import_zod71.z.string().trim().min(1)).optional().describe("Exact blocking task IDs required for an external_dependency interruption"),
44622
- result: import_zod71.z.string().optional().describe("Result summary. Used with set_status status='completed' or update status='completed'"),
44623
- failureReason: import_zod71.z.string().optional().describe("Failure reason. Used with set_status status='failed' or update status='failed'"),
44624
- files: import_zod71.z.array(import_zod71.z.object({
44625
- uri: import_zod71.z.string().describe("Uniquely locates the resource: http(s):// URL, /s/:token share, or sandbox path"),
44626
- name: import_zod71.z.string().optional().describe("Display name"),
44627
- addedBy: import_zod71.z.enum(["user", "agent"]).optional().describe("Who attached the file")
43607
+ parentId: import_zod68.z.string().optional().describe("Parent task ID for grouping subtasks"),
43608
+ sourceId: import_zod68.z.string().optional().describe("Source session/thread ID"),
43609
+ context: import_zod68.z.record(import_zod68.z.unknown()).optional().describe("Additional context data"),
43610
+ ownerType: import_zod68.z.enum(["user", "agent"]).optional().describe("Owner type. Defaults to 'user' if omitted"),
43611
+ ownerId: import_zod68.z.string().optional().describe("Owner ID. Auto-filled from current user/agent if omitted"),
43612
+ requireReview: import_zod68.z.boolean().optional().describe("If true, agent completion pauses as interrupted(review_required) for HITL approval"),
43613
+ dependencies: import_zod68.z.array(import_zod68.z.string()).optional().describe("List of task IDs that must be completed before this task can start"),
43614
+ dependencyTaskIds: import_zod68.z.array(import_zod68.z.string().trim().min(1)).optional().describe("Exact blocking task IDs required for an external_dependency interruption"),
43615
+ result: import_zod68.z.string().optional().describe("Result summary. Used with set_status status='completed' or update status='completed'"),
43616
+ failureReason: import_zod68.z.string().optional().describe("Failure reason. Used with set_status status='failed' or update status='failed'"),
43617
+ files: import_zod68.z.array(import_zod68.z.object({
43618
+ uri: import_zod68.z.string().describe("Uniquely locates the resource: http(s):// URL, /s/:token share, or sandbox path"),
43619
+ name: import_zod68.z.string().optional().describe("Display name"),
43620
+ addedBy: import_zod68.z.enum(["user", "agent"]).optional().describe("Who attached the file")
44628
43621
  })).optional().describe("File references attached to this task"),
44629
- beliefImpact: import_zod71.z.array(import_zod71.z.object({
44630
- key: import_zod71.z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
44631
- after: import_zod71.z.number().int().min(0).max(100),
44632
- basis: import_zod71.z.string().trim().min(1).max(1e3),
44633
- isNew: import_zod71.z.boolean().optional().describe("Set true only to add a belief key that is absent from the belief owner's Belief State; omit for keys that already exist")
43622
+ beliefImpact: import_zod68.z.array(import_zod68.z.object({
43623
+ key: import_zod68.z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
43624
+ after: import_zod68.z.number().int().min(0).max(100),
43625
+ basis: import_zod68.z.string().trim().min(1).max(1e3),
43626
+ isNew: import_zod68.z.boolean().optional().describe("Set true only to add a belief key that is absent from the belief owner's Belief State; omit for keys that already exist")
44634
43627
  })).optional().describe("Structured belief reports required when an agent-owned task completes; existing keys update the belief owner's table, and a brand-new key must be declared with isNew: true"),
44635
- content: import_zod71.z.string().optional().describe("Markdown content required for add_activity"),
44636
- summary: import_zod71.z.string().optional().describe("Brief summary of the operation"),
44637
- executionResultId: import_zod71.z.string().refine(import_protocols33.isExecutionResultEventKey, {
43628
+ content: import_zod68.z.string().optional().describe("Markdown content required for add_activity"),
43629
+ summary: import_zod68.z.string().optional().describe("Brief summary of the operation"),
43630
+ executionResultId: import_zod68.z.string().refine(import_protocols33.isExecutionResultEventKey, {
44638
43631
  message: "executionResultId must be the execution-result:<threadId> event key returned by task()"
44639
43632
  }).optional().describe(
44640
43633
  "Canonical ASCII `execution-result:<suffix>` event key returned by task(); the nonempty suffix allows only A-Z, a-z, 0-9, period, underscore, colon, and hyphen, and is not a database row ID"
44641
- )
43634
+ ),
43635
+ ids: import_zod68.z.array(import_zod68.z.string().trim().min(1)).optional().describe("Task IDs to delete in one batch (delete action only). Use with or instead of id.")
44642
43636
  }).superRefine((input, context) => {
44643
43637
  if (input.executionResultId && input.action !== "update" && input.action !== "set_status" && input.action !== "add_activity") {
44644
43638
  context.addIssue({
44645
- code: import_zod71.z.ZodIssueCode.custom,
43639
+ code: import_zod68.z.ZodIssueCode.custom,
44646
43640
  path: ["executionResultId"],
44647
43641
  message: "executionResultId is valid only for update, set_status, or add_activity"
44648
43642
  });
44649
43643
  }
44650
43644
  if (input.metadataFilter && input.action !== "list") {
44651
43645
  context.addIssue({
44652
- code: import_zod71.z.ZodIssueCode.custom,
43646
+ code: import_zod68.z.ZodIssueCode.custom,
44653
43647
  path: ["metadataFilter"],
44654
43648
  message: "metadataFilter is valid only for list"
44655
43649
  });
44656
43650
  }
43651
+ if (input.ids && input.action !== "delete") {
43652
+ context.addIssue({
43653
+ code: import_zod68.z.ZodIssueCode.custom,
43654
+ path: ["ids"],
43655
+ message: "ids is valid only for delete"
43656
+ });
43657
+ }
44657
43658
  });
44658
- var startTaskSchema = import_zod71.z.object({
44659
- taskId: import_zod71.z.string().trim().min(1).describe("ID of the persisted TaskItem to start"),
44660
- agentId: import_zod71.z.string().trim().min(1).describe("ID of the Agent that should execute the task")
43659
+ var startTaskSchema = import_zod68.z.object({
43660
+ taskId: import_zod68.z.string().trim().min(1).describe("ID of the persisted TaskItem to start"),
43661
+ agentId: import_zod68.z.string().trim().min(1).describe(
43662
+ `ID of the Agent that should execute the task. Use "general-purpose" to run the caller's own capabilities as an isolated worker.`
43663
+ )
44661
43664
  });
44662
43665
  function mergeTaskUpdateWarnings(existing, added) {
44663
43666
  const warnings = [...existing ?? [], ...added ?? []];
@@ -44794,6 +43797,49 @@ function createTaskMiddleware(options = {}) {
44794
43797
  }
44795
43798
  const ownerId = input.ownerId || trustedScope?.assistantId || (input.ownerType === "agent" ? rc.assistant_id : null) || rc.user_id;
44796
43799
  const store = getTaskStore();
43800
+ const deleteOneTask = async (id) => {
43801
+ if (delegatedTaskId && id !== delegatedTaskId) {
43802
+ return delegatedTaskScopeError(delegatedTaskId);
43803
+ }
43804
+ const existing = await store.getById(tenantId2, id);
43805
+ if (!existing) {
43806
+ return JSON.stringify({
43807
+ success: false,
43808
+ code: "TASK_NOT_FOUND",
43809
+ error: `Task '${id}' was not found.`,
43810
+ hint: "Use manage_task list to see available tasks and their correct IDs."
43811
+ });
43812
+ }
43813
+ if (!taskMatchesRuntimeScope3(existing, workspaceId, projectId)) {
43814
+ return taskScopeAccessError(id);
43815
+ }
43816
+ if (trustedProject?.projectTask) {
43817
+ const trustedFailure = trustedTaskContextFailure(existing, trustedProject.projectTask);
43818
+ if (trustedFailure) return trustedFailure;
43819
+ }
43820
+ let deleted;
43821
+ if (trustedProject) {
43822
+ const snapshot = taskMutationSnapshot(existing);
43823
+ if (!snapshot) return trustedContextError();
43824
+ try {
43825
+ await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
43826
+ } catch (error) {
43827
+ return projectPolicyError(error);
43828
+ }
43829
+ deleted = await store.deleteIfSnapshot(tenantId2, id, snapshot);
43830
+ } else {
43831
+ deleted = await store.delete(tenantId2, id);
43832
+ }
43833
+ if (!deleted) {
43834
+ return JSON.stringify({
43835
+ success: false,
43836
+ code: "TASK_DELETE_FAILED",
43837
+ error: `Task '${id}' was not found or could not be deleted.`,
43838
+ hint: "Use manage_task list to verify the task exists and you have access to it."
43839
+ });
43840
+ }
43841
+ return JSON.stringify({ success: true, message: `Task '${id}' deleted` });
43842
+ };
44797
43843
  switch (input.action) {
44798
43844
  case "create": {
44799
43845
  if (delegatedTaskId && input.parentId !== delegatedTaskId) {
@@ -44949,9 +43995,6 @@ function createTaskMiddleware(options = {}) {
44949
43995
  hint: "Pass the task ID you want to retrieve"
44950
43996
  });
44951
43997
  }
44952
- if (delegatedTaskId && input.id !== delegatedTaskId) {
44953
- return delegatedTaskScopeError(delegatedTaskId);
44954
- }
44955
43998
  const task = await store.getById(tenantId2, input.id);
44956
43999
  if (!task) {
44957
44000
  return JSON.stringify({
@@ -44997,25 +44040,6 @@ function createTaskMiddleware(options = {}) {
44997
44040
  });
44998
44041
  }
44999
44042
  case "list": {
45000
- if (delegatedTaskId) {
45001
- const delegatedTask = await store.getById(tenantId2, delegatedTaskId);
45002
- if (!delegatedTask || !taskMatchesRuntimeScope3(delegatedTask, workspaceId, projectId)) {
45003
- return serializeTaskReadResponse({ success: true, data: [], count: 0 });
45004
- }
45005
- const children = await store.list({
45006
- tenantId: tenantId2,
45007
- workspaceId,
45008
- projectId,
45009
- parentId: delegatedTaskId,
45010
- metadata: input.metadataFilter
45011
- });
45012
- const scopedChildren = children.filter((child) => child.id !== delegatedTaskId && child.parentId === delegatedTaskId && exactScopeMatch(child, delegatedTask));
45013
- return serializeTaskReadResponse({
45014
- success: true,
45015
- data: [delegatedTask, ...scopedChildren],
45016
- count: scopedChildren.length + 1
45017
- });
45018
- }
45019
44043
  const filter2 = {
45020
44044
  tenantId: tenantId2,
45021
44045
  ownerType: input.ownerType,
@@ -45610,41 +44634,31 @@ function createTaskMiddleware(options = {}) {
45610
44634
  });
45611
44635
  return lifecycleMutationResponse(interrupted);
45612
44636
  }
45613
- if (lifecycle && input.status === "in_progress" && existing.status === "interrupted") {
45614
- await validateExecutionResult();
45615
- const callerError = await revalidateCaller();
45616
- if (callerError) return callerError;
45617
- const resumed = await lifecycle.resumeInterruption({
45618
- tenantId: tenantId2,
45619
- taskId: input.id,
45620
- actor,
45621
- threadId: statusThreadId
45622
- });
45623
- return lifecycleMutationResponse(resumed);
45624
- }
45625
- if (lifecycle && input.status === "in_progress" && existing.status === "pending") {
45626
- await validateExecutionResult();
44637
+ if (lifecycle && input.status === "in_progress") {
45627
44638
  const callerError = await revalidateCaller();
45628
44639
  if (callerError) return callerError;
45629
- const started = await lifecycle.startTask({
45630
- tenantId: tenantId2,
45631
- taskId: input.id,
45632
- actor,
45633
- threadId: statusThreadId
45634
- });
45635
- return lifecycleMutationResponse(started);
45636
- }
45637
- if (lifecycle && input.status === "in_progress" && existing.status === "failed") {
45638
- await validateExecutionResult();
45639
- const callerError = await revalidateCaller();
45640
- if (callerError) return callerError;
45641
- const retried = await lifecycle.retryTask({
44640
+ if (existing.status === "interrupted") {
44641
+ return lifecycleMutationResponse(await lifecycle.resumeInterruption({
44642
+ tenantId: tenantId2,
44643
+ taskId: input.id,
44644
+ actor,
44645
+ threadId: statusThreadId
44646
+ }));
44647
+ }
44648
+ if (existing.status === "failed") {
44649
+ return lifecycleMutationResponse(await lifecycle.retryTask({
44650
+ tenantId: tenantId2,
44651
+ taskId: input.id,
44652
+ actor,
44653
+ threadId: statusThreadId
44654
+ }));
44655
+ }
44656
+ return lifecycleMutationResponse(await lifecycle.startTask({
45642
44657
  tenantId: tenantId2,
45643
44658
  taskId: input.id,
45644
44659
  actor,
45645
44660
  threadId: statusThreadId
45646
- });
45647
- return lifecycleMutationResponse(retried);
44661
+ }));
45648
44662
  }
45649
44663
  const effectiveRequireReview = existing.requireReview === true || input.requireReview === true;
45650
44664
  const candidateReviewInterruption = input.status === "interrupted" && input.context?.interruption && typeof input.context.interruption === "object" && input.context.interruption.type === "review_required" && !!input.result?.trim();
@@ -45711,9 +44725,9 @@ function createTaskMiddleware(options = {}) {
45711
44725
  }
45712
44726
  let response;
45713
44727
  try {
45714
- response = await (0, import_langgraph15.interrupt)(buildReviewMarkdown(submitted.task));
44728
+ response = await (0, import_langgraph16.interrupt)(buildReviewMarkdown(submitted.task));
45715
44729
  } catch (error) {
45716
- if (error instanceof import_langgraph15.GraphInterrupt) throw error;
44730
+ if (error instanceof import_langgraph16.GraphInterrupt) throw error;
45717
44731
  return lifecycleMutationResponse(submitted, { code: "REVIEW_REQUIRED" });
45718
44732
  }
45719
44733
  if (response?.action === "approve") {
@@ -45825,54 +44839,49 @@ function createTaskMiddleware(options = {}) {
45825
44839
  return successfulTaskResponse(input.id, updatedStatus, true);
45826
44840
  }
45827
44841
  case "delete": {
45828
- if (!input.id) {
45829
- return JSON.stringify({
45830
- success: false,
45831
- error: "id is required for delete action",
45832
- hint: "Pass the task ID you want to delete"
45833
- });
45834
- }
45835
- if (delegatedTaskId && input.id !== delegatedTaskId) {
45836
- return delegatedTaskScopeError(delegatedTaskId);
45837
- }
45838
- const existing = await store.getById(tenantId2, input.id);
45839
- if (!existing) {
45840
- return JSON.stringify({
45841
- success: false,
45842
- code: "TASK_NOT_FOUND",
45843
- error: `Task '${input.id}' was not found.`,
45844
- hint: "Use manage_task list to see available tasks and their correct IDs."
45845
- });
45846
- }
45847
- if (!taskMatchesRuntimeScope3(existing, workspaceId, projectId)) {
45848
- return taskScopeAccessError(input.id);
45849
- }
45850
- if (trustedProject?.projectTask) {
45851
- const trustedFailure = trustedTaskContextFailure(existing, trustedProject.projectTask);
45852
- if (trustedFailure) return trustedFailure;
44842
+ const missingTargetError = JSON.stringify({
44843
+ success: false,
44844
+ error: "id or ids is required for delete action",
44845
+ hint: "Pass the task ID(s) you want to delete"
44846
+ });
44847
+ const requestedIds = input.ids && input.ids.length > 0 ? [.../* @__PURE__ */ new Set([...input.id ? [input.id] : [], ...input.ids])] : void 0;
44848
+ if (requestedIds === void 0) {
44849
+ if (!input.id) {
44850
+ return missingTargetError;
44851
+ }
44852
+ return deleteOneTask(input.id);
45853
44853
  }
45854
- let deleted;
45855
- if (trustedProject) {
45856
- const snapshot = taskMutationSnapshot(existing);
45857
- if (!snapshot) return trustedContextError();
44854
+ const deletedIds = [];
44855
+ const failed = [];
44856
+ for (const id of requestedIds) {
44857
+ let raw;
45858
44858
  try {
45859
- await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
44859
+ raw = await deleteOneTask(id);
45860
44860
  } catch (error) {
45861
- return projectPolicyError(error);
44861
+ failed.push({
44862
+ id,
44863
+ code: "TASK_DELETE_FAILED",
44864
+ error: error instanceof Error ? error.message : String(error)
44865
+ });
44866
+ continue;
44867
+ }
44868
+ const result = JSON.parse(raw);
44869
+ if (result.success) {
44870
+ deletedIds.push(id);
44871
+ } else {
44872
+ failed.push({
44873
+ id,
44874
+ ...result.code ? { code: result.code } : {},
44875
+ error: result.error ?? `Task '${id}' could not be deleted.`
44876
+ });
45862
44877
  }
45863
- deleted = await store.deleteIfSnapshot(tenantId2, input.id, snapshot);
45864
- } else {
45865
- deleted = await store.delete(tenantId2, input.id);
45866
- }
45867
- if (!deleted) {
45868
- return JSON.stringify({
45869
- success: false,
45870
- code: "TASK_DELETE_FAILED",
45871
- error: `Task '${input.id}' was not found or could not be deleted.`,
45872
- hint: "Use manage_task list to verify the task exists and you have access to it."
45873
- });
45874
44878
  }
45875
- return JSON.stringify({ success: true, message: `Task '${input.id}' deleted` });
44879
+ return JSON.stringify({
44880
+ success: failed.length === 0,
44881
+ deleted: deletedIds,
44882
+ failed,
44883
+ summary: `${deletedIds.length} of ${requestedIds.length} deleted`
44884
+ });
45876
44885
  }
45877
44886
  default:
45878
44887
  return JSON.stringify({
@@ -45987,23 +44996,29 @@ function createTaskMiddleware(options = {}) {
45987
44996
  error: "Runtime actor identity is required for persistent task execution"
45988
44997
  });
45989
44998
  }
44999
+ const callerAssistantId = rc.assistant_id;
45000
+ const agentId = input.agentId === "general-purpose" && callerAssistantId ? `${callerAssistantId}-general-purpose` : input.agentId;
45990
45001
  const service2 = createTaskExecutionService({
45991
45002
  taskStore: getTaskStore(),
45992
45003
  workItemStore: getTaskWorkItemStore(),
45993
- resolveAgent: async (targetTenantId, agentId) => !!await agentLatticeManager.getOrLoadWithTenant(targetTenantId, agentId),
45994
- resolveTaskCapability: async (targetTenantId, agentId) => agentHasManagedTaskCapability(
45995
- (await agentLatticeManager.getOrLoadWithTenant(targetTenantId, agentId))?.config
45996
- ),
45004
+ resolveAgent: async (targetTenantId, agentId2) => !!await agentLatticeManager.getOrLoadWithTenant(targetTenantId, agentId2),
45997
45005
  invokeAgent: async (invocation) => {
45998
- const worker = new Agent({
45999
- tenant_id: invocation.tenantId,
45006
+ const workerResult = await agentWorkerGraph.invoke({
46000
45007
  assistant_id: invocation.agentId,
46001
45008
  thread_id: invocation.threadId,
46002
- workspace_id: invocation.workspaceId,
46003
- project_id: invocation.projectId,
46004
- custom_run_config: createDelegatedWorkerRunConfig(invocation.taskId)
45009
+ input: { message: invocation.message },
45010
+ runConfig: {
45011
+ ...rc,
45012
+ assistant_id: invocation.agentId,
45013
+ thread_id: invocation.threadId,
45014
+ taskId: invocation.taskId,
45015
+ tenantId: invocation.tenantId,
45016
+ workspaceId: invocation.workspaceId,
45017
+ projectId: invocation.projectId
45018
+ }
46005
45019
  });
46006
- return worker.invoke({ input: { message: invocation.message } });
45020
+ const finalState = workerResult?.finalState;
45021
+ return boundedWorkerObservation(finalState, void 0);
46007
45022
  }
46008
45023
  });
46009
45024
  const trustedCaller = authority.kind === "projectTask" || authority.kind === "projectRoom" ? authority.trusted.projectTask ?? authority.trusted.projectRoom : void 0;
@@ -46012,15 +45027,75 @@ function createTaskMiddleware(options = {}) {
46012
45027
  workspaceId: rc.workspaceId,
46013
45028
  projectId: rc.projectId,
46014
45029
  taskId: input.taskId,
46015
- agentId: input.agentId,
45030
+ agentId,
46016
45031
  actor,
46017
45032
  callerThreadId: rc.thread_id,
46018
45033
  ...trustedCaller ? { callerMembershipId: trustedCaller.membershipId, callerAssistantId: trustedCaller.assistantId } : {}
46019
45034
  }));
46020
45035
  };
46021
- return (0, import_langchain87.createMiddleware)({
45036
+ return (0, import_langchain83.createMiddleware)({
46022
45037
  name: "TaskMiddleware",
46023
45038
  contextSchema,
45039
+ // Persisted between invocations (ADRs: the run↔task binding survives turns).
45040
+ stateSchema: import_zod68.z.object({
45041
+ taskId: import_zod68.z.string().default("")
45042
+ }),
45043
+ // CLAIM: a run that holds a task moves it to in_progress (idempotent).
45044
+ beforeAgent: async (state, runtime) => {
45045
+ const rc = readRuntimeRunConfig(runtime);
45046
+ const bound = typeof state?.taskId === "string" ? state.taskId : "";
45047
+ const taskId = bound || readExecutionTaskId(rc) || "";
45048
+ if (!taskId) return {};
45049
+ if (!taskId) return {};
45050
+ const tenantId2 = rc.tenantId || "default";
45051
+ const threadId = runtime?.configurable?.thread_id;
45052
+ const task = await getTaskStore().getById(tenantId2, taskId);
45053
+ if (!task) return {};
45054
+ const runWorkspaceId = typeof rc.workspaceId === "string" ? rc.workspaceId : void 0;
45055
+ const runProjectId = typeof rc.projectId === "string" ? rc.projectId : void 0;
45056
+ if (task.workspaceId && task.workspaceId !== runWorkspaceId) return {};
45057
+ if (task.projectId && task.projectId !== runProjectId) return {};
45058
+ if (task.status === "completed" || task.status === "failed" || task.status === "cancelled") {
45059
+ return bound ? {} : { taskId };
45060
+ }
45061
+ taskRunRegistry.register(taskId);
45062
+ if (task.status === "pending") {
45063
+ await createBoundTaskBridge().beginRun({
45064
+ tenantId: tenantId2,
45065
+ task,
45066
+ actor: getRuntimeActor2(rc) ?? "system",
45067
+ ...threadId ? { threadId } : {}
45068
+ });
45069
+ } else if (task.status === "interrupted" && isResumableInterruption(task.context?.interruption)) {
45070
+ await createBoundTaskLifecycle().resumeInterruption({
45071
+ tenantId: tenantId2,
45072
+ taskId: task.id,
45073
+ actor: getRuntimeActor2(rc) ?? "system",
45074
+ ...threadId ? { threadId } : {}
45075
+ });
45076
+ }
45077
+ return bound ? {} : { taskId };
45078
+ },
45079
+ // SETTLE: a run that ends without a lifecycle transition converges the task.
45080
+ afterAgent: async (state, runtime) => {
45081
+ const taskId = typeof state?.taskId === "string" ? state.taskId : "";
45082
+ if (!taskId) return {};
45083
+ const rc = readRuntimeRunConfig(runtime);
45084
+ const tenantId2 = rc.tenantId || "default";
45085
+ const threadId = runtime?.configurable?.thread_id;
45086
+ const task = await getTaskStore().getById(tenantId2, taskId);
45087
+ if (task?.status === "in_progress" && task.context?.thread_id === threadId) {
45088
+ await createBoundTaskBridge().settleRun({
45089
+ tenantId: tenantId2,
45090
+ task,
45091
+ actor: getRuntimeActor2(rc) ?? "system",
45092
+ ...threadId ? { threadId } : {},
45093
+ outcome: { kind: "interrupted", summary: "Run ended without a task lifecycle transition" }
45094
+ });
45095
+ }
45096
+ taskRunRegistry.unregister(taskId);
45097
+ return {};
45098
+ },
46024
45099
  wrapModelCall: async (request, handler) => {
46025
45100
  const taskPrompt = `## Task Management
46026
45101
 
@@ -46029,8 +45104,11 @@ ongoing record of a GOAL and its ACCEPTANCE CRITERIA.
46029
45104
 
46030
45105
  ### When to create a task
46031
45106
  - Agent-owned work is multi-step and needs a persistent contract and plan ->
46032
- create the parent task FIRST (a \`pending\` record), then either execute it
46033
- inline and keep the status truthful, or dispatch it with \`task\`.
45107
+ create the parent task FIRST (a \`pending\` record), then process it in this run;
45108
+ mark it \`in_progress\` with \`manage_task set_status\` when you start, and
45109
+ \`completed\` when the acceptance criteria are met. To bring in an
45110
+ expert, create a subtask and dispatch it with \`task { taskId, agentId }\` \u2014 never
45111
+ re-dispatch the task you are processing.
46034
45112
  - Persistence is useful for resumption, review, or visibility across the
46035
45113
  independently verifiable business results.
46036
45114
 
@@ -46060,13 +45138,17 @@ ${TASK_CONVERGENCE_GUIDANCE}
46060
45138
  - No params: ownerType defaults to "user" with current user's ID
46061
45139
  - ownerType="agent": auto-fills ownerId from current agent (subtask for yourself)
46062
45140
  - Explicit ownerId: assign to a specific agent or user`;
45141
+ const boundTaskId = request.state?.taskId;
45142
+ const binding = typeof boundTaskId === "string" && boundTaskId ? renderTaskBinding(boundTaskId) : "";
45143
+ const rc = readRuntimeRunConfig(request.runtime);
45144
+ const executors = await renderAvailableExecutors(rc, rc.tenantId || "default");
46063
45145
  return handler({
46064
45146
  ...request,
46065
- systemPrompt: taskPrompt + "\n\n" + (request.systemPrompt ?? "")
45147
+ systemPrompt: taskPrompt + binding + executors + "\n\n" + (request.systemPrompt ?? "")
46066
45148
  });
46067
45149
  },
46068
45150
  tools: [
46069
- (0, import_langchain87.tool)(
45151
+ (0, import_langchain83.tool)(
46070
45152
  handleManageTask,
46071
45153
  {
46072
45154
  name: "manage_task",
@@ -46087,15 +45169,14 @@ ${TASK_CONVERGENCE_GUIDANCE}
46087
45169
  - update: Update a task's content fields (title/description/priority/dueDate/metadata/parentId/sourceId/context/ownerId/result/failureReason/requireReview/dependencies/files)
46088
45170
  Status changes can also be done here, but use set_status for a simpler dedicated status update.
46089
45171
  - set_status: Change a task's status (id and status required). Use this when you only need to change the status.
46090
- Valid status values: pending, in_progress, review, failed, interrupted, completed, cancelled
46091
- Companion fields: result (for completed), failureReason (for failed), summary (for any status)
46092
- To mark complete: set_status with status='completed', result='...'
45172
+ Start processing a task you hold: set_status with status='in_progress' (the engine binds it to this run's thread).
45173
+ To mark complete: set_status with status='completed', result='...' (the task must be in_progress)
46093
45174
  To mark failed: set_status with status='failed', failureReason='...'
46094
45175
  To pause for input: set_status with status='interrupted', summary='what is needed'
46095
- Status can be freely changed to any valid value \u2014 no restrictions on transitions.
45176
+ Valid status values: pending, in_progress, review, failed, interrupted, completed, cancelled.
46096
45177
  set_status only changes the record; it never dispatches execution (only the \`task\` tool does).
46097
45178
  - add_activity: Add a Markdown activity without changing task fields or status (id and content required)
46098
- - delete: Delete a task (id required)
45179
+ - delete: Delete one task by id, or a batch with ids (best-effort per id; returns deleted/failed lists). At least one of id/ids is required.
46099
45180
 
46100
45181
  ## Agent completion beliefs
46101
45182
  Completing an agent-owned task MAY include a beliefImpact array reporting which
@@ -46106,14 +45187,16 @@ Report existing keys directly; set 'isNew: true' to add a key the owner does not
46106
45187
  track yet. Belief is evidence metadata: it never blocks a completion, and an
46107
45188
  unmatched or malformed entry is recorded without changing the owner's table.
46108
45189
  Create always persists a pending record \u2014 a supplied status is coerced and no
46109
- execution is dispatched. Only dispatching runs a task through the queue; an
46110
- agent may also work inline and update status.`,
45190
+ execution is dispatched. When you start processing a task you hold, set it
45191
+ \`in_progress\` with \`manage_task set_status\`; a dispatched task is claimed
45192
+ automatically by the engine. Use \`task { taskId, agentId }\` to delegate a subtask
45193
+ to an expert \u2014 never re-dispatch the task you are processing.`,
46111
45194
  schema: manageTaskSchema
46112
45195
  }
46113
45196
  ),
46114
- (0, import_langchain87.tool)(handleStartTask, {
45197
+ (0, import_langchain83.tool)(handleStartTask, {
46115
45198
  name: "task",
46116
- description: "Start a persisted TaskItem with any Agent in a fresh isolated thread. An ordinary task returns an observation plus executionResultId that the caller passes to the manage_task update or add_activity that interprets it; a project task returns a managed result (success:true, managed:true) because the project-lifecycle queue owns execution.",
45199
+ description: `Start a persisted TaskItem with any existing Agent in a fresh isolated thread. Use this to delegate work \u2014 dispatch a subtask you created to the agent that should execute it; never re-dispatch the task you are currently processing (give the expert a child task instead). Pass agentId "general-purpose" for the general-purpose worker \u2014 ${DEFAULT_GENERAL_PURPOSE_DESCRIPTION} It has access to all the caller's tools, model, and middleware, so use it for general-purpose subtasks, to isolate context and token usage, and whenever no specialized agent fits. The target does NOT need task-management tools: it runs and returns an observation plus an executionResultId, and the caller passes that executionResultId to the manage_task update or add_activity that interprets and records it. A project task instead returns a managed result (success:true, managed:true) because the project-lifecycle queue owns execution.`,
46117
45200
  schema: startTaskSchema
46118
45201
  })
46119
45202
  ]
@@ -46256,7 +45339,7 @@ canonical Belief State:
46256
45339
 
46257
45340
  // src/middlewares/documentLearningMiddleware.ts
46258
45341
  var import_protocols34 = require("@axiom-lattice/protocols");
46259
- var import_langchain88 = require("langchain");
45342
+ var import_langchain84 = require("langchain");
46260
45343
 
46261
45344
  // src/middlewares/documentLearningSkills.ts
46262
45345
  var LEARN_CAPABILITY_SKILL = `---
@@ -46495,7 +45578,7 @@ patterns discovered, recommendations. Include validation coverage: user-sample N
46495
45578
  `;
46496
45579
 
46497
45580
  // src/middlewares/documentLearningMiddleware.ts
46498
- var createDocumentLearningMiddleware = () => (0, import_langchain88.createMiddleware)({
45581
+ var createDocumentLearningMiddleware = () => (0, import_langchain84.createMiddleware)({
46499
45582
  name: "DocumentLearningMiddleware",
46500
45583
  contextSchema,
46501
45584
  tools: []
@@ -46613,12 +45696,12 @@ var documentLearningPlugin = {
46613
45696
  };
46614
45697
 
46615
45698
  // src/middlewares/documentParserMiddleware.ts
46616
- var import_langchain90 = require("langchain");
45699
+ var import_langchain86 = require("langchain");
46617
45700
 
46618
45701
  // src/tool_lattice/document_parser/index.ts
46619
45702
  var path7 = __toESM(require("path"));
46620
- var import_zod72 = __toESM(require("zod"));
46621
- var import_langchain89 = require("langchain");
45703
+ var import_zod69 = __toESM(require("zod"));
45704
+ var import_langchain85 = require("langchain");
46622
45705
  var PARSE_DOCUMENT_DESCRIPTION = `Parse a document file (docx, pdf) into structured Markdown using a remote document parsing service.
46623
45706
  This tool handles the full pipeline internally: file upload \u2192 document parsing \u2192 polling until complete \u2192 download result \u2192 save to filesystem.
46624
45707
 
@@ -46741,7 +45824,7 @@ function createParseDocumentTool({
46741
45824
  baseUrl = "",
46742
45825
  apiKey = ""
46743
45826
  }) {
46744
- return (0, import_langchain89.tool)(
45827
+ return (0, import_langchain85.tool)(
46745
45828
  async (input, exe_config) => {
46746
45829
  try {
46747
45830
  const runConfig = exe_config?.configurable?.runConfig ?? { assistant_id: "", thread_id: "" };
@@ -46812,17 +45895,17 @@ function createParseDocumentTool({
46812
45895
  {
46813
45896
  name: "parse_document",
46814
45897
  description: PARSE_DOCUMENT_DESCRIPTION,
46815
- schema: import_zod72.default.object({
46816
- file_path: import_zod72.default.string().describe(
45898
+ schema: import_zod69.default.object({
45899
+ file_path: import_zod69.default.string().describe(
46817
45900
  'Absolute path to the document file. Must point to an existing .docx or .pdf file. Example: "/project/reports/contract.docx". The file must be accessible from the current workspace.'
46818
45901
  ),
46819
- engine: import_zod72.default.string().describe(
45902
+ engine: import_zod69.default.string().describe(
46820
45903
  'Parsing engine to use. Available options: "textin" (recommended, works with local files, supports docx/pdf), "datalab" (alternative engine for docx/pdf), "mineru" (requires public URL, use only if textin/datalab fail), "paddleocr_remote" (PaddleOCR, good for scanned documents), "qwen_ocr" (OCR-focused, best for image-heavy PDFs).'
46821
45904
  ),
46822
- output_path: import_zod72.default.string().optional().describe(
45905
+ output_path: import_zod69.default.string().optional().describe(
46823
45906
  'Path to save the parsed result. If not specified, the input extension is replaced with .md. Example: "/project/report.docx" becomes "/project/report.md". Parent directories are created automatically.'
46824
45907
  ),
46825
- output_format: import_zod72.default.enum(["markdown", "json"]).optional().default("markdown").describe(
45908
+ output_format: import_zod69.default.enum(["markdown", "json"]).optional().default("markdown").describe(
46826
45909
  'Output format. "markdown": structured Markdown with tables, headers, formatting preserved (recommended). "json": raw JSON output from the parsing engine (for programmatic use).'
46827
45910
  )
46828
45911
  })
@@ -47240,7 +46323,7 @@ def main() -> None:
47240
46323
  if __name__ == "__main__":
47241
46324
  main()
47242
46325
  `;
47243
- var resources2 = {
46326
+ var resources = {
47244
46327
  "references/api_reference.md": { mimeType: "text/markdown", content: `# API reference
47245
46328
 
47246
46329
  The supported command-line form is 'markitdown input -o output.md'. The Python API uses 'MarkItDown().convert(path)' upstream, but this runtime prefers the installed CLI and does not provide direct Python SDK LLM calls. Use local conversion for local files and keep output as Markdown.` },
@@ -47269,7 +46352,7 @@ Single file: 'markitdown input -o output.md'. Ordinary directory: 'scripts/batch
47269
46352
  var DOCUMENT_PARSER_MARKITDOWN_SKILL = {
47270
46353
  version: "1.1.0",
47271
46354
  content: MARKITDOWN_SKILL_CONTENT,
47272
- resources: resources2
46355
+ resources
47273
46356
  };
47274
46357
 
47275
46358
  // src/middlewares/documentParserMiddleware.ts
@@ -47278,7 +46361,7 @@ function createDocumentParserMiddleware(config) {
47278
46361
  const baseUrl = config.baseUrl || "";
47279
46362
  const apiKey = config.apiKey || "";
47280
46363
  const connections = Array.isArray(config.connections) ? config.connections.filter((key5) => typeof key5 === "string") : [];
47281
- return (0, import_langchain90.createMiddleware)({
46364
+ return (0, import_langchain86.createMiddleware)({
47282
46365
  name: "DocumentParser",
47283
46366
  contextSchema,
47284
46367
  tools: [createParseDocumentTool({ connectAll, connections, baseUrl, apiKey })]
@@ -47394,8 +46477,8 @@ var documentParserPlugin = {
47394
46477
  // src/middlewares/projectRoomMiddleware.ts
47395
46478
  var import_crypto10 = require("crypto");
47396
46479
  var import_protocols36 = require("@axiom-lattice/protocols");
47397
- var import_langchain91 = require("langchain");
47398
- var import_zod73 = require("zod");
46480
+ var import_langchain87 = require("langchain");
46481
+ var import_zod70 = require("zod");
47399
46482
  var PROJECT_ROOM_CONTEXT_REQUIRED = "PROJECT_ROOM_CONTEXT_REQUIRED";
47400
46483
  var PROJECT_ROOM_POST_FAILED = "PROJECT_ROOM_POST_FAILED";
47401
46484
  var PROJECT_ROOM_ROSTER_FAILED = "PROJECT_ROOM_ROSTER_FAILED";
@@ -47415,10 +46498,10 @@ var ROSTER_FAILED = JSON.stringify({
47415
46498
  error: PROJECT_ROOM_ROSTER_FAILED,
47416
46499
  message: PROJECT_ROOM_ROSTER_FAILED_MESSAGE
47417
46500
  });
47418
- var postSchema = import_zod73.z.object({
47419
- text: import_zod73.z.string().trim().min(1).max(2e4)
46501
+ var postSchema = import_zod70.z.object({
46502
+ text: import_zod70.z.string().trim().min(1).max(2e4)
47420
46503
  }).strict();
47421
- var listSchema = import_zod73.z.object({}).strict();
46504
+ var listSchema = import_zod70.z.object({}).strict();
47422
46505
  function ownDataValue2(record, key5) {
47423
46506
  if (typeof record !== "object" || record === null || Array.isArray(record)) return void 0;
47424
46507
  try {
@@ -47485,10 +46568,10 @@ async function hasActiveCurrentMembership(scope) {
47485
46568
  return true;
47486
46569
  }
47487
46570
  function createProjectRoomMiddleware() {
47488
- return (0, import_langchain91.createMiddleware)({
46571
+ return (0, import_langchain87.createMiddleware)({
47489
46572
  name: "ProjectRoomMiddleware",
47490
46573
  tools: [
47491
- (0, import_langchain91.tool)(async (input, config) => {
46574
+ (0, import_langchain87.tool)(async (input, config) => {
47492
46575
  const { text } = input;
47493
46576
  const scope = readTrustedRoomScope(config);
47494
46577
  if (!scope) return CONTEXT_REQUIRED;
@@ -47519,7 +46602,7 @@ function createProjectRoomMiddleware() {
47519
46602
  description: "Post a text reply to the current trusted Project Room message",
47520
46603
  schema: postSchema
47521
46604
  }),
47522
- (0, import_langchain91.tool)(async (_input, config) => {
46605
+ (0, import_langchain87.tool)(async (_input, config) => {
47523
46606
  const scope = readTrustedRoomScope(config);
47524
46607
  if (!scope) return CONTEXT_REQUIRED;
47525
46608
  try {
@@ -47561,8 +46644,8 @@ var projectRoomPlugin = {
47561
46644
  };
47562
46645
 
47563
46646
  // src/middlewares/sandboxPluginsMiddleware.ts
47564
- var import_langchain92 = require("langchain");
47565
- var import_zod74 = require("zod");
46647
+ var import_langchain88 = require("langchain");
46648
+ var import_zod71 = require("zod");
47566
46649
  var import_protocols37 = require("@axiom-lattice/protocols");
47567
46650
 
47568
46651
  // src/middlewares/sandboxPluginsSkills.ts
@@ -48284,16 +47367,16 @@ function tenantIdFrom(exeConfig) {
48284
47367
  const c = exeConfig;
48285
47368
  return c?.configurable?.runConfig?.tenantId ?? "default";
48286
47369
  }
48287
- var managePluginSchema = import_zod74.z.object({
48288
- action: import_zod74.z.enum(["list", "get", "validate", "create", "update", "delete", "reload", "test"]),
48289
- type: import_zod74.z.string().optional(),
48290
- manifest: import_zod74.z.record(import_zod74.z.unknown()).optional(),
48291
- handlers: import_zod74.z.record(import_zod74.z.string()).optional(),
48292
- target: import_zod74.z.object({
48293
- kind: import_zod74.z.enum(["tool", "connection-test", "connection-discover"]),
48294
- name: import_zod74.z.string().optional(),
48295
- input: import_zod74.z.unknown().optional(),
48296
- connectionKey: import_zod74.z.string().optional()
47370
+ var managePluginSchema = import_zod71.z.object({
47371
+ action: import_zod71.z.enum(["list", "get", "validate", "create", "update", "delete", "reload", "test"]),
47372
+ type: import_zod71.z.string().optional(),
47373
+ manifest: import_zod71.z.record(import_zod71.z.unknown()).optional(),
47374
+ handlers: import_zod71.z.record(import_zod71.z.string()).optional(),
47375
+ target: import_zod71.z.object({
47376
+ kind: import_zod71.z.enum(["tool", "connection-test", "connection-discover"]),
47377
+ name: import_zod71.z.string().optional(),
47378
+ input: import_zod71.z.unknown().optional(),
47379
+ connectionKey: import_zod71.z.string().optional()
48297
47380
  }).optional()
48298
47381
  });
48299
47382
  var sandboxPluginsPlugin = {
@@ -48367,10 +47450,10 @@ var sandboxPluginsPlugin = {
48367
47450
  ]
48368
47451
  }
48369
47452
  },
48370
- middleware: () => (0, import_langchain92.createMiddleware)({
47453
+ middleware: () => (0, import_langchain88.createMiddleware)({
48371
47454
  name: "SandboxPluginsMiddleware",
48372
47455
  tools: [
48373
- (0, import_langchain92.tool)(
47456
+ (0, import_langchain88.tool)(
48374
47457
  async (input, exeConfig) => {
48375
47458
  const tenantId2 = tenantIdFrom(exeConfig);
48376
47459
  const catalog2 = getSandboxPluginCatalog();
@@ -48511,7 +47594,6 @@ var BUILTIN_PLUGINS = [
48511
47594
  sqlPlugin,
48512
47595
  skillPlugin,
48513
47596
  metricsPlugin,
48514
- semanticMetricsPlugin,
48515
47597
  askUserClarifyPlugin,
48516
47598
  widgetPlugin,
48517
47599
  clawPlugin,
@@ -49087,6 +48169,7 @@ registerBuiltinPlugins();
49087
48169
  TaskLifecycleNotifier,
49088
48170
  TaskLifecycleService,
49089
48171
  TaskRunBridgeStoresRequiredError,
48172
+ TaskRunRegistry,
49090
48173
  TaskStatus,
49091
48174
  TeamAgentGraphBuilder,
49092
48175
  TenantPluginCatalog,
@@ -49098,7 +48181,6 @@ registerBuiltinPlugins();
49098
48181
  VectorStoreProviderManager,
49099
48182
  VolumeFilesystem,
49100
48183
  abortWorkflowRun,
49101
- agentHasManagedTaskCapability,
49102
48184
  agentInstanceManager,
49103
48185
  agentLatticeManager,
49104
48186
  appendReconciliationWarning,
@@ -49151,7 +48233,6 @@ registerBuiltinPlugins();
49151
48233
  createSandboxProvider,
49152
48234
  createSandboxResolver,
49153
48235
  createSchedulerMiddleware,
49154
- createSemanticMetricsMiddleware,
49155
48236
  createSharePayload,
49156
48237
  createTaskExecutionService,
49157
48238
  createTaskLifecycleService,
@@ -49273,6 +48354,9 @@ registerBuiltinPlugins();
49273
48354
  projectTaskAdmissionNotifier,
49274
48355
  queueLatticeManager,
49275
48356
  readLoopBreakerConfig,
48357
+ reconcileAllTenantTaskRuns,
48358
+ reconcileStaleTaskRuns,
48359
+ reconcileTenantTaskRuns,
49276
48360
  registerAgentLattice,
49277
48361
  registerAgentLatticeWithTenant,
49278
48362
  registerAgentLattices,
@@ -49307,7 +48391,6 @@ registerBuiltinPlugins();
49307
48391
  sandboxLatticeManager,
49308
48392
  sanitizeToolCallId,
49309
48393
  scheduleLatticeManager,
49310
- semanticMetricsPlugin,
49311
48394
  serializePluginMeta,
49312
48395
  serializeTaskMutationSuccess,
49313
48396
  serializeTaskNormalizationFallback,
@@ -49321,6 +48404,7 @@ registerBuiltinPlugins();
49321
48404
  storeLatticeManager,
49322
48405
  sttModelLatticeManager,
49323
48406
  taskLifecycleNotifier,
48407
+ taskRunRegistry,
49324
48408
  toJsonSchema,
49325
48409
  toSafeStateExpr,
49326
48410
  toolLatticeManager,