@axiom-lattice/core 4.3.0 → 4.4.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.mjs CHANGED
@@ -11238,7 +11238,7 @@ function readLoopBreakerConfig(env = process.env) {
11238
11238
  return {
11239
11239
  repeatWarn: parse(env.AGENT_REPEATED_TOOL_CALL_WARN, 3),
11240
11240
  repeatStop: parse(env.AGENT_REPEATED_TOOL_CALL_STOP, 5),
11241
- runLimit: parse(env.AGENT_TOOL_CALL_RUN_LIMIT, 120),
11241
+ runLimit: parse(env.AGENT_TOOL_CALL_RUN_LIMIT, 300),
11242
11242
  skillRunLimit: parse(env.AGENT_SKILL_CALL_RUN_LIMIT, 8)
11243
11243
  };
11244
11244
  }
@@ -14938,6 +14938,41 @@ var AgentManager = class _AgentManager {
14938
14938
  }
14939
14939
  };
14940
14940
 
14941
+ // src/services/TaskExecutionContext.ts
14942
+ var DELEGATED_WORKER_SCOPE_TOKEN = Symbol("delegated-worker-scope");
14943
+ var delegatedWorkerScopeSecret = Object.freeze({});
14944
+ function createDelegatedWorkerRunConfig(taskId) {
14945
+ return {
14946
+ taskId,
14947
+ delegatedTaskId: taskId,
14948
+ taskExecutionRole: "worker",
14949
+ execution: { taskId },
14950
+ [DELEGATED_WORKER_SCOPE_TOKEN]: delegatedWorkerScopeSecret
14951
+ };
14952
+ }
14953
+ function getDelegatedTaskId(runConfig) {
14954
+ 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;
14955
+ }
14956
+ function hasDelegatedWorkerToken(runConfig) {
14957
+ return Object.prototype.hasOwnProperty.call(runConfig, DELEGATED_WORKER_SCOPE_TOKEN);
14958
+ }
14959
+ function preserveDelegatedWorkerContext(source, target) {
14960
+ const delegatedTaskId = getDelegatedTaskId(source);
14961
+ if (!delegatedTaskId) return;
14962
+ target.taskId = delegatedTaskId;
14963
+ target.delegatedTaskId = delegatedTaskId;
14964
+ target.taskExecutionRole = "worker";
14965
+ target.execution = { taskId: delegatedTaskId };
14966
+ target[DELEGATED_WORKER_SCOPE_TOKEN] = delegatedWorkerScopeSecret;
14967
+ }
14968
+ function stripDelegatedWorkerContext(target) {
14969
+ delete target.taskId;
14970
+ delete target.delegatedTaskId;
14971
+ delete target.taskExecutionRole;
14972
+ delete target.execution;
14973
+ delete target[DELEGATED_WORKER_SCOPE_TOKEN];
14974
+ }
14975
+
14941
14976
  // src/agent_worker/agent_worker_graph.ts
14942
14977
  var AgentWorkerState = Annotation.Root({
14943
14978
  // Input parameters
@@ -14962,6 +14997,13 @@ var AgentWorkerState = Annotation.Root({
14962
14997
  reducer: (x, y) => y ?? x,
14963
14998
  default: () => void 0
14964
14999
  }),
15000
+ // Optional persistent TaskItem binding. Rebuilt into an authentic delegated
15001
+ // worker scope on every execute (the in-process scope symbol cannot survive
15002
+ // LangGraph checkpointing, so it is re-derived from this plain task id).
15003
+ taskId: Annotation({
15004
+ reducer: (x, y) => y ?? x,
15005
+ default: () => ""
15006
+ }),
14965
15007
  // Execution result
14966
15008
  result: Annotation({
14967
15009
  reducer: (x, y) => y ?? x,
@@ -14979,14 +15021,15 @@ var AgentWorkerState = Annotation.Root({
14979
15021
  })
14980
15022
  });
14981
15023
  async function executeNode(state) {
14982
- const { assistant_id, thread_id, input, command2, runConfig } = state;
15024
+ const { assistant_id, thread_id, input, command2, runConfig, taskId } = state;
15025
+ const effectiveRunConfig = taskId ? { ...runConfig ?? {}, ...createDelegatedWorkerRunConfig(taskId) } : runConfig;
14983
15026
  const callParams = {
14984
15027
  assistant_id,
14985
15028
  "x-tenant-id": runConfig?.tenantId,
14986
15029
  thread_id,
14987
15030
  input,
14988
15031
  command: command2,
14989
- runConfig
15032
+ runConfig: effectiveRunConfig
14990
15033
  };
14991
15034
  const result = await AgentManager.getInstance().callAgentInQueue(
14992
15035
  callParams,
@@ -16337,38 +16380,6 @@ var CapabilityRuntimeResolver = class {
16337
16380
  }
16338
16381
  };
16339
16382
 
16340
- // src/services/TaskExecutionContext.ts
16341
- var DELEGATED_WORKER_SCOPE_TOKEN = Symbol("delegated-worker-scope");
16342
- var delegatedWorkerScopeSecret = Object.freeze({});
16343
- function createDelegatedWorkerRunConfig(taskId) {
16344
- return {
16345
- taskId,
16346
- delegatedTaskId: taskId,
16347
- taskExecutionRole: "worker",
16348
- [DELEGATED_WORKER_SCOPE_TOKEN]: delegatedWorkerScopeSecret
16349
- };
16350
- }
16351
- function getDelegatedTaskId(runConfig) {
16352
- 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;
16353
- }
16354
- function hasDelegatedWorkerToken(runConfig) {
16355
- return Object.prototype.hasOwnProperty.call(runConfig, DELEGATED_WORKER_SCOPE_TOKEN);
16356
- }
16357
- function preserveDelegatedWorkerContext(source, target) {
16358
- const delegatedTaskId = getDelegatedTaskId(source);
16359
- if (!delegatedTaskId) return;
16360
- target.taskId = delegatedTaskId;
16361
- target.delegatedTaskId = delegatedTaskId;
16362
- target.taskExecutionRole = "worker";
16363
- target[DELEGATED_WORKER_SCOPE_TOKEN] = delegatedWorkerScopeSecret;
16364
- }
16365
- function stripDelegatedWorkerContext(target) {
16366
- delete target.taskId;
16367
- delete target.delegatedTaskId;
16368
- delete target.taskExecutionRole;
16369
- delete target[DELEGATED_WORKER_SCOPE_TOKEN];
16370
- }
16371
-
16372
16383
  // src/services/TrustedAgentDispatchCapability.ts
16373
16384
  var TRUSTED_AGENT_DISPATCH = Symbol("axiom.trustedAgentDispatch");
16374
16385
 
@@ -16532,8 +16543,22 @@ function sanitizeCallerRunConfig(value, preserveDelegatedContext = true) {
16532
16543
  } else {
16533
16544
  stripDelegatedWorkerContext(callerRunConfig);
16534
16545
  }
16546
+ preserveExecutionBinding(value, callerRunConfig);
16535
16547
  return callerRunConfig;
16536
16548
  }
16549
+ function preserveExecutionBinding(source, target) {
16550
+ if (typeof source !== "object" || source === null || Array.isArray(source)) return;
16551
+ const execution = descriptorDataValue(Object.getOwnPropertyDescriptor(source, "execution"))?.value;
16552
+ if (typeof execution !== "object" || execution === null || Array.isArray(execution)) return;
16553
+ const taskId = descriptorDataValue(Object.getOwnPropertyDescriptor(execution, "taskId"))?.value;
16554
+ if (typeof taskId !== "string" || taskId.trim() === "") return;
16555
+ Object.defineProperty(target, "execution", {
16556
+ value: { taskId },
16557
+ enumerable: true,
16558
+ configurable: true,
16559
+ writable: true
16560
+ });
16561
+ }
16537
16562
  function sanitizeExecutionRunConfig(value) {
16538
16563
  return cloneRunConfig(value, false);
16539
16564
  }
@@ -16653,6 +16678,7 @@ function checkpointCapabilityRevision(state) {
16653
16678
  }
16654
16679
  var QUEUE_PROCESSOR_RETRY_BASE_MS = 100;
16655
16680
  var QUEUE_PROCESSOR_MAX_RETRIES = 3;
16681
+ var AGENT_RECURSION_LIMIT = 1e3;
16656
16682
  function hasExactKeys(record, required, optional = []) {
16657
16683
  const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
16658
16684
  return required.every((key5) => Object.prototype.hasOwnProperty.call(record, key5)) && Reflect.ownKeys(record).every((key5) => typeof key5 === "string" && allowed.has(key5));
@@ -16705,7 +16731,7 @@ var Agent = class {
16705
16731
  ...executionRunConfig,
16706
16732
  runConfig: executionRunConfig
16707
16733
  },
16708
- recursionLimit: 200,
16734
+ recursionLimit: AGENT_RECURSION_LIMIT,
16709
16735
  signal
16710
16736
  }
16711
16737
  );
@@ -16780,7 +16806,7 @@ var Agent = class {
16780
16806
  },
16781
16807
  streamMode: ["updates", "messages"],
16782
16808
  subgraphs: false,
16783
- recursionLimit: 200,
16809
+ recursionLimit: AGENT_RECURSION_LIMIT,
16784
16810
  signal
16785
16811
  }
16786
16812
  );
@@ -17278,6 +17304,15 @@ var Agent = class {
17278
17304
  configurable: true,
17279
17305
  writable: true
17280
17306
  });
17307
+ const trustedTaskId = parsed.projectTask?.taskId;
17308
+ if (trustedTaskId) {
17309
+ Object.defineProperty(base, "execution", {
17310
+ value: { taskId: trustedTaskId },
17311
+ enumerable: true,
17312
+ configurable: true,
17313
+ writable: true
17314
+ });
17315
+ }
17281
17316
  return base;
17282
17317
  }
17283
17318
  getHumanPendingContent(message) {
@@ -17481,7 +17516,7 @@ var Agent = class {
17481
17516
  ...executionRunConfig,
17482
17517
  runConfig: executionRunConfig
17483
17518
  },
17484
- recursionLimit: 200,
17519
+ recursionLimit: AGENT_RECURSION_LIMIT,
17485
17520
  signal
17486
17521
  }
17487
17522
  );
@@ -17592,7 +17627,7 @@ var Agent = class {
17592
17627
  },
17593
17628
  streamMode: ["updates", "messages"],
17594
17629
  subgraphs: false,
17595
- recursionLimit: 200,
17630
+ recursionLimit: AGENT_RECURSION_LIMIT,
17596
17631
  signal
17597
17632
  }
17598
17633
  );
@@ -18349,6 +18384,20 @@ var agentInstanceManager = AgentInstanceManager.getInstance();
18349
18384
  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.";
18350
18385
  var EXCLUDED_STATE_KEYS = ["messages", "todos", "jumpTo"];
18351
18386
  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.";
18387
+ function createGeneralPurposeAgent(options) {
18388
+ const middleware = [...options.middleware];
18389
+ if (options.interruptOn) {
18390
+ middleware.push(humanInTheLoopMiddleware({ interruptOn: options.interruptOn }));
18391
+ }
18392
+ return createAgent2({
18393
+ model: options.model,
18394
+ systemPrompt: DEFAULT_SUBAGENT_PROMPT,
18395
+ tools: options.tools,
18396
+ middleware,
18397
+ checkpointer: getCheckpointSaver("default"),
18398
+ name: "general-purpose"
18399
+ });
18400
+ }
18352
18401
  function getTaskToolDescription(subagentDescriptions) {
18353
18402
  return subagentDescriptions.length > 0 ? `
18354
18403
  Launch an ephemeral subagent to handle complex, multi-step independent tasks with isolated context windows.
@@ -18528,21 +18577,12 @@ function getSubagents(options) {
18528
18577
  const agents = {};
18529
18578
  const subagentDescriptions = [];
18530
18579
  if (generalPurposeAgent) {
18531
- const generalPurposeMiddleware = [...defaultSubagentMiddleware];
18532
- if (defaultInterruptOn) {
18533
- generalPurposeMiddleware.push(
18534
- humanInTheLoopMiddleware({ interruptOn: defaultInterruptOn })
18535
- );
18536
- }
18537
- const generalPurposeSubagent = createAgent2({
18580
+ agents["general-purpose"] = createGeneralPurposeAgent({
18538
18581
  model: defaultModel,
18539
- systemPrompt: DEFAULT_SUBAGENT_PROMPT,
18540
18582
  tools: defaultTools,
18541
- middleware: generalPurposeMiddleware,
18542
- checkpointer: getCheckpointSaver("default"),
18543
- name: "general-purpose"
18583
+ middleware: defaultSubagentMiddleware,
18584
+ interruptOn: defaultInterruptOn
18544
18585
  });
18545
- agents["general-purpose"] = generalPurposeSubagent;
18546
18586
  subagentDescriptions.push(
18547
18587
  `- general-purpose: ${DEFAULT_GENERAL_PURPOSE_DESCRIPTION}`
18548
18588
  );
@@ -21987,6 +22027,7 @@ ${BASE_PROMPT}` : BASE_PROMPT;
21987
22027
  }
21988
22028
 
21989
22029
  // src/agent_lattice/builders/DeepAgentGraphBuilder.ts
22030
+ import { AgentType as AgentType2 } from "@axiom-lattice/protocols";
21990
22031
  var DeepAgentGraphBuilder = class {
21991
22032
  /**
21992
22033
  * 构建Deep Agent Graph
@@ -22035,6 +22076,28 @@ var DeepAgentGraphBuilder = class {
22035
22076
  backend: filesystemBackend,
22036
22077
  middleware: middlewares
22037
22078
  });
22079
+ if (middlewares.some((candidate) => candidate.name === "TaskMiddleware") && agentLattice.config.key) {
22080
+ const tenantId2 = params.tenantId ?? "default";
22081
+ const generalPurposeKey = `${agentLattice.config.key}-general-purpose`;
22082
+ if (!agentLatticeManager.hasAgentLatticeWithTenant(tenantId2, generalPurposeKey)) {
22083
+ const generalPurposeAgent = createGeneralPurposeAgent({
22084
+ model: params.model,
22085
+ tools,
22086
+ middleware: middlewares
22087
+ });
22088
+ agentLatticeManager.registerWithTenant(tenantId2, generalPurposeKey, {
22089
+ config: {
22090
+ key: generalPurposeKey,
22091
+ name: "general-purpose",
22092
+ description: DEFAULT_GENERAL_PURPOSE_DESCRIPTION,
22093
+ type: AgentType2.REACT,
22094
+ prompt: DEFAULT_SUBAGENT_PROMPT,
22095
+ tenantId: tenantId2
22096
+ },
22097
+ client: generalPurposeAgent
22098
+ });
22099
+ }
22100
+ }
22038
22101
  return deepAgent;
22039
22102
  }
22040
22103
  };
@@ -23982,10 +24045,10 @@ _A2ARemoteClient.MAX_CACHED_TASKS = 100;
23982
24045
  var A2ARemoteClient = _A2ARemoteClient;
23983
24046
 
23984
24047
  // src/agent_lattice/builders/RemoteAgentGraphBuilder.ts
23985
- import { AgentType as AgentType2 } from "@axiom-lattice/protocols";
24048
+ import { AgentType as AgentType3 } from "@axiom-lattice/protocols";
23986
24049
  var RemoteAgentGraphBuilder = class {
23987
24050
  async build(agentLattice, params) {
23988
- if (agentLattice.config.type !== AgentType2.A2A_REMOTE) {
24051
+ if (agentLattice.config.type !== AgentType3.A2A_REMOTE) {
23989
24052
  throw new Error(
23990
24053
  `RemoteAgentGraphBuilder received wrong agent type: ${agentLattice.config.type}`
23991
24054
  );
@@ -24755,9 +24818,15 @@ For human judgment, use the actual HITL payload \`status: "interrupted"\` plus
24755
24818
  handled by the configured HITL lifecycle; \`review_required\` is not a task status.
24756
24819
 
24757
24820
  Create the active parent and each started subtask as records: \`manage_task
24758
- create\` always persists \`pending\`. Execution starts only via
24759
- \`task(taskId, agentId)\` dispatch, or the agent works inline and keeps the status
24760
- truthful with \`set_status\`. Use \`pending\` only for future or
24821
+ create\` always persists \`pending\`. **Process the task you were assigned in this
24822
+ run: set it \`in_progress\` with \`manage_task set_status\` when you start (a
24823
+ dispatched task is claimed automatically by the engine).** To bring
24824
+ in a more suitable expert, create a subtask (\`pending\`) and dispatch THAT with
24825
+ \`task { taskId, agentId }\` (a specialist, or agentId "general-purpose" to run your
24826
+ own capabilities in an isolated run). **Never re-dispatch the task you are
24827
+ currently processing** \u2014 delegating to an expert means giving them a child task,
24828
+ not handing over your own. Report the outcome with \`set_status completed\` (result
24829
+ + beliefImpact), \`failed\`, or \`interrupted\`. Use \`pending\` only for future or
24761
24830
  dependency-blocked work.
24762
24831
  Before marking the parent completed, call \`list(parentId)\`: every child must
24763
24832
  be completed or cancelled, while a failed or interrupted child blocks completion
@@ -26048,34 +26117,24 @@ Renew HITL approval when a foundational assumption or authority boundary changes
26048
26117
 
26049
26118
  ## Skill Loading Policy
26050
26119
 
26051
- Visible in <available_skills> does not mean loaded. Follow these three tiers.
26052
-
26053
- ### Tier 1 \u2014 Session start (mandatory, unconditional)
26054
- Load before any other work; the bootstrap prompt enforces this:
26055
- - [[agent-architecture]] (this skill) \u2014 shared policy and routing.
26056
- - [[task-tracking]] \u2014 before your first \`manage_task\` call; Task management is
26057
- the planning surface and is gated again under Architect Task Policy.
26058
-
26059
- ### Tier 2 \u2014 Scenario gates (mandatory before entering the scenario)
26060
- Load the owning skill with the \`skill\` tool BEFORE the first action of that
26061
- scenario. Never execute a scenario without its owning skill loaded:
26062
- - Creating or modifying a Capability (\`react\`) or Orchestra (\`deep_agent\`)
26063
- Agent \u2192 [[agent-build]]
26064
- - Creating or modifying a Workflow (stable enumerable pipelines) \u2192 [[design-workflow]]
26065
- - Learning a capability from source material \u2192 [[document-learning-learn-capability]]
26066
- - Designing evals, running evals, or fixing eval failures \u2192 [[eval-verify]]
26067
- - Claiming work is complete or delivered \u2192 [[completion-gate]]
26068
- - Final configuration pre-check before delivery \u2192 [[review-agent]]
26069
- - Placing or authoring knowledge files (company vs project level) \u2192 [[knowledge-management]]
26070
-
26071
- If a Tier 2 load fails, retry once, then stop and tell the user which
26072
- capability is unavailable. Do not improvise the scenario from partial knowledge.
26073
-
26074
- ### Tier 3 \u2014 Reference (load on demand, never preload)
26075
- Deep details reachable through wiki-links inside loaded skills, and plugin
26076
- skills outside this chain (for example task-definition for non-architect
26077
- agents, or sandbox-plugins-authoring for the \`plugin-builder\` agent). Load one
26078
- only when the current step actually needs it.
26120
+ Visible in <available_skills> does not mean loaded. Load a skill only when the
26121
+ current step actually requires its procedure \u2014 one at a time, never preloaded.
26122
+ Do not load skills speculatively or to "see what exists": inspect existing
26123
+ assets with a bounded read-only survey, not by loading skill content.
26124
+
26125
+ - [[agent-architecture]] (this skill) \u2014 loaded at session start by the bootstrap
26126
+ prompt; it is the shared policy and router.
26127
+ - [[task-tracking]] \u2014 load right before your first \`manage_task\` call; Task
26128
+ management is the planning surface (gated again under Architect Task Policy).
26129
+ - Procedure skills \u2014 [[agent-build]], [[design-workflow]],
26130
+ [[document-learning-learn-capability]], [[eval-verify]], [[completion-gate]],
26131
+ [[review-agent]], [[knowledge-management]]: load the ONE that owns the step you
26132
+ are about to perform, immediately before performing it. Never preload the chain.
26133
+ - Reference and plugin skills (deep wiki-links, task-definition, sandbox authoring,
26134
+ and any plugin skills): load only when the current step needs them; never preload.
26135
+
26136
+ Loading a skill is a tool call, not a plan. If a required load fails, retry once,
26137
+ then stop and tell the user which capability is unavailable.
26079
26138
 
26080
26139
  ## Agent Forms and Routing
26081
26140
  - **Capability** (\`react\`) for bounded direct work: [[agent-build]]
@@ -26088,9 +26147,19 @@ only when the current step actually needs it.
26088
26147
  - **Tenant plugin** (sandbox-authored tool + optional HTML UI) \u2192 use the \`plugin-builder\` agent, or load [[sandbox-plugins-authoring]].
26089
26148
 
26090
26149
  ## Architect Task Policy
26091
- The Agent Architect uses persistent TaskItems as its planning surface. Architect must not use
26092
- \`write_todos\`. Create a persistent child only for an independently verifiable
26150
+ The Agent Architect MUST use persistent TaskItems as its single working surface;
26151
+ Architect must not use \`write_todos\` for independently verifiable outcomes, and
26152
+ working without a corresponding TaskItem is a policy violation.
26153
+ Create a persistent child only for an independently verifiable
26093
26154
  outcome; tool calls and file reads are actions inside the active Task.
26155
+ **Each task is your evidence ledger**: its Acceptance Criteria + Belief State define
26156
+ what counts as evidence, the work runs inside your own run (eval / \`invoke_agent\` for
26157
+ subject agents) and produces that evidence, and the parent completes only when the
26158
+ evidence is sufficient. Process the task you were assigned in this run; set it
26159
+ \`in_progress\` with \`manage_task set_status\` when you start. Delegate a subtask only
26160
+ when it belongs to another agent \u2014 create it (\`pending\`) and dispatch it with
26161
+ \`task { taskId, agentId }\`. To exercise a designed/subject agent, use eval /
26162
+ \`invoke_agent\` inside your own run instead of \`task\` dispatch.
26094
26163
  **MANDATORY: before your first \`manage_task\` call in this session, load
26095
26164
  [[task-tracking]] with the \`skill\` tool.** Do not create, update, or transition
26096
26165
  any Task until it is loaded. If the load fails, retry once, then tell the user
@@ -26161,11 +26230,11 @@ When a room request is actionable work, decide between two paths:
26161
26230
  \`assistantId\`, then dispatch it with
26162
26231
  \`task { taskId, agentId: <bot assistantId> }\` so the specialist actually runs
26163
26232
  (creating the task alone starts nothing). \`task\` transfers the task owner to
26164
- \`agentId\` and requires a **task-capable** bot (enabled \`task\` middleware that
26165
- exposes \`manage_task\`); a non-capable target is rejected with
26166
- \`TASK_DELEGATE_TARGET_NOT_CAPABLE\`. State the expected output and
26167
- acceptance criteria in the task description so the assigned bot can verify its
26168
- own work.
26233
+ \`agentId\` and runs it in an isolated thread; the target does not need task
26234
+ tools \u2014 if it has \`manage_task\` it records status itself, otherwise reconcile
26235
+ its returned \`executionResultId\` with \`manage_task\` update. State the expected output
26236
+ and acceptance criteria in the task description so the assigned bot can
26237
+ verify its own work.
26169
26238
 
26170
26239
  ## Discovering bots
26171
26240
  Before delegating, call \`list_room_roster\` to see the active room bots and their
@@ -26316,9 +26385,15 @@ criteria are truly met \u2014 never as a workaround.
26316
26385
  uncertainties, with no required minimum and a maximum of seven:
26317
26386
  \`manage_task create(title: <goal>, description: <contract + Belief State>, ownerType: "agent")\`
26318
26387
  \`create\` always yields a \`pending\` record \u2014 it never starts execution. Record
26319
- the returned parent task id, then run it by dispatching
26320
- \`task { taskId, agentId }\` (a fresh isolated thread); otherwise work inline and
26321
- \`set_status\` as you go.
26388
+ the returned parent task id, then **process it in this run**, setting it
26389
+ \`in_progress\` with \`manage_task set_status\` when you start. To decompose, create each subtask
26390
+ with \`manage_task create\` (\`pending\`) and delegate it with \`task { taskId,
26391
+ agentId }\` to the agent that should execute it (a specialist, or
26392
+ "general-purpose" for your own capabilities). The executor does not need
26393
+ \`manage_task\`: it returns an observation and \`executionResultId\`, and the caller
26394
+ records the outcome with \`manage_task\`. To exercise a subject application agent,
26395
+ use eval cases / \`invoke_agent\` inside your own run \u2014 \`task\` dispatch is
26396
+ delegation of persistent work, not an evaluation mechanism.
26322
26397
  - **Create a subtask for a verifiable result**, not per phase: identify its
26323
26398
  deliverable, define observable acceptance criteria and required evidence, and
26324
26399
  state positive and negative result branches under Targets / Expected Impact
@@ -26343,10 +26418,15 @@ ${TASK_BELIEF_REFERENCE_EXAMPLE}
26343
26418
 
26344
26419
  ## Status discipline \u2014 MANDATORY
26345
26420
 
26421
+ - Execution ownership: process the task you were assigned in this run; set it
26422
+ \`in_progress\` with \`manage_task set_status\` when you start. To involve a more
26423
+ suitable expert, create a subtask and dispatch it with \`task { taskId, agentId }\`
26424
+ \u2014 never re-dispatch the task you are processing. Report the outcome with
26425
+ \`set_status completed\` (result + beliefImpact), \`failed\`, or \`interrupted\`.
26346
26426
  - All status transitions go through \`manage_task set_status\` (with
26347
26427
  \`result\` on completed, \`failureReason\` on failed). \`update\` is for
26348
26428
  content fields only and rejects a status field.
26349
- - A subtask is \`completed\` ONLY when its work is actually finished.
26429
+ - A task is \`completed\` ONLY when its work is actually finished.
26350
26430
  While fixing eval failures, keep it \`in_progress\` \u2014 never mark
26351
26431
  \`completed\` as a workaround (the state machine rejects illegal
26352
26432
  transitions).
@@ -26946,6 +27026,11 @@ its evidence projection, not an independent source of goals or expectations.
26946
27026
  touching any eval project. An eval project created without a real, confirmed
26947
27027
  subject is a hard error. If the agent is only planned (not yet materialized),
26948
27028
  evaluation must wait until materialization returns its id.
27029
+ - **Exercise the subject through eval \u2014 never through \`task\` dispatch.** The
27030
+ subject agent is invoked by eval cases / \`invoke_agent\`; do NOT create a
27031
+ TaskItem assigned to the subject and dispatch it. \`task\` is for delegated
27032
+ execution of persistent work, not an evaluation mechanism. Use eval cases to
27033
+ measure the subject; keep \`task\` dispatch for executors running real work.
26949
27034
  - **Check existence before creating; reuse is the rule, creation is the exception.**
26950
27035
  Project names are unique per tenant. 1) Name it exactly \`eval-{agent-id}\`.
26951
27036
  2) \`read_eval list_projects({ name: "eval-{agent-id}" })\` \u2014 a name-scoped lookup,
@@ -27933,7 +28018,7 @@ var InMemoryMenuStore = class {
27933
28018
  // src/agent_lattice/agentArchitectTools.ts
27934
28019
  import z52 from "zod";
27935
28020
  import { v4 as v43 } from "uuid";
27936
- import { AgentType as AgentType3 } from "@axiom-lattice/protocols";
28021
+ import { AgentType as AgentType4 } from "@axiom-lattice/protocols";
27937
28022
  function getTenantId2(exeConfig) {
27938
28023
  const runConfig = exeConfig?.configurable?.runConfig || {};
27939
28024
  return runConfig.tenantId || "default";
@@ -27983,7 +28068,7 @@ function getStringMetadata(config) {
27983
28068
  }
27984
28069
  function isUndecidedLearningPlaceholder(config) {
27985
28070
  const metadata = getStringMetadata(config);
27986
- return config.type === AgentType3.REACT && metadata.learningPlaceholder === "true" && metadata.architectureStatus === "undecided";
28071
+ return config.type === AgentType4.REACT && metadata.learningPlaceholder === "true" && metadata.architectureStatus === "undecided";
27987
28072
  }
27988
28073
  function requireSkillDeclaration(skillLoaded) {
27989
28074
  if (skillLoaded !== true) {
@@ -28136,7 +28221,7 @@ registerToolLattice(
28136
28221
  key: id,
28137
28222
  name: input.name,
28138
28223
  description: input.description || "",
28139
- type: input.type === "deep_agent" ? AgentType3.DEEP_AGENT : AgentType3.REACT,
28224
+ type: input.type === "deep_agent" ? AgentType4.DEEP_AGENT : AgentType4.REACT,
28140
28225
  prompt: input.prompt,
28141
28226
  ...input.tools && input.tools.length > 0 ? { tools: input.tools } : {},
28142
28227
  ...input.middleware && input.middleware.length > 0 ? { middleware: input.middleware } : {},
@@ -28193,7 +28278,7 @@ registerToolLattice(
28193
28278
  key: id,
28194
28279
  name: input.name,
28195
28280
  description: input.description || "",
28196
- type: AgentType3.WORKFLOW,
28281
+ type: AgentType4.WORKFLOW,
28197
28282
  prompt: input.description || `Workflow: ${input.name}`,
28198
28283
  workflowYaml: input.yaml,
28199
28284
  ...input.tools && input.tools.length > 0 ? { tools: input.tools } : {},
@@ -28230,7 +28315,7 @@ registerToolLattice(
28230
28315
  return JSON.stringify({ error: `Agent '${input.id}' not found` });
28231
28316
  }
28232
28317
  const graphDef = agent.graphDefinition;
28233
- if (!graphDef || graphDef.type !== AgentType3.WORKFLOW) {
28318
+ if (!graphDef || graphDef.type !== AgentType4.WORKFLOW) {
28234
28319
  return JSON.stringify({ error: `Agent '${input.id}' is not a workflow agent` });
28235
28320
  }
28236
28321
  const yaml = graphDef.workflowYaml;
@@ -28345,7 +28430,7 @@ registerToolLattice(
28345
28430
  return JSON.stringify({ error: `Agent '${input.id}' not found` });
28346
28431
  }
28347
28432
  const existingConfig = existing.graphDefinition || {};
28348
- const isWorkflow = existingConfig.type === AgentType3.WORKFLOW;
28433
+ const isWorkflow = existingConfig.type === AgentType4.WORKFLOW;
28349
28434
  const isPlaceholder = isUndecidedLearningPlaceholder(existingConfig);
28350
28435
  if (!isWorkflow && !isPlaceholder) {
28351
28436
  console.log(`[update_workflow] ERROR: not a workflow agent: ${input.id}`);
@@ -28361,7 +28446,7 @@ registerToolLattice(
28361
28446
  const mergedConfig = {
28362
28447
  ...existingConfig,
28363
28448
  ...isPlaceholder ? {
28364
- type: AgentType3.WORKFLOW,
28449
+ type: AgentType4.WORKFLOW,
28365
28450
  workflowYaml: input.yaml,
28366
28451
  metadata: {
28367
28452
  ...getStringMetadata(existingConfig),
@@ -28467,14 +28552,14 @@ registerToolLattice(
28467
28552
  const mergedConfig = { ...existingConfig, ...input.config };
28468
28553
  const isPlaceholder = isUndecidedLearningPlaceholder(existingConfigRecord);
28469
28554
  const materializedType = input.config.type;
28470
- const isMaterializingPlaceholder = isPlaceholder && (materializedType === AgentType3.REACT || materializedType === AgentType3.DEEP_AGENT);
28555
+ const isMaterializingPlaceholder = isPlaceholder && (materializedType === AgentType4.REACT || materializedType === AgentType4.DEEP_AGENT);
28471
28556
  if (isMaterializingPlaceholder) {
28472
28557
  mergedConfig.metadata = {
28473
28558
  ...getStringMetadata(existingConfigRecord),
28474
28559
  ...input.config.metadata ?? {},
28475
28560
  learningPlaceholder: "false",
28476
28561
  architectureStatus: "materialized",
28477
- architectureForm: materializedType === AgentType3.DEEP_AGENT ? "orchestra" : "capability"
28562
+ architectureForm: materializedType === AgentType4.DEEP_AGENT ? "orchestra" : "capability"
28478
28563
  };
28479
28564
  } else if (isPlaceholder && input.config.metadata !== void 0) {
28480
28565
  const metadata = {
@@ -28724,100 +28809,20 @@ import { AgentType as AgentType5 } from "@axiom-lattice/protocols";
28724
28809
  // src/agent_lattice/agentArchitectPrompt.ts
28725
28810
  var AGENT_ARCHITECT_PROMPT = `You are the Agent Architect.
28726
28811
 
28727
- CRITICAL FIRST ACTION: Before any response or other action, call the \`skill\`
28728
- tool with skill_name: "agent-architecture" to load agent-architecture and follow it.
28729
- Immediately after it loads, call the \`skill\` tool again with skill_name:
28730
- "task-tracking" \u2014 persistent Task management is your core planning surface and
28731
- you must have its operation reference before creating or updating any Task.
28732
- Never announce skill loads. If a load fails, retry once, then stop and
28733
- explicitly report that the required skill could not be loaded.`;
28734
-
28735
- // src/agent_lattice/agentReviewerConfig.ts
28736
- import { AgentType as AgentType4 } from "@axiom-lattice/protocols";
28737
-
28738
- // src/agent_lattice/agentReviewerPrompt.ts
28739
- var AGENT_REVIEWER_PROMPT = `# Agent Reviewer
28740
-
28741
- 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.
28742
-
28743
- ## Your Tools
28744
-
28745
- - **get_agent** \u2014 Fetch an agent's full configuration
28746
- - **list_agents** \u2014 List all agents in the workspace
28747
- - **list_tools** \u2014 List all available tools that can be assigned to agents
28748
- - **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.
28749
-
28750
- ## Your Workflow
28751
-
28752
- ### When asked to review an agent:
28753
-
28754
- 1. Call **get_agent** to fetch the agent's config
28755
- 2. Review the configuration for:
28756
- - **Completeness** \u2014 Are name, description, prompt present? Is the prompt clear and actionable?
28757
- - **Tool validity** \u2014 Do the referenced tools exist? Call **list_tools** to verify.
28758
- - **Middleware correctness** \u2014 Is every middleware entry complete (id, type, name, description, enabled, config)?
28759
- - **Sub-agent references** \u2014 Do referenced sub-agent IDs exist? Call **list_agents** to verify.
28760
- - **Type consistency** \u2014 Does the agent type match its configuration shape? (e.g., PROCESSING must have edges, DEEP_AGENT may have subAgents)
28761
- 3. Report your findings clearly. For each issue, state:
28762
- - Severity (ERROR / WARNING / INFO)
28763
- - What the problem is
28764
- - How to fix it
28765
-
28766
- ### When asked to test an agent:
28767
-
28768
- 1. Call **get_agent** to understand the agent's purpose and expected behavior
28769
- 2. Craft a realistic test message that exercises the agent's core responsibility \u2014 what would a real user say?
28770
- 3. Call **invoke_agent(id, message)** to send the test message
28771
- 4. Analyze the response:
28772
- - **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.
28773
- - **Otherwise, result.messages contains the agent's output**: The agent completed without interruption. Check:
28774
- - Did the agent understand the request?
28775
- - Was the response relevant and accurate?
28776
- - Did the agent use the right tools?
28777
- - Were there any errors or unexpected behaviors?
28778
- - **If result.error is present**: The invocation itself failed (agent not found, compilation error, etc.). Report the error clearly.
28779
- 5. Report your findings with the agent's actual response
28780
-
28781
- ### When results are wrong:
28782
-
28783
- If the agent's response is incorrect or unexpected:
28784
- 1. Point out specifically what went wrong
28785
- 2. Suggest what might need to change in the prompt or middleware config
28786
- 3. Offer to re-test after fixes are applied
28787
-
28788
- ## Important Rules
28789
-
28790
- - **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.
28791
- - **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."
28792
- - **One agent at a time.** Focus on one agent per review or test request. Don't try to review multiple agents simultaneously.
28793
- - **Be concise but thorough.** Cover all the checks, but present findings clearly without fluff.
28794
- `;
28812
+ Your working surface is persistent **TaskItems**. Every independently verifiable
28813
+ outcome MUST be a TaskItem created and kept truthful through \`manage_task\`; do NOT
28814
+ keep a separate todo list \u2014 the TaskItem is your only planning and evidence surface.
28815
+ Gather evidence through tasks, and treat the parent as done only when its
28816
+ acceptance evidence is sufficient. If the \`task\` tools are unavailable, stop and
28817
+ report that task management is unavailable instead of working around it.
28795
28818
 
28796
- // src/agent_lattice/agentReviewerConfig.ts
28797
- var AGENT_REVIEWER_KEY = "agent-reviewer";
28798
- var agentReviewerConfig = {
28799
- key: AGENT_REVIEWER_KEY,
28800
- name: "Agent Reviewer",
28801
- 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.",
28802
- type: AgentType4.REACT,
28803
- prompt: AGENT_REVIEWER_PROMPT,
28804
- tools: [
28805
- "invoke_agent",
28806
- "get_agent",
28807
- "list_agents",
28808
- "list_tools"
28809
- ],
28810
- middleware: [
28811
- {
28812
- id: "widget",
28813
- type: "widget",
28814
- name: "Widget",
28815
- description: "Render interactive HTML widgets and SVG diagrams",
28816
- enabled: true,
28817
- config: {}
28818
- }
28819
- ]
28820
- };
28819
+ CRITICAL FIRST ACTION: Before any response or other action, call the \`skill\`
28820
+ tool with skill_name: "agent-architecture" to load the shared policy and router,
28821
+ and follow it. Load every OTHER skill only when the current step actually
28822
+ requires its procedure \u2014 one at a time, never preloaded. Load "task-tracking"
28823
+ right before your first \`manage_task\` call. Never announce skill loads. If a
28824
+ required load fails, retry once, then stop and explicitly report that the
28825
+ required skill could not be loaded.`;
28821
28826
 
28822
28827
  // src/agent_lattice/agentArchitectConfig.ts
28823
28828
  var AGENT_ARCHITECT_KEY = "agent-architect";
@@ -28843,7 +28848,6 @@ var agentArchitectConfig = {
28843
28848
  "manage_binding"
28844
28849
  ],
28845
28850
  subAgents: ["document-parser-benchmark"],
28846
- internalSubAgents: [agentReviewerConfig],
28847
28851
  middleware: [
28848
28852
  {
28849
28853
  id: "filesystem",
@@ -28928,9 +28932,96 @@ var agentArchitectConfig = {
28928
28932
  ]
28929
28933
  };
28930
28934
 
28931
- // src/agent_lattice/roomCoordinatorConfig.ts
28935
+ // src/agent_lattice/agentReviewerConfig.ts
28932
28936
  import { AgentType as AgentType6 } from "@axiom-lattice/protocols";
28933
28937
 
28938
+ // src/agent_lattice/agentReviewerPrompt.ts
28939
+ var AGENT_REVIEWER_PROMPT = `# Agent Reviewer
28940
+
28941
+ 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.
28942
+
28943
+ ## Your Tools
28944
+
28945
+ - **get_agent** \u2014 Fetch an agent's full configuration
28946
+ - **list_agents** \u2014 List all agents in the workspace
28947
+ - **list_tools** \u2014 List all available tools that can be assigned to agents
28948
+ - **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.
28949
+
28950
+ ## Your Workflow
28951
+
28952
+ ### When asked to review an agent:
28953
+
28954
+ 1. Call **get_agent** to fetch the agent's config
28955
+ 2. Review the configuration for:
28956
+ - **Completeness** \u2014 Are name, description, prompt present? Is the prompt clear and actionable?
28957
+ - **Tool validity** \u2014 Do the referenced tools exist? Call **list_tools** to verify.
28958
+ - **Middleware correctness** \u2014 Is every middleware entry complete (id, type, name, description, enabled, config)?
28959
+ - **Sub-agent references** \u2014 Do referenced sub-agent IDs exist? Call **list_agents** to verify.
28960
+ - **Type consistency** \u2014 Does the agent type match its configuration shape? (e.g., PROCESSING must have edges, DEEP_AGENT may have subAgents)
28961
+ 3. Report your findings clearly. For each issue, state:
28962
+ - Severity (ERROR / WARNING / INFO)
28963
+ - What the problem is
28964
+ - How to fix it
28965
+
28966
+ ### When asked to test an agent:
28967
+
28968
+ 1. Call **get_agent** to understand the agent's purpose and expected behavior
28969
+ 2. Craft a realistic test message that exercises the agent's core responsibility \u2014 what would a real user say?
28970
+ 3. Call **invoke_agent(id, message)** to send the test message
28971
+ 4. Analyze the response:
28972
+ - **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.
28973
+ - **Otherwise, result.messages contains the agent's output**: The agent completed without interruption. Check:
28974
+ - Did the agent understand the request?
28975
+ - Was the response relevant and accurate?
28976
+ - Did the agent use the right tools?
28977
+ - Were there any errors or unexpected behaviors?
28978
+ - **If result.error is present**: The invocation itself failed (agent not found, compilation error, etc.). Report the error clearly.
28979
+ 5. Report your findings with the agent's actual response
28980
+
28981
+ ### When results are wrong:
28982
+
28983
+ If the agent's response is incorrect or unexpected:
28984
+ 1. Point out specifically what went wrong
28985
+ 2. Suggest what might need to change in the prompt or middleware config
28986
+ 3. Offer to re-test after fixes are applied
28987
+
28988
+ ## Important Rules
28989
+
28990
+ - **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.
28991
+ - **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."
28992
+ - **One agent at a time.** Focus on one agent per review or test request. Don't try to review multiple agents simultaneously.
28993
+ - **Be concise but thorough.** Cover all the checks, but present findings clearly without fluff.
28994
+ `;
28995
+
28996
+ // src/agent_lattice/agentReviewerConfig.ts
28997
+ var AGENT_REVIEWER_KEY = "agent-reviewer";
28998
+ var agentReviewerConfig = {
28999
+ key: AGENT_REVIEWER_KEY,
29000
+ name: "Agent Reviewer",
29001
+ 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.",
29002
+ type: AgentType6.REACT,
29003
+ prompt: AGENT_REVIEWER_PROMPT,
29004
+ tools: [
29005
+ "invoke_agent",
29006
+ "get_agent",
29007
+ "list_agents",
29008
+ "list_tools"
29009
+ ],
29010
+ middleware: [
29011
+ {
29012
+ id: "widget",
29013
+ type: "widget",
29014
+ name: "Widget",
29015
+ description: "Render interactive HTML widgets and SVG diagrams",
29016
+ enabled: true,
29017
+ config: {}
29018
+ }
29019
+ ]
29020
+ };
29021
+
29022
+ // src/agent_lattice/roomCoordinatorConfig.ts
29023
+ import { AgentType as AgentType7 } from "@axiom-lattice/protocols";
29024
+
28934
29025
  // src/agent_lattice/roomCoordinatorPrompt.ts
28935
29026
  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.`;
28936
29027
 
@@ -28940,7 +29031,7 @@ var roomCoordinatorConfig = {
28940
29031
  key: ROOM_COORDINATOR_KEY,
28941
29032
  name: "Room Coordinator",
28942
29033
  description: "Manages project room conversations: replies when no bot is mentioned, coordinates room members, and organizes project work.",
28943
- type: AgentType6.DEEP_AGENT,
29034
+ type: AgentType7.DEEP_AGENT,
28944
29035
  prompt: ROOM_COORDINATOR_PROMPT,
28945
29036
  tools: [],
28946
29037
  middleware: [
@@ -29575,17 +29666,6 @@ var getAgentClient = (tenantId2, key5, options) => agentLatticeManager.initializ
29575
29666
  var getAgentClientAsync = async (tenantId2, key5, options) => agentLatticeManager.initializeClientAsync(tenantId2, key5, options);
29576
29667
  var createAgentClientFromAgentLattice = async (agentLattice, options) => await agentLatticeManager.createAgentClientFromConfig(agentLattice, options);
29577
29668
 
29578
- // src/agent_lattice/taskCapability.ts
29579
- function agentHasManagedTaskCapability(config) {
29580
- const middleware = config?.middleware;
29581
- const taskMiddleware = Array.isArray(middleware) ? middleware.find((entry) => entry?.type === "task" && entry?.enabled === true) : void 0;
29582
- if (!taskMiddleware) {
29583
- return false;
29584
- }
29585
- const allowedTools = taskMiddleware.allowedTools;
29586
- return allowedTools === void 0 || Array.isArray(allowedTools) && (allowedTools.length === 0 || allowedTools.includes("manage_task"));
29587
- }
29588
-
29589
29669
  // src/vectorstore_lattice/VectorStoreLatticeManager.ts
29590
29670
  var VectorStoreLatticeManager = class _VectorStoreLatticeManager extends BaseLatticeManager {
29591
29671
  /**
@@ -34167,7 +34247,7 @@ var LatticeEvalSuite = class {
34167
34247
  };
34168
34248
 
34169
34249
  // src/eval_lattice/LatticeEvalProject.ts
34170
- import { AgentType as AgentType7 } from "@axiom-lattice/protocols";
34250
+ import { AgentType as AgentType8 } from "@axiom-lattice/protocols";
34171
34251
  import { HumanMessage as HumanMessage6 } from "@langchain/core/messages";
34172
34252
  import { v4 as uuidv47 } from "uuid";
34173
34253
  var DEFAULT_CALIBRATION_PROBES = [
@@ -34223,7 +34303,7 @@ var LatticeEvalProject = class {
34223
34303
  key: this.judgeAgentKey,
34224
34304
  name: `Judge agent for ${this.project.projectName}`,
34225
34305
  description: "Judge agent for evaluating Lattice test cases",
34226
- type: AgentType7.REACT,
34306
+ type: AgentType8.REACT,
34227
34307
  prompt: "",
34228
34308
  modelKey: judgeModelKey
34229
34309
  };
@@ -37578,6 +37658,33 @@ function createTaskRunBridge(deps) {
37578
37658
  transitioned: true
37579
37659
  };
37580
37660
  }
37661
+ if (task.status === "interrupted" || task.status === "failed") {
37662
+ if (task.ownerType !== "agent") {
37663
+ return {
37664
+ success: false,
37665
+ code: "AGENT_TASK_REQUIRED",
37666
+ error: "Lifecycle transitions only support agent tasks."
37667
+ };
37668
+ }
37669
+ 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 });
37670
+ if (!result.success) {
37671
+ return {
37672
+ success: false,
37673
+ code: result.code,
37674
+ error: result.error,
37675
+ ...result.hint !== void 0 ? { hint: result.hint } : {},
37676
+ ...result.retryable !== void 0 ? { retryable: result.retryable } : {},
37677
+ ...result.warnings !== void 0 ? { warnings: result.warnings } : {}
37678
+ };
37679
+ }
37680
+ return {
37681
+ success: true,
37682
+ task: result.task,
37683
+ warnings: result.warnings ?? [],
37684
+ mutated: true,
37685
+ transitioned: true
37686
+ };
37687
+ }
37581
37688
  return { success: true, task, warnings, mutated: false, transitioned: false };
37582
37689
  },
37583
37690
  async settleRun(input) {
@@ -37731,48 +37838,18 @@ async function prepareTaskDispatch(deps, input) {
37731
37838
  }
37732
37839
  };
37733
37840
  }
37734
- if (task.status !== "pending") {
37841
+ if (task.status !== "pending" && task.status !== "interrupted" && task.status !== "failed") {
37735
37842
  return {
37736
37843
  kind: "failure",
37737
37844
  failure: {
37738
37845
  success: false,
37739
37846
  code: "TASK_NOT_DISPATCHABLE",
37740
- error: "Only a `pending` task can be dispatched.",
37741
- 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.`,
37847
+ error: "Only a `pending`, `interrupted`, or `failed` task can be dispatched.",
37848
+ 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.`,
37742
37849
  taskId: task.id
37743
37850
  }
37744
37851
  };
37745
37852
  }
37746
- if (deps.resolveTaskCapability) {
37747
- let targetCapable;
37748
- try {
37749
- targetCapable = await deps.resolveTaskCapability(input.tenantId, input.agentId);
37750
- } catch (error) {
37751
- return {
37752
- kind: "failure",
37753
- failure: {
37754
- success: false,
37755
- code: "AGENT_RESOLUTION_FAILED",
37756
- error: errorMessage(error),
37757
- taskId: task.id,
37758
- agentId: input.agentId
37759
- }
37760
- };
37761
- }
37762
- if (!targetCapable) {
37763
- return {
37764
- kind: "failure",
37765
- failure: {
37766
- success: false,
37767
- code: "TASK_DELEGATE_TARGET_NOT_CAPABLE",
37768
- taskId: task.id,
37769
- agentId: input.agentId,
37770
- error: `Agent '${input.agentId}' cannot manage tasks, so a dispatched TaskItem could never be completed.`,
37771
- 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`."
37772
- }
37773
- };
37774
- }
37775
- }
37776
37853
  const managedAuthority = executionAuthorityRegistry.resolve(task);
37777
37854
  if (managedAuthority) {
37778
37855
  if (managedAuthority.onManagedStart) {
@@ -38184,6 +38261,7 @@ function toJsonSafeValue(value) {
38184
38261
  }
38185
38262
 
38186
38263
  // src/services/TaskExecutionService.ts
38264
+ import { GraphInterrupt as GraphInterrupt2 } from "@langchain/langgraph";
38187
38265
  function persistedExecutionObservation(item, attempted) {
38188
38266
  const detail = item.detail;
38189
38267
  const persistedObservation = toJsonSafeValue(detail?.observation);
@@ -38230,9 +38308,10 @@ function createTaskExecutionService(deps) {
38230
38308
  const run = async (plan) => {
38231
38309
  const { tenantId: tenantId2, agentId, actor, parent, completedDependencies } = plan;
38232
38310
  let task = plan.task;
38311
+ 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;
38233
38312
  let threadId;
38234
38313
  try {
38235
- threadId = (deps.createThreadId ?? randomUUID8)();
38314
+ threadId = persistedThreadId ?? (deps.createThreadId ?? randomUUID8)();
38236
38315
  } catch (error) {
38237
38316
  return {
38238
38317
  success: false,
@@ -38271,12 +38350,12 @@ function createTaskExecutionService(deps) {
38271
38350
  task = transfer.task;
38272
38351
  }
38273
38352
  const warnings = [];
38274
- if (task.status === "pending") {
38353
+ if (task.status === "pending" || task.status === "interrupted" || task.status === "failed") {
38275
38354
  const begun = await bridge.beginRun({
38276
38355
  tenantId: tenantId2,
38277
38356
  task,
38278
38357
  actor,
38279
- threadId: plan.callerThreadId
38358
+ threadId
38280
38359
  });
38281
38360
  if (!begun.success) return { ...begun, taskId: task.id };
38282
38361
  if (!begun.mutated || !begun.transitioned) {
@@ -38305,6 +38384,19 @@ function createTaskExecutionService(deps) {
38305
38384
  try {
38306
38385
  observation = toJsonSafeValue(await deps.invokeAgent(invocation));
38307
38386
  } catch (error) {
38387
+ if (error instanceof GraphInterrupt2) {
38388
+ try {
38389
+ await bridge.settleRun({
38390
+ tenantId: tenantId2,
38391
+ task,
38392
+ actor,
38393
+ threadId,
38394
+ outcome: { kind: "interrupted", summary: "Awaiting user input" }
38395
+ });
38396
+ } catch {
38397
+ }
38398
+ throw error;
38399
+ }
38308
38400
  const normalizationError = error instanceof JsonSafeValueError;
38309
38401
  const message = normalizationError ? `${error.code}: ${error.message}` : errorMessage(error);
38310
38402
  const failureCode = normalizationError ? "EXECUTION_RESULT_NORMALIZATION_FAILED" : "AGENT_INVOCATION_FAILED";
@@ -38435,6 +38527,76 @@ function createTaskExecutionService(deps) {
38435
38527
  };
38436
38528
  }
38437
38529
 
38530
+ // src/services/TaskRunRegistry.ts
38531
+ var TaskRunRegistry = class {
38532
+ constructor() {
38533
+ this.live = /* @__PURE__ */ new Set();
38534
+ }
38535
+ /** Marks a task as currently held by a live run. */
38536
+ register(taskId) {
38537
+ this.live.add(taskId);
38538
+ }
38539
+ /** Removes a task once its run has ended. */
38540
+ unregister(taskId) {
38541
+ this.live.delete(taskId);
38542
+ }
38543
+ /** Reports whether a task is currently held by a live run. */
38544
+ isLive(taskId) {
38545
+ return this.live.has(taskId);
38546
+ }
38547
+ /** Returns a snapshot of the live task ids (diagnostics/tests). */
38548
+ snapshot() {
38549
+ return [...this.live];
38550
+ }
38551
+ /** Clears all live entries (tests / process teardown). */
38552
+ clear() {
38553
+ this.live.clear();
38554
+ }
38555
+ };
38556
+ var taskRunRegistry = new TaskRunRegistry();
38557
+ async function reconcileStaleTaskRuns(input) {
38558
+ const registry4 = input.registry ?? taskRunRegistry;
38559
+ const converged = [];
38560
+ for (const task of input.tasks) {
38561
+ if (task.status !== "in_progress" || registry4.isLive(task.id)) continue;
38562
+ const result = await input.lifecycle.interruptTask({
38563
+ tenantId: task.tenantId,
38564
+ taskId: task.id,
38565
+ actor: input.actor,
38566
+ type: "missing_input",
38567
+ summary: "Run is no longer executing this task (no_executor)"
38568
+ });
38569
+ if (result.success) converged.push(task.id);
38570
+ }
38571
+ return { converged };
38572
+ }
38573
+ async function reconcileTenantTaskRuns(input) {
38574
+ const tasks = await input.taskStore.list({ tenantId: input.tenantId, status: "in_progress" });
38575
+ const candidates = input.include ? tasks.filter(input.include) : tasks;
38576
+ return reconcileStaleTaskRuns({
38577
+ tasks: candidates,
38578
+ actor: input.actor,
38579
+ lifecycle: input.lifecycle,
38580
+ ...input.registry ? { registry: input.registry } : {}
38581
+ });
38582
+ }
38583
+ async function reconcileAllTenantTaskRuns(input) {
38584
+ const tenants = await input.tenantStore.listTenants();
38585
+ const converged = [];
38586
+ for (const tenant of tenants) {
38587
+ const result = await reconcileTenantTaskRuns({
38588
+ tenantId: tenant.id,
38589
+ actor: input.actor,
38590
+ taskStore: input.taskStore,
38591
+ lifecycle: input.lifecycle,
38592
+ ...input.registry ? { registry: input.registry } : {},
38593
+ ...input.include ? { include: input.include } : {}
38594
+ });
38595
+ converged.push(...result.converged);
38596
+ }
38597
+ return { converged };
38598
+ }
38599
+
38438
38600
  // src/index.ts
38439
38601
  import * as Protocols from "@axiom-lattice/protocols";
38440
38602
 
@@ -39799,7 +39961,7 @@ function createMetricsRuntimeTool(params) {
39799
39961
  // src/middlewares/semanticMetricsModelingSkill.ts
39800
39962
  var CONTENT = `---
39801
39963
  name: semantic-metrics-modeling
39802
- 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.
39964
+ description: Builder policy for turning a granted datasource into published semantic tables and metrics. Defines the orchestrator/worker contract \u2014 the orchestrator agrees goals, proposes the model, plans persistent tasks, and delegates execution to general-purpose workers with self-contained briefs; workers execute one bound brief each. Governs goal agreement, delegation, FEP verification, belief-state reconciliation, and continuous refinement until acceptance evidence is met.
39803
39965
  ---
39804
39966
 
39805
39967
  # Semantic Metrics Modeling
@@ -39808,6 +39970,15 @@ You are the Semantic Metrics Builder. You turn physical datasource tables into r
39808
39970
  **semantic tables** and **business metrics** on a Metrics Server (\`/api/v1\`). Work is
39809
39971
  governed, observable, and continuously refined \u2014 never a one-shot guess.
39810
39972
 
39973
+ You always operate in exactly ONE of two roles:
39974
+
39975
+ - **Orchestrator** (default; no \`## Bound Task\` section in your context): you face the
39976
+ user. You agree the Goal Model, propose the model, plan persistent tasks, dispatch
39977
+ execution to workers, reconcile belief, and own every user interaction.
39978
+ - **Worker** (your context contains a \`## Bound Task\` section naming you executor of one
39979
+ task): you execute that task's brief only. See **Worker mode** \u2014 its rules override the
39980
+ orchestrator policy.
39981
+
39811
39982
  ## Goal Model
39812
39983
 
39813
39984
  Before any exploration or publishing, agree with the user on:
@@ -39816,16 +39987,17 @@ Before any exploration or publishing, agree with the user on:
39816
39987
  - **Usable state**: observable conditions that make the published meta useful.
39817
39988
  - **Scope**: which datasource/tables, and what is explicitly out of scope.
39818
39989
  - **Acceptance evidence**: objective criteria (e.g. "metric \`sell_in_nes\` returns sane monthly
39819
- totals for 2024") used to decide success.
39990
+ totals for 2024") used to decide success. Verbatim acceptance evidence is required later by
39991
+ the Verify dispatch \u2014 record it exactly.
39820
39992
  Do not guess material goals, consumers, or acceptance evidence.
39821
39993
 
39822
39994
  **Vague requests** (e.g. "build the metric layer") \u2014 do not act and do not ask blind questions.
39823
- First run cheap read-only observations (\`list_datasources\`, \`get_grants\`, \`list_tables\`,
39824
- \`list_metrics\`) to see what is authorized and already published, then ask focused questions that
39825
- carry that context and offer concrete options (which datasource/tables, which business questions,
39826
- extend existing metrics or build new). Every clarification question must include enough context and
39827
- options for the user to answer in one step. Only after the user picks a direction does the Goal
39828
- Model become confirmable \u2014 record it, create the task, and proceed to the workflow.
39995
+ First run cheap read-only observations (\`list_datasources\`, \`get_grants\`, \`list_metrics\`) to
39996
+ see what is authorized and already published, then ask focused questions that carry that
39997
+ context and offer concrete options (which datasource/tables, which business questions, extend
39998
+ existing metrics or build new). Every clarification question must include enough context and
39999
+ options for the user to answer in one step. Only after the user picks a direction does the
40000
+ Goal Model become confirmable \u2014 record it, create the task, and proceed to the workflow.
39829
40001
 
39830
40002
  ## Target model and quality bar
39831
40003
 
@@ -39863,19 +40035,152 @@ Apply this loop to every step (explore, publish table, publish metric, verify):
39863
40035
  - **Decide**: classify as **RETAIN** (confirmed), **REVERT** (rejected), or **INCONCLUSIVE**.
39864
40036
  - **Reconcile**: update the belief state and plan, then repeat while decision-relevant action remains.
39865
40037
 
39866
- Renew user approval when a foundational assumption or the goal changes.
39867
-
39868
- ## Task Policy
40038
+ The orchestrator applies the loop **between dispatches** (each observation updates the plan
40039
+ before the next brief is written). A worker applies it **inside its brief**.
39869
40040
 
39870
- Use persistent TaskItems as your planning surface. Do not use \`write_todos\`. Create a child task
39871
- only for an independently verifiable outcome (e.g. "publish table meta for \`hankel_distr_sell_in\`").
39872
- Exploration queries and tool calls are activities inside the active task. See the
39873
- \`task-definition\` skill for \`manage_task\` operation details.
39874
-
39875
- ## Belief State
40041
+ Renew user approval when a foundational assumption or the goal changes.
39876
40042
 
39877
- Record your modeling beliefs in the active task's description under a \`## Belief State\` section as
39878
- a Markdown table:
40043
+ ## Orchestrator: Task Policy
40044
+
40045
+ You are an orchestrator, not the hands. Exactly five duties:
40046
+
40047
+ 1. **Goal Model agreement** \u2014 including cheap read-only observation for vague requests
40048
+ (\`list_datasources\`, \`get_grants\`, \`list_metrics\`). This is your ONLY inline datasource
40049
+ access; do not use \`write_todos\`.
40050
+ 2. **Propose the model** and get user approval.
40051
+ 3. **Task tree** \u2014 parent task = contract + \`## Belief State\`; child tasks = independently
40052
+ verifiable outcomes (explore / publish-table / publish-metric / verify), one per dispatch.
40053
+ See the \`task-definition\` skill for \`manage_task\` operation details.
40054
+ 4. **Dispatch and collect** \u2014 \`task { taskId, agentId: "general-purpose" }\`; read the
40055
+ observation; record the \`executionResultId\` on the child task with \`manage_task update\` or
40056
+ \`add_activity\`; reconcile \`## Belief State\`.
40057
+ 5. **HITL** \u2014 every \`ask_user_to_clarify\` is yours. Workers never ask the user.
40058
+
40059
+ Hard rules:
40060
+ - Never run exploration SQL inline. Never build or publish payloads inline (sole exception:
40061
+ the Publish/Verify inline fallback below).
40062
+ - **Belief State: you are the sole writer.** Workers return findings in their results; you
40063
+ update \`## Belief State\` via \`manage_task update\` on the parent task. Workers never touch it.
40064
+ - **Dispatch serially** \u2014 one worker at a time; reconcile belief before writing the next brief.
40065
+ - **Distinguish dispatch failure from worker outcome**: a dispatch failure is a tool-level
40066
+ error where the worker never ran. A worker returning INCONCLUSIVE or failed is a normal FEP
40067
+ input \u2014 reconcile it, never treat it as a dispatch failure.
40068
+
40069
+ Dispatch failure handling (worker never ran, tool error):
40070
+ 1. Retry the dispatch once (recreate the child task if the store reports it unusable).
40071
+ 2. **Explore: never execute inline.** If the retry fails, stop and ask the user via
40072
+ \`ask_user_to_clarify\` (report what is blocked and why).
40073
+ 3. **Publish/Verify: after a failed retry you MAY execute inline** to preserve delivery \u2014
40074
+ the payload decisions are already in your context. Follow the same gate self-check as a
40075
+ worker would.
40076
+
40077
+ ## Delegation Protocol
40078
+
40079
+ Mechanics every brief must be designed around:
40080
+
40081
+ - A worker sees ONLY: its task title + description, the parent task's description, and the
40082
+ results of completed dependency tasks. It does NOT see this conversation.
40083
+ - Therefore **every brief is self-contained**: all decisions, boundaries, and evidence travel
40084
+ inside the task description.
40085
+ - Dispatch is synchronous: \`task { taskId, agentId: "general-purpose" }\` returns an
40086
+ observation (the worker's final message, truncated at ~8k chars) and an
40087
+ \`executionResultId\`. Record the id on the child task (\`manage_task update\`/\`add_activity\`).
40088
+ - The worker settles its own task (\`set_status\` with \`result\`/\`failureReason\`). Read both the
40089
+ observation and the task result before reconciling.
40090
+
40091
+ Write briefs as field checklists adapted to the situation \u2014 decisions and evidence, not prose.
40092
+ The worker assembles payloads from the reference sections of this skill; the brief carries the
40093
+ approved decisions, never full payload JSON.
40094
+
40095
+ ### Explore brief (\`Explore <schema>.<table> for <goal>\`)
40096
+
40097
+ Required fields:
40098
+ 1. Datasource: serverKey/connectionKey + datasourceId (and \`runConfig.metricsDataSource\` preset if present).
40099
+ 2. Grant boundary: the allowed schema + table pattern from \`get_grants\`, verbatim; never probe outside it.
40100
+ 3. Target table(s): schema-qualified names; one brief per table.
40101
+ 4. Question list: per column (or column group) \u2014 business meaning candidates, expected role
40102
+ (dimension | measure | time), net/gross, grain.
40103
+ 5. Method: read-only SELECT/WITH only; use the \`references/metadata-sql.md\` templates
40104
+ (columns, sample rows, value distribution); cap sample size (e.g. \u22641000 rows, \u226450 groups).
40105
+ Prefer targeted queries over bulk catalog dumps. A large single read (e.g. full
40106
+ \`read_semantic_catalog\` detail) is allowed \u2014 your isolation protects the orchestrator's
40107
+ context \u2014 but findings must be compressed to conclusion level.
40108
+ 6. Output contract: structured findings \u2014 per column: observed type, sample values,
40109
+ distribution highlights, role candidate + evidence, \`INCONCLUSIVE\` marking for unresolved
40110
+ semantics.
40111
+ 7. Invariants: read-only only; grant boundary absolute; never guess \u2014 \`INCONCLUSIVE\` instead.
40112
+ 8. Closing: settle the task (\`set_status completed\`, result = findings summary); final message
40113
+ = the structured findings (it becomes the observation).
40114
+
40115
+ ### Publish-table brief (\`Publish table meta <objectKey>\`)
40116
+
40117
+ Required fields:
40118
+ 1. Approved decisions: full column list (name/type/role/label/description), grain,
40119
+ displayName/docType/shortDesc/sourceSystem/sourceTables.
40120
+ 2. Identity: \`objectKey\` (stable, unique per datasource) + \`schemaName.tableName\`.
40121
+ 3. Assembly instruction: full \`table_view_detail\` payload per **Publish table meta** below,
40122
+ plus the identity twin (\`table_catalog\`, same \`objectKey\`), plus an EXACT \`accessGrant\`
40123
+ matching the tenant grant.
40124
+ 4. Gate self-check: publish gate items 1\u20133 \u2014 do not publish if any fails.
40125
+ 5. Publish via \`metrics_meta_tool\` \`create_table\`; then \`get_meta\` to confirm visibility.
40126
+ 6. Mistakes: fix with \`update_table\`; never leave a partial publish.
40127
+ 7. Invariants: EXACT patternType; every column tagged and labeled.
40128
+ 8. Closing: settle the task; final message = receipts (objectKeys + get_meta confirmation).
40129
+
40130
+ ### Publish-metric brief (\`Publish metric <objectKey>\`)
40131
+
40132
+ Required fields (per metric):
40133
+ 1. Identity: \`objectKey\` = \`metric_name\`, display_name, domain, description, data_type, format.
40134
+ 2. Source: schema-qualified \`source.table_view\` (must match the published table meta).
40135
+ 3. Calculation: aggregate (\`aggregation\` + \`measure\`, with the confirmed business meaning) or
40136
+ derived (ratio references / formula) \u2014 exactly as approved in Propose the model.
40137
+ 4. \`supported_dimensions\`: array of objects \`{dim_id, field_name, label, data_type}\`,
40138
+ including the time dimension.
40139
+ 5. \`default_time_context\`: time_dimension + granularity + supported_grains (+ window if requested).
40140
+ 6. \`ai_agent_context\`: polarity, synonyms, human_readable_explanation.
40141
+ 7. Assembly instruction: \`metric_index\` then \`metric_detail\` in the FULL runtime style per
40142
+ **Publish metric meta** below; publish via \`metrics_meta_tool\` \`create_metric\`.
40143
+ 8. Gate self-check + smoke \`query\` (one grouping by the default time grain) + \`get_meta\`
40144
+ receipts; closing = settle the task, final message = receipts.
40145
+
40146
+ ### Verify brief (\`Verify <metric> against acceptance evidence\`)
40147
+
40148
+ Required fields:
40149
+ 1. Acceptance evidence verbatim (from the Goal Model).
40150
+ 2. Queries to run (semantic \`query\` via \`metrics_runtime_tool\`) and the expected shape/values.
40151
+ 3. Report contract: PASS/FAIL verdict + actual vs expected; on FAIL include the differences
40152
+ and a suspicion list \u2014 do NOT modify meta (fixes are new Publish tasks).
40153
+ 4. Invariants: read-only only.
40154
+ 5. Closing: settle the task; final message = the verdict summary.
40155
+
40156
+ ### Brief closing (all types)
40157
+
40158
+ - Invariants line: grant boundary + read-only SQL + publish gate before any create.
40159
+ - Result structure: the structured summary the orchestrator expects back.
40160
+ - Finish by settling the task (\`set_status completed\` with result, or \`failed\` with
40161
+ failureReason) and making the final message that structured summary.
40162
+
40163
+ ## Worker mode
40164
+
40165
+ Trigger: your context contains \`## Bound Task\`. You are a worker; these rules override the
40166
+ orchestrator policy (Safety and the reference sections still apply):
40167
+
40168
+ - Execute the bound task's brief only. Read the contract with \`manage_task get\`; the task
40169
+ description is authoritative. Load this skill if the bootstrap asks \u2014 you need its payload
40170
+ reference sections.
40171
+ - Do NOT: re-agree the Goal Model, create sibling or child tasks, dispatch \`task\`, call
40172
+ \`ask_user_to_clarify\`, or update the parent task's \`## Belief State\`.
40173
+ - Apply the FEP loop inside the brief; obey the grant boundary and read-only SQL; run the
40174
+ publish gate before any create.
40175
+ - Unclear semantics: mark \`INCONCLUSIVE\` with candidates + evidence in your findings. Never
40176
+ guess, never publish on a guess.
40177
+ - Finish: \`set_status completed\` with a structured result (or \`failed\` with failureReason),
40178
+ and make your final message the structured summary \u2014 it is the observation your
40179
+ orchestrator reads.
40180
+
40181
+ ## Belief State (orchestrator-owned)
40182
+
40183
+ The parent task's description carries a \`## Belief State\` section as a Markdown table:
39879
40184
 
39880
40185
  \`\`\`
39881
40186
  | Belief Key | Probability | Target | Basis |
@@ -39884,31 +40189,35 @@ a Markdown table:
39884
40189
  \`\`\`
39885
40190
 
39886
40191
  Rules: belief keys are lowercase kebab-case; probability/target are percentages 0\u2013100% that
39887
- represent evidence support, not calibrated probability. Update this section each FEP reconcile so
39888
- the task always reflects the current evidence.
40192
+ represent evidence support, not calibrated probability. Only the orchestrator writes this
40193
+ section \u2014 after each dispatch it folds the worker's findings into the table so the parent
40194
+ task always reflects the current evidence.
39889
40195
 
39890
40196
  ## Workflow
39891
40197
 
39892
- 1. **Pick the datasource.** \`metrics_datasource_tool\` action \`list_datasources\`, or the preset
39893
- \`runConfig.metricsDataSource\` (\`serverKey\`\u2192connectionKey, \`datasourceId\`).
39894
- 2. **Read the boundary.** \`get_grants\` \u2192 note the allowed schema + table pattern. Never probe outside it.
39895
- 3. **Explore within the grant.** \`query\` with read-only SQL. Use the templates in
39896
- \`references/metadata-sql.md\`; if the user supplied schema docs or sample files, read them first
39897
- via filesystem to reduce querying.
39898
- 4. **Propose the model.** Present the table columns (with \`role: dimension | measure\`) and the
39899
- metrics (aggregate/derived) for approval before publishing.
39900
- 5. **Publish the semantic table.** \`metrics_meta_tool\` \`create_table\`.
39901
- 6. **Publish the metric.** \`metrics_meta_tool\` \`create_metric\` \u2014 \`metric_index\` then \`metric_detail\`
39902
- using the SQL-free \`calculation\` DSL.
39903
- 7. **Verify.** \`metrics_runtime_tool\` \`get_meta\`, then \`query\` the metric against acceptance evidence.
39904
-
39905
- ## 1. Explore
40198
+ 1. **Pick the datasource + cheap observation.** \`metrics_datasource_tool\` action
40199
+ \`list_datasources\`, or the preset \`runConfig.metricsDataSource\` (\`serverKey\`\u2192connectionKey,
40200
+ \`datasourceId\`). Inline, read-only.
40201
+ 2. **Agree the Goal Model.** (HITL)
40202
+ 3. **Create the parent task** \u2014 contract + \`## Belief State\` (seeded from the Goal Model).
40203
+ 4. **Explore by dispatch** \u2014 one Explore brief per table, serial; collect findings; reconcile
40204
+ \`## Belief State\`; collect \`INCONCLUSIVE\` columns.
40205
+ 5. **Propose the model** (HITL) \u2014 present table columns (with \`role: dimension | measure\`)
40206
+ and the metrics (aggregate/derived) for approval; include clarify questions for
40207
+ \`INCONCLUSIVE\` columns in the same ask.
40208
+ 6. **Publish tables by dispatch** \u2014 one Publish-table brief per table; check receipts.
40209
+ 7. **Publish metrics by dispatch** \u2014 one Publish-metric brief per metric; receipts + smoke query.
40210
+ 8. **Verify by dispatch** \u2014 Verify brief against acceptance evidence. FAIL \u2192 reconcile
40211
+ belief \u2192 fix decisions \u2192 new Publish task (\`update_table\`/\`update_metric\`) \u2192 re-Verify.
40212
+ PASS \u2192 complete the parent task (result = acceptance evidence met).
40213
+
40214
+ ## Explore (reference)
39906
40215
 
39907
40216
  Read \`table-grants\`, then probe with \`query\`. SQL is validated read-only by the client and the
39908
40217
  server enforces the grant; un-granted tables return \`TABLE_NOT_GRANTED\`. Prefer the
39909
40218
  \`references/metadata-sql.md\` templates because dialect varies (PostgreSQL / SQL Server / HANA).
39910
- If the user provides a data dictionary or sample data file, read it with filesystem and reconcile it
39911
- against the probed columns.
40219
+ If the user provides a data dictionary or sample data file, read it with filesystem and
40220
+ reconcile it against the probed columns.
39912
40221
 
39913
40222
  ## Unclear field semantics
39914
40223
 
@@ -39917,7 +40226,7 @@ sum, a rate to average, or an enum to filter). Publishing meta on a misunderstoo
39917
40226
  the runtime and every downstream metric that depends on it, and delete is not available. Treat this
39918
40227
  as FEP **INCONCLUSIVE** \u2014 never guess, and never publish on an unverified guess.
39919
40228
 
39920
- Resolve in order of increasing cost:
40229
+ Resolve in order of increasing cost (inside the Explore brief):
39921
40230
  1. **Probe sample values and distribution** (\`query\`, templates in \`references/metadata-sql.md\`):
39922
40231
  - numbers in (0,1) or clustered near 100 \u2192 likely a ratio/percentage \u2192 dimension or \`avg\`, rarely \`sum\`;
39923
40232
  - large additive amounts (currency, counts) \u2192 measure with \`sum\`;
@@ -39929,14 +40238,16 @@ Resolve in order of increasing cost:
39929
40238
 
39930
40239
  If evidence is still INCONCLUSIVE:
39931
40240
  - Do **not** publish meta that depends on the unclear field.
39932
- - List the field with its candidate interpretations in the **Propose the model** step and ask the
39933
- user to confirm its semantics (role, value meaning, net/gross) via ask_user_to_clarify. The user
39934
- does not need to see the table \u2014 your probed schema, samples, and candidates are enough.
39935
- - Record a low-probability belief entry (e.g.
39936
- \`| sales-nes-semantics | 40% | 100% | user must confirm role / net amount |\`) so verify/refine can
39937
- revisit it later instead of assuming it is settled.
40241
+ - The worker marks the column \`INCONCLUSIVE\` (candidates + evidence) in its findings; the
40242
+ **orchestrator** lists it with candidate interpretations in the **Propose the model** step
40243
+ and asks the user to confirm its semantics (role, value meaning, net/gross) via
40244
+ \`ask_user_to_clarify\`. The user does not need to see the table \u2014 probed schema, samples, and
40245
+ candidates are enough.
40246
+ - The orchestrator records a low-probability belief entry (e.g.
40247
+ \`| sales-nes-semantics | 40% | 100% | user must confirm role / net amount |\`) so verify/refine
40248
+ can revisit it later instead of assuming it is settled.
39938
40249
 
39939
- ## 2. Publish table meta (\`create_table\`)
40250
+ ## Publish table meta (\`create_table\`)
39940
40251
 
39941
40252
  Publish the authoritative shape below (objectType \`table_view_detail\`, with an EXACT accessGrant):
39942
40253
 
@@ -39979,7 +40290,7 @@ Design rules:
39979
40290
  - Runtime table publication uses \`patternType: "EXACT"\` (\`PREFIX\` is only for datasource-level exploration scopes).
39980
40291
  - For each semantic table also publish the identity twin: the same body with \`objectType: "table_catalog"\` and the same \`objectKey\` (same or richer payload).
39981
40292
 
39982
- ## 3. Publish metric meta (\`create_metric\`)
40293
+ ## Publish metric meta (\`create_metric\`)
39983
40294
 
39984
40295
  Two steps for the same \`objectKey\`.
39985
40296
 
@@ -40087,11 +40398,13 @@ Design rules:
40087
40398
  - Do not inline raw SQL for new DB-backed metrics (complex logic belongs in a view).
40088
40399
  - Use \`update_metric\` / \`update_table\` to correct mistakes; no removal actions are exposed.
40089
40400
 
40090
- ## 4. Verify and refine
40401
+ ## Verify and refine
40091
40402
 
40092
- - \`get_meta\` \u2192 confirm the table and metric are visible.
40093
- - \`query\` the metric against the acceptance evidence. On failure, apply the FEP reconcile: update the
40094
- \`## Belief State\`, fix the meta, and retry \u2014 until acceptance evidence is met.
40403
+ - Verify is **dispatched** (Verify brief). The worker runs \`get_meta\` \u2192 confirms the table and
40404
+ metric are visible, then \`query\`es the metric against acceptance evidence.
40405
+ - On FAIL the worker reports differences; the **orchestrator** applies the FEP reconcile:
40406
+ update \`## Belief State\`, fix the decisions, and dispatch a new Publish task
40407
+ (\`update_table\`/\`update_metric\`) \u2014 then re-Verify \u2014 until acceptance evidence is met.
40095
40408
 
40096
40409
  ## Troubleshooting
40097
40410
 
@@ -40103,6 +40416,8 @@ Design rules:
40103
40416
  | derived metric create fails | numerator/denominator metrics don't exist yet \u2014 publish them first |
40104
40417
  | datasource \`query\` rejected | SQL was not read-only (SELECT/WITH only) or multi-statement |
40105
40418
  | \`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 |
40419
+ | worker observation truncated | findings exceeded ~8k chars; worker must keep the final message a compact structured summary |
40420
+ | dispatch failed (tool error) | retry once; Explore never goes inline \u2014 ask the user; Publish/Verify may go inline after the failed retry |
40106
40421
 
40107
40422
  ## Safety
40108
40423
 
@@ -40159,15 +40474,35 @@ the SQL is validated read-only.
40159
40474
  "examples/metric-aggregate.json": {
40160
40475
  content: `{
40161
40476
  "objectType": "metric_detail",
40162
- "objectKey": "hankel_sell_in_nes",
40477
+ "objectKey": "sell_in_nes",
40163
40478
  "status": 1,
40164
40479
  "payload": {
40165
- "name": "hankel_sell_in_nes",
40166
- "displayName": "Sell-in NES",
40480
+ "metric_name": "sell_in_nes",
40481
+ "display_name": "Sell-in NES",
40482
+ "domain": "sales",
40167
40483
  "description": "Net external sales amount from distributor sell-in rows.",
40168
- "sourceTable": "hankel_distr_sell_in",
40484
+ "data_type": "numeric",
40485
+ "format": "currency",
40486
+ "source_type": "cdp_postgres",
40487
+ "source": { "table_view": "public.hankel_distr_sell_in", "base_filters": [] },
40169
40488
  "calculation": { "type": "aggregate", "aggregation": "sum", "measure": "nes" },
40170
- "dimensions": ["posting_year", "posting_month", "sales_team", "region"]
40489
+ "supported_dimensions": [
40490
+ { "dim_id": "posting_year", "field_name": "posting_year", "label": "Posting Year", "data_type": "number" },
40491
+ { "dim_id": "sales_team", "field_name": "sales_team", "label": "Sales Team", "data_type": "string" },
40492
+ { "dim_id": "posting_date", "field_name": "posting_date", "label": "Posting Date", "data_type": "string" }
40493
+ ],
40494
+ "default_time_context": {
40495
+ "time_dimension": "posting_date",
40496
+ "label": "Posting date",
40497
+ "granularity": "month",
40498
+ "window": "YTD",
40499
+ "supported_grains": ["month", "year"]
40500
+ },
40501
+ "ai_agent_context": {
40502
+ "polarity": "positive",
40503
+ "synonyms": ["sell in", "nes", "net external sales"],
40504
+ "human_readable_explanation": "Higher sell-in NES means more goods purchased from the distributor."
40505
+ }
40171
40506
  }
40172
40507
  }
40173
40508
  `
@@ -40175,27 +40510,40 @@ the SQL is validated read-only.
40175
40510
  "examples/metric-derived.json": {
40176
40511
  content: `{
40177
40512
  "objectType": "metric_detail",
40178
- "objectKey": "hankel_gross_margin_rate",
40513
+ "objectKey": "gross_margin_rate",
40179
40514
  "status": 1,
40180
40515
  "payload": {
40181
- "name": "hankel_gross_margin_rate",
40182
- "displayName": "Gross Margin Rate",
40516
+ "metric_name": "gross_margin_rate",
40517
+ "display_name": "Gross Margin Rate",
40518
+ "domain": "sales",
40183
40519
  "description": "Gross margin divided by sell-in NES.",
40184
- "sourceTable": "hankel_distr_sell_in",
40185
- "calculation": {
40186
- "type": "derived",
40187
- "operator": "ratio",
40188
- "numerator": "hankel_gross_margin",
40189
- "denominator": "hankel_sell_in_nes"
40520
+ "data_type": "numeric",
40521
+ "format": "percent",
40522
+ "source_type": "cdp_postgres",
40523
+ "source": { "table_view": "public.hankel_distr_sell_in", "base_filters": [] },
40524
+ "calculation": { "type": "derived", "operator": "ratio", "numerator": "gross_margin", "denominator": "sell_in_nes" },
40525
+ "supported_dimensions": [
40526
+ { "dim_id": "posting_year", "field_name": "posting_year", "label": "Posting Year", "data_type": "number" },
40527
+ { "dim_id": "posting_date", "field_name": "posting_date", "label": "Posting Date", "data_type": "string" }
40528
+ ],
40529
+ "default_time_context": {
40530
+ "time_dimension": "posting_date",
40531
+ "label": "Posting date",
40532
+ "granularity": "month",
40533
+ "supported_grains": ["month", "year"]
40190
40534
  },
40191
- "dimensions": ["posting_year", "sales_team", "region"]
40535
+ "ai_agent_context": {
40536
+ "polarity": "positive",
40537
+ "synonyms": ["gross margin rate", "margin rate"],
40538
+ "human_readable_explanation": "Gross margin rate divides gross margin by sell-in NES; higher means more margin retained on sold-in goods."
40539
+ }
40192
40540
  }
40193
40541
  }
40194
40542
  `
40195
40543
  }
40196
40544
  };
40197
40545
  var SEMANTIC_METRICS_MODELING_SKILL = {
40198
- version: "1.0.0",
40546
+ version: "1.1.2",
40199
40547
  content: CONTENT,
40200
40548
  resources
40201
40549
  };
@@ -40209,7 +40557,7 @@ Never announce the skill load. If it fails, retry once, then stop and explicitly
40209
40557
  report that the required Semantic Metrics Builder skill could not be loaded.`;
40210
40558
 
40211
40559
  // src/middlewares/semanticMetricsMiddleware.ts
40212
- import { AgentType as AgentType8 } from "@axiom-lattice/protocols";
40560
+ import { AgentType as AgentType9 } from "@axiom-lattice/protocols";
40213
40561
  function createSemanticMetricsMiddleware(config) {
40214
40562
  const connections = config.connections ?? [];
40215
40563
  const connectAll = config.connectAll === true;
@@ -40361,7 +40709,7 @@ var semanticMetricsPlugin = {
40361
40709
  key: "semantic-metrics-builder",
40362
40710
  name: "Semantic Metrics Builder",
40363
40711
  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.",
40364
- type: AgentType8.DEEP_AGENT,
40712
+ type: AgentType9.DEEP_AGENT,
40365
40713
  prompt: SEMANTIC_METRICS_BUILDER_PROMPT,
40366
40714
  middleware: [
40367
40715
  {
@@ -41947,7 +42295,65 @@ var widgetPlugin = {
41947
42295
  // src/middlewares/taskMiddleware.ts
41948
42296
  import { createMiddleware as createMiddleware24, tool as tool67 } from "langchain";
41949
42297
  import { z as z73 } from "zod";
41950
- import { GraphInterrupt as GraphInterrupt2, interrupt as interrupt4 } from "@langchain/langgraph";
42298
+ import { GraphInterrupt as GraphInterrupt3, interrupt as interrupt4 } from "@langchain/langgraph";
42299
+
42300
+ // src/util/truncateForJson.ts
42301
+ var TRUNCATION_MARKER = "...[truncated]";
42302
+ function truncateString(value, cap) {
42303
+ if (value.length <= cap) return value;
42304
+ const budget = Math.max(0, cap - TRUNCATION_MARKER.length);
42305
+ return value.slice(0, budget) + TRUNCATION_MARKER;
42306
+ }
42307
+ function truncateValue(value, depth, maxDepth, maxEntries, maxStringLength, seen) {
42308
+ if (typeof value === "string") return truncateString(value, maxStringLength);
42309
+ if (value === null || typeof value !== "object") return value;
42310
+ if (depth >= maxDepth) return "[truncated:max-depth]";
42311
+ if (seen.has(value)) return "[Circular]";
42312
+ seen.add(value);
42313
+ try {
42314
+ if (value instanceof Date) return value.toISOString();
42315
+ if (Array.isArray(value)) {
42316
+ const limit2 = Math.min(value.length, maxEntries);
42317
+ const output2 = [];
42318
+ for (let index = 0; index < limit2; index += 1) {
42319
+ output2.push(truncateValue(value[index], depth + 1, maxDepth, maxEntries, maxStringLength, seen));
42320
+ }
42321
+ if (value.length > limit2) output2.push("[truncated:entries]");
42322
+ return output2;
42323
+ }
42324
+ const record = value;
42325
+ const output = {};
42326
+ const keys = Object.keys(record);
42327
+ const limit = Math.min(keys.length, maxEntries);
42328
+ for (let index = 0; index < limit; index += 1) {
42329
+ const key5 = keys[index];
42330
+ output[truncateString(key5, maxStringLength)] = truncateValue(
42331
+ record[key5],
42332
+ depth + 1,
42333
+ maxDepth,
42334
+ maxEntries,
42335
+ maxStringLength,
42336
+ seen
42337
+ );
42338
+ }
42339
+ if (keys.length > limit) output["[truncated]"] = true;
42340
+ return output;
42341
+ } finally {
42342
+ seen.delete(value);
42343
+ }
42344
+ }
42345
+ function truncateForJson(value, options = {}) {
42346
+ return truncateValue(
42347
+ value,
42348
+ 0,
42349
+ options.maxDepth ?? JSON_SAFE_MAX_DEPTH,
42350
+ options.maxEntries ?? JSON_SAFE_MAX_COLLECTION_ENTRIES,
42351
+ options.maxStringLength ?? JSON_SAFE_MAX_STRING_LENGTH,
42352
+ /* @__PURE__ */ new WeakSet()
42353
+ );
42354
+ }
42355
+
42356
+ // src/middlewares/taskMiddleware.ts
41951
42357
  import {
41952
42358
  isExecutionResultEventKey as isExecutionResultEventKey3,
41953
42359
  parseTaskBeliefState as parseTaskBeliefState2,
@@ -42277,6 +42683,132 @@ function getRuntimeActor2(runConfig) {
42277
42683
  if (runConfig.user_id) return `user:${String(runConfig.user_id)}`;
42278
42684
  return void 0;
42279
42685
  }
42686
+ function readRuntimeRunConfig(source) {
42687
+ const s = source;
42688
+ const rc = s?.context?.runConfig ?? s?.configurable?.runConfig;
42689
+ return rc && typeof rc === "object" && !Array.isArray(rc) ? rc : {};
42690
+ }
42691
+ function readExecutionTaskId(runConfig) {
42692
+ const execution = runConfig.execution;
42693
+ if (!execution || typeof execution !== "object" || Array.isArray(execution)) return void 0;
42694
+ const value = execution.taskId;
42695
+ return typeof value === "string" && value.trim() !== "" ? value : void 0;
42696
+ }
42697
+ function renderTaskBinding(taskId) {
42698
+ return `
42699
+
42700
+ ## Bound Task
42701
+
42702
+ You are executing task \`${taskId}\`. Read its contract with \`manage_task get\`, update it as you work, and complete it when done.
42703
+ `;
42704
+ }
42705
+ function createBoundTaskLifecycle() {
42706
+ return createTaskLifecycleService({ taskStore: getTaskStore(), workItemStore: getTaskWorkItemStore() });
42707
+ }
42708
+ function createBoundTaskBridge() {
42709
+ return createTaskRunBridge({ lifecycle: createBoundTaskLifecycle() });
42710
+ }
42711
+ function isResumableInterruption(interruption) {
42712
+ if (!interruption || typeof interruption !== "object" || Array.isArray(interruption)) return false;
42713
+ const type = interruption.type;
42714
+ return type === "missing_input" || type === "user_decision";
42715
+ }
42716
+ var TASK_WORKER_OBSERVATION_MAX_CHARS = 8192;
42717
+ function snapshotMessages(state) {
42718
+ if (!state || typeof state !== "object") return [];
42719
+ const values = state.values;
42720
+ if (!values || typeof values !== "object") return [];
42721
+ const messages = values.messages;
42722
+ return Array.isArray(messages) ? messages : [];
42723
+ }
42724
+ function messageText(value) {
42725
+ if (typeof value === "string") return value;
42726
+ if (!Array.isArray(value)) return void 0;
42727
+ return value.flatMap((part) => {
42728
+ if (typeof part === "string") return [part];
42729
+ if (part && typeof part === "object" && typeof part.text === "string") {
42730
+ return [part.text];
42731
+ }
42732
+ return [];
42733
+ }).join("");
42734
+ }
42735
+ function lastAssistantText(source) {
42736
+ const messages = Array.isArray(source) ? source : source && typeof source === "object" && Array.isArray(source.messages) ? source.messages : snapshotMessages(source);
42737
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
42738
+ const message = messages[index];
42739
+ if (!message || typeof message !== "object") continue;
42740
+ const role = message.role ?? message.type;
42741
+ if (role !== "ai" && role !== "assistant") continue;
42742
+ const text = messageText(message.content);
42743
+ if (text !== void 0) return text;
42744
+ }
42745
+ return void 0;
42746
+ }
42747
+ function boundedWorkerObservation(result, state) {
42748
+ const text = lastAssistantText(state) ?? lastAssistantText(result) ?? "";
42749
+ return {
42750
+ status: "completed",
42751
+ output: truncateForJson(text, { maxStringLength: TASK_WORKER_OBSERVATION_MAX_CHARS })
42752
+ };
42753
+ }
42754
+ var EXECUTOR_CACHE_TTL_MS = 3e4;
42755
+ var executorCache = /* @__PURE__ */ new Map();
42756
+ function executorString(value) {
42757
+ return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
42758
+ }
42759
+ async function renderAvailableExecutors(rc, tenantId2) {
42760
+ const authority = classifyTaskAuthority(rc);
42761
+ const governed = authority.kind === "projectRoom" || authority.kind === "projectTask";
42762
+ const projectId = governed ? (authority.trusted.projectTask ?? authority.trusted.projectRoom)?.projectId : void 0;
42763
+ const cacheKey = `${tenantId2}:${governed ? `project:${projectId ?? ""}` : "ordinary"}`;
42764
+ const cached = executorCache.get(cacheKey);
42765
+ const now = Date.now();
42766
+ if (cached && now - cached.at < EXECUTOR_CACHE_TTL_MS) return cached.text;
42767
+ const lines = [];
42768
+ try {
42769
+ if (governed && projectId) {
42770
+ const store = getStoreLattice("default", "projectBotMembership").store;
42771
+ if (typeof store.list === "function") {
42772
+ const bots = await store.list(tenantId2, projectId);
42773
+ for (const bot of (Array.isArray(bots) ? bots : []).slice(0, 40)) {
42774
+ const row = bot;
42775
+ if (row.status !== "active") continue;
42776
+ const id = executorString(row.assistantId);
42777
+ if (!id) continue;
42778
+ const title = executorString(row.title);
42779
+ const responsibility = executorString(row.responsibility);
42780
+ lines.push(`- ${id}${title ? ` \u2014 ${title}` : ""}${responsibility ? ` (${responsibility})` : ""}`);
42781
+ }
42782
+ }
42783
+ } else {
42784
+ const configs = await agentLatticeManager.getAllAgentConfigsByTenant(tenantId2);
42785
+ for (const config of configs.slice(0, 40)) {
42786
+ const row = config;
42787
+ const id = executorString(row.key);
42788
+ if (!id) continue;
42789
+ const name = executorString(row.name);
42790
+ const description = executorString(row.description);
42791
+ lines.push(`- ${id}${name ? ` \u2014 ${name}` : ""}${description ? ` (${description.slice(0, 120)})` : ""}`);
42792
+ }
42793
+ }
42794
+ } catch {
42795
+ }
42796
+ if (lines.length === 0) {
42797
+ executorCache.set(cacheKey, { at: now, text: "" });
42798
+ return "";
42799
+ }
42800
+ const header = governed ? "## Available task executors (Project roster)" : "## Available task executors";
42801
+ const text = `
42802
+
42803
+ ${header}
42804
+
42805
+ 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.
42806
+
42807
+ ${lines.join("\n")}
42808
+ `;
42809
+ executorCache.set(cacheKey, { at: now, text });
42810
+ return text;
42811
+ }
42280
42812
  function delegatedTaskScopeError(taskId) {
42281
42813
  return JSON.stringify({
42282
42814
  success: false,
@@ -42646,11 +43178,11 @@ function buildReviewMarkdown(task) {
42646
43178
  }
42647
43179
  var manageTaskSchema = z73.object({
42648
43180
  action: z73.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."),
42649
- id: z73.string().optional().describe("Task ID (required for get, update, add_activity, and delete)"),
43181
+ id: z73.string().optional().describe("Task ID (required for get, update, add_activity; required for delete unless ids is given)"),
42650
43182
  title: z73.string().optional().describe("Task title (required for create)"),
42651
43183
  description: z73.string().optional().describe("Task description in Markdown"),
42652
43184
  priority: z73.enum(["low", "medium", "high"]).optional().describe("Priority level"),
42653
- status: z73.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"),
43185
+ status: z73.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"),
42654
43186
  dueDate: z73.string().optional().describe("Due date (ISO 8601 format)"),
42655
43187
  metadata: z73.record(z73.unknown()).optional().describe("Structured metadata (e.g. projectId, module)"),
42656
43188
  metadataFilter: z73.record(
@@ -42683,7 +43215,8 @@ var manageTaskSchema = z73.object({
42683
43215
  message: "executionResultId must be the execution-result:<threadId> event key returned by task()"
42684
43216
  }).optional().describe(
42685
43217
  "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"
42686
- )
43218
+ ),
43219
+ ids: z73.array(z73.string().trim().min(1)).optional().describe("Task IDs to delete in one batch (delete action only). Use with or instead of id.")
42687
43220
  }).superRefine((input, context) => {
42688
43221
  if (input.executionResultId && input.action !== "update" && input.action !== "set_status" && input.action !== "add_activity") {
42689
43222
  context.addIssue({
@@ -42699,10 +43232,19 @@ var manageTaskSchema = z73.object({
42699
43232
  message: "metadataFilter is valid only for list"
42700
43233
  });
42701
43234
  }
43235
+ if (input.ids && input.action !== "delete") {
43236
+ context.addIssue({
43237
+ code: z73.ZodIssueCode.custom,
43238
+ path: ["ids"],
43239
+ message: "ids is valid only for delete"
43240
+ });
43241
+ }
42702
43242
  });
42703
43243
  var startTaskSchema = z73.object({
42704
43244
  taskId: z73.string().trim().min(1).describe("ID of the persisted TaskItem to start"),
42705
- agentId: z73.string().trim().min(1).describe("ID of the Agent that should execute the task")
43245
+ agentId: z73.string().trim().min(1).describe(
43246
+ `ID of the Agent that should execute the task. Use "general-purpose" to run the caller's own capabilities as an isolated worker.`
43247
+ )
42706
43248
  });
42707
43249
  function mergeTaskUpdateWarnings(existing, added) {
42708
43250
  const warnings = [...existing ?? [], ...added ?? []];
@@ -42839,6 +43381,49 @@ function createTaskMiddleware(options = {}) {
42839
43381
  }
42840
43382
  const ownerId = input.ownerId || trustedScope?.assistantId || (input.ownerType === "agent" ? rc.assistant_id : null) || rc.user_id;
42841
43383
  const store = getTaskStore();
43384
+ const deleteOneTask = async (id) => {
43385
+ if (delegatedTaskId && id !== delegatedTaskId) {
43386
+ return delegatedTaskScopeError(delegatedTaskId);
43387
+ }
43388
+ const existing = await store.getById(tenantId2, id);
43389
+ if (!existing) {
43390
+ return JSON.stringify({
43391
+ success: false,
43392
+ code: "TASK_NOT_FOUND",
43393
+ error: `Task '${id}' was not found.`,
43394
+ hint: "Use manage_task list to see available tasks and their correct IDs."
43395
+ });
43396
+ }
43397
+ if (!taskMatchesRuntimeScope3(existing, workspaceId, projectId)) {
43398
+ return taskScopeAccessError(id);
43399
+ }
43400
+ if (trustedProject?.projectTask) {
43401
+ const trustedFailure = trustedTaskContextFailure(existing, trustedProject.projectTask);
43402
+ if (trustedFailure) return trustedFailure;
43403
+ }
43404
+ let deleted;
43405
+ if (trustedProject) {
43406
+ const snapshot = taskMutationSnapshot(existing);
43407
+ if (!snapshot) return trustedContextError();
43408
+ try {
43409
+ await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
43410
+ } catch (error) {
43411
+ return projectPolicyError(error);
43412
+ }
43413
+ deleted = await store.deleteIfSnapshot(tenantId2, id, snapshot);
43414
+ } else {
43415
+ deleted = await store.delete(tenantId2, id);
43416
+ }
43417
+ if (!deleted) {
43418
+ return JSON.stringify({
43419
+ success: false,
43420
+ code: "TASK_DELETE_FAILED",
43421
+ error: `Task '${id}' was not found or could not be deleted.`,
43422
+ hint: "Use manage_task list to verify the task exists and you have access to it."
43423
+ });
43424
+ }
43425
+ return JSON.stringify({ success: true, message: `Task '${id}' deleted` });
43426
+ };
42842
43427
  switch (input.action) {
42843
43428
  case "create": {
42844
43429
  if (delegatedTaskId && input.parentId !== delegatedTaskId) {
@@ -42994,9 +43579,6 @@ function createTaskMiddleware(options = {}) {
42994
43579
  hint: "Pass the task ID you want to retrieve"
42995
43580
  });
42996
43581
  }
42997
- if (delegatedTaskId && input.id !== delegatedTaskId) {
42998
- return delegatedTaskScopeError(delegatedTaskId);
42999
- }
43000
43582
  const task = await store.getById(tenantId2, input.id);
43001
43583
  if (!task) {
43002
43584
  return JSON.stringify({
@@ -43042,25 +43624,6 @@ function createTaskMiddleware(options = {}) {
43042
43624
  });
43043
43625
  }
43044
43626
  case "list": {
43045
- if (delegatedTaskId) {
43046
- const delegatedTask = await store.getById(tenantId2, delegatedTaskId);
43047
- if (!delegatedTask || !taskMatchesRuntimeScope3(delegatedTask, workspaceId, projectId)) {
43048
- return serializeTaskReadResponse({ success: true, data: [], count: 0 });
43049
- }
43050
- const children = await store.list({
43051
- tenantId: tenantId2,
43052
- workspaceId,
43053
- projectId,
43054
- parentId: delegatedTaskId,
43055
- metadata: input.metadataFilter
43056
- });
43057
- const scopedChildren = children.filter((child) => child.id !== delegatedTaskId && child.parentId === delegatedTaskId && exactScopeMatch(child, delegatedTask));
43058
- return serializeTaskReadResponse({
43059
- success: true,
43060
- data: [delegatedTask, ...scopedChildren],
43061
- count: scopedChildren.length + 1
43062
- });
43063
- }
43064
43627
  const filter2 = {
43065
43628
  tenantId: tenantId2,
43066
43629
  ownerType: input.ownerType,
@@ -43655,41 +44218,31 @@ function createTaskMiddleware(options = {}) {
43655
44218
  });
43656
44219
  return lifecycleMutationResponse(interrupted);
43657
44220
  }
43658
- if (lifecycle && input.status === "in_progress" && existing.status === "interrupted") {
43659
- await validateExecutionResult();
44221
+ if (lifecycle && input.status === "in_progress") {
43660
44222
  const callerError = await revalidateCaller();
43661
44223
  if (callerError) return callerError;
43662
- const resumed = await lifecycle.resumeInterruption({
43663
- tenantId: tenantId2,
43664
- taskId: input.id,
43665
- actor,
43666
- threadId: statusThreadId
43667
- });
43668
- return lifecycleMutationResponse(resumed);
43669
- }
43670
- if (lifecycle && input.status === "in_progress" && existing.status === "pending") {
43671
- await validateExecutionResult();
43672
- const callerError = await revalidateCaller();
43673
- if (callerError) return callerError;
43674
- const started = await lifecycle.startTask({
43675
- tenantId: tenantId2,
43676
- taskId: input.id,
43677
- actor,
43678
- threadId: statusThreadId
43679
- });
43680
- return lifecycleMutationResponse(started);
43681
- }
43682
- if (lifecycle && input.status === "in_progress" && existing.status === "failed") {
43683
- await validateExecutionResult();
43684
- const callerError = await revalidateCaller();
43685
- if (callerError) return callerError;
43686
- const retried = await lifecycle.retryTask({
44224
+ if (existing.status === "interrupted") {
44225
+ return lifecycleMutationResponse(await lifecycle.resumeInterruption({
44226
+ tenantId: tenantId2,
44227
+ taskId: input.id,
44228
+ actor,
44229
+ threadId: statusThreadId
44230
+ }));
44231
+ }
44232
+ if (existing.status === "failed") {
44233
+ return lifecycleMutationResponse(await lifecycle.retryTask({
44234
+ tenantId: tenantId2,
44235
+ taskId: input.id,
44236
+ actor,
44237
+ threadId: statusThreadId
44238
+ }));
44239
+ }
44240
+ return lifecycleMutationResponse(await lifecycle.startTask({
43687
44241
  tenantId: tenantId2,
43688
44242
  taskId: input.id,
43689
44243
  actor,
43690
44244
  threadId: statusThreadId
43691
- });
43692
- return lifecycleMutationResponse(retried);
44245
+ }));
43693
44246
  }
43694
44247
  const effectiveRequireReview = existing.requireReview === true || input.requireReview === true;
43695
44248
  const candidateReviewInterruption = input.status === "interrupted" && input.context?.interruption && typeof input.context.interruption === "object" && input.context.interruption.type === "review_required" && !!input.result?.trim();
@@ -43758,7 +44311,7 @@ function createTaskMiddleware(options = {}) {
43758
44311
  try {
43759
44312
  response = await interrupt4(buildReviewMarkdown(submitted.task));
43760
44313
  } catch (error) {
43761
- if (error instanceof GraphInterrupt2) throw error;
44314
+ if (error instanceof GraphInterrupt3) throw error;
43762
44315
  return lifecycleMutationResponse(submitted, { code: "REVIEW_REQUIRED" });
43763
44316
  }
43764
44317
  if (response?.action === "approve") {
@@ -43870,54 +44423,49 @@ function createTaskMiddleware(options = {}) {
43870
44423
  return successfulTaskResponse(input.id, updatedStatus, true);
43871
44424
  }
43872
44425
  case "delete": {
43873
- if (!input.id) {
43874
- return JSON.stringify({
43875
- success: false,
43876
- error: "id is required for delete action",
43877
- hint: "Pass the task ID you want to delete"
43878
- });
43879
- }
43880
- if (delegatedTaskId && input.id !== delegatedTaskId) {
43881
- return delegatedTaskScopeError(delegatedTaskId);
43882
- }
43883
- const existing = await store.getById(tenantId2, input.id);
43884
- if (!existing) {
43885
- return JSON.stringify({
43886
- success: false,
43887
- code: "TASK_NOT_FOUND",
43888
- error: `Task '${input.id}' was not found.`,
43889
- hint: "Use manage_task list to see available tasks and their correct IDs."
43890
- });
43891
- }
43892
- if (!taskMatchesRuntimeScope3(existing, workspaceId, projectId)) {
43893
- return taskScopeAccessError(input.id);
43894
- }
43895
- if (trustedProject?.projectTask) {
43896
- const trustedFailure = trustedTaskContextFailure(existing, trustedProject.projectTask);
43897
- if (trustedFailure) return trustedFailure;
44426
+ const missingTargetError = JSON.stringify({
44427
+ success: false,
44428
+ error: "id or ids is required for delete action",
44429
+ hint: "Pass the task ID(s) you want to delete"
44430
+ });
44431
+ const requestedIds = input.ids && input.ids.length > 0 ? [.../* @__PURE__ */ new Set([...input.id ? [input.id] : [], ...input.ids])] : void 0;
44432
+ if (requestedIds === void 0) {
44433
+ if (!input.id) {
44434
+ return missingTargetError;
44435
+ }
44436
+ return deleteOneTask(input.id);
43898
44437
  }
43899
- let deleted;
43900
- if (trustedProject) {
43901
- const snapshot = taskMutationSnapshot(existing);
43902
- if (!snapshot) return trustedContextError();
44438
+ const deletedIds = [];
44439
+ const failed = [];
44440
+ for (const id of requestedIds) {
44441
+ let raw;
43903
44442
  try {
43904
- await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
44443
+ raw = await deleteOneTask(id);
43905
44444
  } catch (error) {
43906
- return projectPolicyError(error);
44445
+ failed.push({
44446
+ id,
44447
+ code: "TASK_DELETE_FAILED",
44448
+ error: error instanceof Error ? error.message : String(error)
44449
+ });
44450
+ continue;
44451
+ }
44452
+ const result = JSON.parse(raw);
44453
+ if (result.success) {
44454
+ deletedIds.push(id);
44455
+ } else {
44456
+ failed.push({
44457
+ id,
44458
+ ...result.code ? { code: result.code } : {},
44459
+ error: result.error ?? `Task '${id}' could not be deleted.`
44460
+ });
43907
44461
  }
43908
- deleted = await store.deleteIfSnapshot(tenantId2, input.id, snapshot);
43909
- } else {
43910
- deleted = await store.delete(tenantId2, input.id);
43911
- }
43912
- if (!deleted) {
43913
- return JSON.stringify({
43914
- success: false,
43915
- code: "TASK_DELETE_FAILED",
43916
- error: `Task '${input.id}' was not found or could not be deleted.`,
43917
- hint: "Use manage_task list to verify the task exists and you have access to it."
43918
- });
43919
44462
  }
43920
- return JSON.stringify({ success: true, message: `Task '${input.id}' deleted` });
44463
+ return JSON.stringify({
44464
+ success: failed.length === 0,
44465
+ deleted: deletedIds,
44466
+ failed,
44467
+ summary: `${deletedIds.length} of ${requestedIds.length} deleted`
44468
+ });
43921
44469
  }
43922
44470
  default:
43923
44471
  return JSON.stringify({
@@ -44032,23 +44580,29 @@ function createTaskMiddleware(options = {}) {
44032
44580
  error: "Runtime actor identity is required for persistent task execution"
44033
44581
  });
44034
44582
  }
44583
+ const callerAssistantId = rc.assistant_id;
44584
+ const agentId = input.agentId === "general-purpose" && callerAssistantId ? `${callerAssistantId}-general-purpose` : input.agentId;
44035
44585
  const service2 = createTaskExecutionService({
44036
44586
  taskStore: getTaskStore(),
44037
44587
  workItemStore: getTaskWorkItemStore(),
44038
- resolveAgent: async (targetTenantId, agentId) => !!await agentLatticeManager.getOrLoadWithTenant(targetTenantId, agentId),
44039
- resolveTaskCapability: async (targetTenantId, agentId) => agentHasManagedTaskCapability(
44040
- (await agentLatticeManager.getOrLoadWithTenant(targetTenantId, agentId))?.config
44041
- ),
44588
+ resolveAgent: async (targetTenantId, agentId2) => !!await agentLatticeManager.getOrLoadWithTenant(targetTenantId, agentId2),
44042
44589
  invokeAgent: async (invocation) => {
44043
- const worker = new Agent({
44044
- tenant_id: invocation.tenantId,
44590
+ const workerResult = await agentWorkerGraph.invoke({
44045
44591
  assistant_id: invocation.agentId,
44046
44592
  thread_id: invocation.threadId,
44047
- workspace_id: invocation.workspaceId,
44048
- project_id: invocation.projectId,
44049
- custom_run_config: createDelegatedWorkerRunConfig(invocation.taskId)
44593
+ input: { message: invocation.message },
44594
+ runConfig: {
44595
+ ...rc,
44596
+ assistant_id: invocation.agentId,
44597
+ thread_id: invocation.threadId,
44598
+ taskId: invocation.taskId,
44599
+ tenantId: invocation.tenantId,
44600
+ workspaceId: invocation.workspaceId,
44601
+ projectId: invocation.projectId
44602
+ }
44050
44603
  });
44051
- return worker.invoke({ input: { message: invocation.message } });
44604
+ const finalState = workerResult?.finalState;
44605
+ return boundedWorkerObservation(finalState, void 0);
44052
44606
  }
44053
44607
  });
44054
44608
  const trustedCaller = authority.kind === "projectTask" || authority.kind === "projectRoom" ? authority.trusted.projectTask ?? authority.trusted.projectRoom : void 0;
@@ -44057,7 +44611,7 @@ function createTaskMiddleware(options = {}) {
44057
44611
  workspaceId: rc.workspaceId,
44058
44612
  projectId: rc.projectId,
44059
44613
  taskId: input.taskId,
44060
- agentId: input.agentId,
44614
+ agentId,
44061
44615
  actor,
44062
44616
  callerThreadId: rc.thread_id,
44063
44617
  ...trustedCaller ? { callerMembershipId: trustedCaller.membershipId, callerAssistantId: trustedCaller.assistantId } : {}
@@ -44066,6 +44620,66 @@ function createTaskMiddleware(options = {}) {
44066
44620
  return createMiddleware24({
44067
44621
  name: "TaskMiddleware",
44068
44622
  contextSchema,
44623
+ // Persisted between invocations (ADRs: the run↔task binding survives turns).
44624
+ stateSchema: z73.object({
44625
+ taskId: z73.string().default("")
44626
+ }),
44627
+ // CLAIM: a run that holds a task moves it to in_progress (idempotent).
44628
+ beforeAgent: async (state, runtime) => {
44629
+ const rc = readRuntimeRunConfig(runtime);
44630
+ const bound = typeof state?.taskId === "string" ? state.taskId : "";
44631
+ const taskId = bound || readExecutionTaskId(rc) || "";
44632
+ if (!taskId) return {};
44633
+ if (!taskId) return {};
44634
+ const tenantId2 = rc.tenantId || "default";
44635
+ const threadId = runtime?.configurable?.thread_id;
44636
+ const task = await getTaskStore().getById(tenantId2, taskId);
44637
+ if (!task) return {};
44638
+ const runWorkspaceId = typeof rc.workspaceId === "string" ? rc.workspaceId : void 0;
44639
+ const runProjectId = typeof rc.projectId === "string" ? rc.projectId : void 0;
44640
+ if (task.workspaceId && task.workspaceId !== runWorkspaceId) return {};
44641
+ if (task.projectId && task.projectId !== runProjectId) return {};
44642
+ if (task.status === "completed" || task.status === "failed" || task.status === "cancelled") {
44643
+ return bound ? {} : { taskId };
44644
+ }
44645
+ taskRunRegistry.register(taskId);
44646
+ if (task.status === "pending") {
44647
+ await createBoundTaskBridge().beginRun({
44648
+ tenantId: tenantId2,
44649
+ task,
44650
+ actor: getRuntimeActor2(rc) ?? "system",
44651
+ ...threadId ? { threadId } : {}
44652
+ });
44653
+ } else if (task.status === "interrupted" && isResumableInterruption(task.context?.interruption)) {
44654
+ await createBoundTaskLifecycle().resumeInterruption({
44655
+ tenantId: tenantId2,
44656
+ taskId: task.id,
44657
+ actor: getRuntimeActor2(rc) ?? "system",
44658
+ ...threadId ? { threadId } : {}
44659
+ });
44660
+ }
44661
+ return bound ? {} : { taskId };
44662
+ },
44663
+ // SETTLE: a run that ends without a lifecycle transition converges the task.
44664
+ afterAgent: async (state, runtime) => {
44665
+ const taskId = typeof state?.taskId === "string" ? state.taskId : "";
44666
+ if (!taskId) return {};
44667
+ const rc = readRuntimeRunConfig(runtime);
44668
+ const tenantId2 = rc.tenantId || "default";
44669
+ const threadId = runtime?.configurable?.thread_id;
44670
+ const task = await getTaskStore().getById(tenantId2, taskId);
44671
+ if (task?.status === "in_progress" && task.context?.thread_id === threadId) {
44672
+ await createBoundTaskBridge().settleRun({
44673
+ tenantId: tenantId2,
44674
+ task,
44675
+ actor: getRuntimeActor2(rc) ?? "system",
44676
+ ...threadId ? { threadId } : {},
44677
+ outcome: { kind: "interrupted", summary: "Run ended without a task lifecycle transition" }
44678
+ });
44679
+ }
44680
+ taskRunRegistry.unregister(taskId);
44681
+ return {};
44682
+ },
44069
44683
  wrapModelCall: async (request, handler) => {
44070
44684
  const taskPrompt = `## Task Management
44071
44685
 
@@ -44074,8 +44688,11 @@ ongoing record of a GOAL and its ACCEPTANCE CRITERIA.
44074
44688
 
44075
44689
  ### When to create a task
44076
44690
  - Agent-owned work is multi-step and needs a persistent contract and plan ->
44077
- create the parent task FIRST (a \`pending\` record), then either execute it
44078
- inline and keep the status truthful, or dispatch it with \`task\`.
44691
+ create the parent task FIRST (a \`pending\` record), then process it in this run;
44692
+ mark it \`in_progress\` with \`manage_task set_status\` when you start, and
44693
+ \`completed\` when the acceptance criteria are met. To bring in an
44694
+ expert, create a subtask and dispatch it with \`task { taskId, agentId }\` \u2014 never
44695
+ re-dispatch the task you are processing.
44079
44696
  - Persistence is useful for resumption, review, or visibility across the
44080
44697
  independently verifiable business results.
44081
44698
 
@@ -44105,9 +44722,13 @@ ${TASK_CONVERGENCE_GUIDANCE}
44105
44722
  - No params: ownerType defaults to "user" with current user's ID
44106
44723
  - ownerType="agent": auto-fills ownerId from current agent (subtask for yourself)
44107
44724
  - Explicit ownerId: assign to a specific agent or user`;
44725
+ const boundTaskId = request.state?.taskId;
44726
+ const binding = typeof boundTaskId === "string" && boundTaskId ? renderTaskBinding(boundTaskId) : "";
44727
+ const rc = readRuntimeRunConfig(request.runtime);
44728
+ const executors = await renderAvailableExecutors(rc, rc.tenantId || "default");
44108
44729
  return handler({
44109
44730
  ...request,
44110
- systemPrompt: taskPrompt + "\n\n" + (request.systemPrompt ?? "")
44731
+ systemPrompt: taskPrompt + binding + executors + "\n\n" + (request.systemPrompt ?? "")
44111
44732
  });
44112
44733
  },
44113
44734
  tools: [
@@ -44132,15 +44753,14 @@ ${TASK_CONVERGENCE_GUIDANCE}
44132
44753
  - update: Update a task's content fields (title/description/priority/dueDate/metadata/parentId/sourceId/context/ownerId/result/failureReason/requireReview/dependencies/files)
44133
44754
  Status changes can also be done here, but use set_status for a simpler dedicated status update.
44134
44755
  - set_status: Change a task's status (id and status required). Use this when you only need to change the status.
44135
- Valid status values: pending, in_progress, review, failed, interrupted, completed, cancelled
44136
- Companion fields: result (for completed), failureReason (for failed), summary (for any status)
44137
- To mark complete: set_status with status='completed', result='...'
44756
+ Start processing a task you hold: set_status with status='in_progress' (the engine binds it to this run's thread).
44757
+ To mark complete: set_status with status='completed', result='...' (the task must be in_progress)
44138
44758
  To mark failed: set_status with status='failed', failureReason='...'
44139
44759
  To pause for input: set_status with status='interrupted', summary='what is needed'
44140
- Status can be freely changed to any valid value \u2014 no restrictions on transitions.
44760
+ Valid status values: pending, in_progress, review, failed, interrupted, completed, cancelled.
44141
44761
  set_status only changes the record; it never dispatches execution (only the \`task\` tool does).
44142
44762
  - add_activity: Add a Markdown activity without changing task fields or status (id and content required)
44143
- - delete: Delete a task (id required)
44763
+ - 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.
44144
44764
 
44145
44765
  ## Agent completion beliefs
44146
44766
  Completing an agent-owned task MAY include a beliefImpact array reporting which
@@ -44151,14 +44771,16 @@ Report existing keys directly; set 'isNew: true' to add a key the owner does not
44151
44771
  track yet. Belief is evidence metadata: it never blocks a completion, and an
44152
44772
  unmatched or malformed entry is recorded without changing the owner's table.
44153
44773
  Create always persists a pending record \u2014 a supplied status is coerced and no
44154
- execution is dispatched. Only dispatching runs a task through the queue; an
44155
- agent may also work inline and update status.`,
44774
+ execution is dispatched. When you start processing a task you hold, set it
44775
+ \`in_progress\` with \`manage_task set_status\`; a dispatched task is claimed
44776
+ automatically by the engine. Use \`task { taskId, agentId }\` to delegate a subtask
44777
+ to an expert \u2014 never re-dispatch the task you are processing.`,
44156
44778
  schema: manageTaskSchema
44157
44779
  }
44158
44780
  ),
44159
44781
  tool67(handleStartTask, {
44160
44782
  name: "task",
44161
- 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.",
44783
+ 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.`,
44162
44784
  schema: startTaskSchema
44163
44785
  })
44164
44786
  ]
@@ -44300,7 +44922,7 @@ canonical Belief State:
44300
44922
  };
44301
44923
 
44302
44924
  // src/middlewares/documentLearningMiddleware.ts
44303
- import { AgentType as AgentType9 } from "@axiom-lattice/protocols";
44925
+ import { AgentType as AgentType10 } from "@axiom-lattice/protocols";
44304
44926
  import { createMiddleware as createMiddleware25 } from "langchain";
44305
44927
 
44306
44928
  // src/middlewares/documentLearningSkills.ts
@@ -44567,7 +45189,7 @@ var documentLearningPlugin = {
44567
45189
  key: "document-learner",
44568
45190
  name: "Document Learning Agent",
44569
45191
  description: "Read documents and build structured skill systems with evaluations. Use this agent when you need to extract knowledge from documents and turn it into reusable, testable agent skills.",
44570
- type: AgentType9.DEEP_AGENT,
45192
+ type: AgentType10.DEEP_AGENT,
44571
45193
  prompt: DOCUMENT_LEARNER_SYSTEM_PROMPT,
44572
45194
  subAgents: ["document-parser-benchmark"],
44573
45195
  tools: [
@@ -44876,7 +45498,7 @@ function createParseDocumentTool({
44876
45498
  }
44877
45499
 
44878
45500
  // src/middlewares/documentParserMiddleware.ts
44879
- import { AgentType as AgentType10 } from "@axiom-lattice/protocols";
45501
+ import { AgentType as AgentType11 } from "@axiom-lattice/protocols";
44880
45502
 
44881
45503
  // src/middlewares/documentBenchmarkWorkflow.ts
44882
45504
  var DOCUMENT_PARSER_BENCHMARK_YAML = `name: document-parser-benchmark
@@ -45401,7 +46023,7 @@ var documentParserPlugin = {
45401
46023
  agents: {
45402
46024
  "document-parser-benchmark": {
45403
46025
  key: "document-parser-benchmark",
45404
- type: AgentType10.WORKFLOW,
46026
+ type: AgentType11.WORKFLOW,
45405
46027
  name: "Document Parser Benchmark",
45406
46028
  description: "Benchmark document parsing engines. Parses a document with 5 engines in parallel, scores results, and produces a ranking report. Use this when you need to evaluate which parsing engine works best for a given document.",
45407
46029
  prompt: "Benchmark document parsing engines: parse with 5 engines, score, and rank results.",
@@ -45613,7 +46235,7 @@ var projectRoomPlugin = {
45613
46235
  // src/middlewares/sandboxPluginsMiddleware.ts
45614
46236
  import { createMiddleware as createMiddleware28, tool as tool70 } from "langchain";
45615
46237
  import { z as z76 } from "zod";
45616
- import { AgentType as AgentType11 } from "@axiom-lattice/protocols";
46238
+ import { AgentType as AgentType12 } from "@axiom-lattice/protocols";
45617
46239
 
45618
46240
  // src/middlewares/sandboxPluginsSkills.ts
45619
46241
  var PLUGIN_JSON_TEMPLATE = `{
@@ -46363,7 +46985,7 @@ var sandboxPluginsPlugin = {
46363
46985
  key: "plugin-builder",
46364
46986
  name: "Plugin Builder",
46365
46987
  description: "Author and manage tenant plugins in the shared sandbox: clarify goal, inputs/outputs, credentials, and whether a UI is needed; then write the manifest and JS handlers, add an optional HTML MCP App UI, and validate/test with the manage_plugin tool.",
46366
- type: AgentType11.DEEP_AGENT,
46988
+ type: AgentType12.DEEP_AGENT,
46367
46989
  prompt: PLUGIN_BUILDER_PROMPT,
46368
46990
  middleware: [
46369
46991
  {
@@ -47129,6 +47751,7 @@ export {
47129
47751
  TaskLifecycleNotifier,
47130
47752
  TaskLifecycleService,
47131
47753
  TaskRunBridgeStoresRequiredError,
47754
+ TaskRunRegistry,
47132
47755
  TaskStatus,
47133
47756
  TeamAgentGraphBuilder,
47134
47757
  TenantPluginCatalog,
@@ -47140,7 +47763,6 @@ export {
47140
47763
  VectorStoreProviderManager,
47141
47764
  VolumeFilesystem,
47142
47765
  abortWorkflowRun,
47143
- agentHasManagedTaskCapability,
47144
47766
  agentInstanceManager,
47145
47767
  agentLatticeManager,
47146
47768
  appendReconciliationWarning,
@@ -47315,6 +47937,9 @@ export {
47315
47937
  projectTaskAdmissionNotifier,
47316
47938
  queueLatticeManager,
47317
47939
  readLoopBreakerConfig,
47940
+ reconcileAllTenantTaskRuns,
47941
+ reconcileStaleTaskRuns,
47942
+ reconcileTenantTaskRuns,
47318
47943
  registerAgentLattice,
47319
47944
  registerAgentLatticeWithTenant,
47320
47945
  registerAgentLattices,
@@ -47363,6 +47988,7 @@ export {
47363
47988
  storeLatticeManager,
47364
47989
  sttModelLatticeManager,
47365
47990
  taskLifecycleNotifier,
47991
+ taskRunRegistry,
47366
47992
  toJsonSchema,
47367
47993
  toSafeStateExpr,
47368
47994
  toolLatticeManager,