@axiom-lattice/core 4.2.5 → 4.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3915,6 +3915,7 @@ function cloneWebApp(webApp) {
3915
3915
  },
3916
3916
  features: { ...webApp.features },
3917
3917
  appearance: { ...webApp.appearance },
3918
+ identity: webApp.identity ? { policy: webApp.identity.policy, issuers: webApp.identity.issuers.map((issuer) => ({ ...issuer })) } : void 0,
3918
3919
  createdAt: new Date(webApp.createdAt),
3919
3920
  updatedAt: new Date(webApp.updatedAt)
3920
3921
  };
@@ -3960,6 +3961,7 @@ var InMemoryAgentWebAppStore = class {
3960
3961
  },
3961
3962
  features: { ...input.features },
3962
3963
  appearance: { ...input.appearance },
3964
+ identity: input.identity ? { policy: input.identity.policy, issuers: input.identity.issuers.map((issuer) => ({ ...issuer })) } : void 0,
3963
3965
  createdAt: now,
3964
3966
  updatedAt: now
3965
3967
  };
@@ -3976,7 +3978,7 @@ var InMemoryAgentWebAppStore = class {
3976
3978
  const existing = tenantWebApps?.get(webAppId);
3977
3979
  if (!tenantWebApps || !existing) return null;
3978
3980
  if (options?.expectedUpdatedAt && existing.updatedAt.getTime() !== options.expectedUpdatedAt.getTime()) return null;
3979
- const hasUpdate = patch.name !== void 0 || Object.prototype.hasOwnProperty.call(patch, "description") || patch.scope !== void 0 || patch.features !== void 0 || patch.appearance !== void 0 || patch.status !== void 0;
3981
+ const hasUpdate = patch.name !== void 0 || Object.prototype.hasOwnProperty.call(patch, "description") || patch.scope !== void 0 || patch.features !== void 0 || patch.appearance !== void 0 || patch.identity !== void 0 || patch.status !== void 0;
3980
3982
  if (!hasUpdate) return cloneWebApp(existing);
3981
3983
  const updated = {
3982
3984
  ...existing,
@@ -3991,6 +3993,7 @@ var InMemoryAgentWebAppStore = class {
3991
3993
  } : {},
3992
3994
  ...patch.features ? { features: { ...patch.features } } : {},
3993
3995
  ...patch.appearance ? { appearance: { ...patch.appearance } } : {},
3996
+ ...patch.identity !== void 0 ? { identity: { policy: patch.identity.policy, issuers: patch.identity.issuers.map((issuer) => ({ ...issuer })) } } : {},
3994
3997
  ...patch.status !== void 0 ? { status: patch.status } : {},
3995
3998
  updatedAt: new Date(Math.max(Date.now(), existing.updatedAt.getTime() + 1))
3996
3999
  };
@@ -9174,7 +9177,8 @@ var VolumeFilesystem = class {
9174
9177
  path: entry.path.startsWith("/") ? entry.path : prefix + entry.path,
9175
9178
  is_dir: entry.kind === "directory",
9176
9179
  size: entry.size,
9177
- modified_at: entry.modified ? new Date(entry.modified).toISOString() : void 0
9180
+ modified_at: entry.modified ? new Date(entry.modified).toISOString() : void 0,
9181
+ created_at: entry.created ? new Date(entry.created).toISOString() : void 0
9178
9182
  }));
9179
9183
  }
9180
9184
  async read(filePath, offset = 0, limit = 2e3) {
@@ -24474,8 +24478,12 @@ Otherwise, the owning caller interprets the returned observation.
24474
24478
  An execution result is an observation, not automatic proof of business
24475
24479
  completion. \`task\` returns its exact \`executionResultId\`. After \`task\`
24476
24480
  returns, inspect the observation, then pass that \`executionResultId\` to the
24477
- meaningful \`manage_task update\` or \`manage_task add_activity\` that interprets
24478
- it and reconciles status, belief, plan, and next action. Omitting
24481
+ meaningful \`manage_task set_status\` (status transition), \`manage_task
24482
+ update\` (content fields), or \`manage_task add_activity\` that interprets
24483
+ it and reconciles status, belief, plan, and next action. Action split:
24484
+ \`set_status\` owns status transitions (with result/failureReason/summary and
24485
+ beliefImpact on completion); \`update\` owns content fields (title,
24486
+ description, priority, dependencies, ...); the two never mix in one call. Omitting
24479
24487
  \`executionResultId\` leaves the result pending so forgotten handling remains
24480
24488
  detectable. Reconciliation does not require the task to become \`completed\`;
24481
24489
  choose the truthful status. \`manage_task get\` exposes pending execution-result
@@ -24495,13 +24503,14 @@ independently.
24495
24503
  6. **Reconcile** - revise Belief, Task, plan, and next action on Prediction Error,
24496
24504
  then repeat only while a decision-relevant action remains and stop at honest convergence.
24497
24505
 
24498
- Converge using existing statuses:
24506
+ Converge through \`set_status\` using existing statuses:
24499
24507
 
24500
- - \`completed\`: acceptance is satisfied by evidence; include a \`result\`.
24508
+ - \`completed\`: acceptance is satisfied by evidence; \`set_status\` with a
24509
+ \`result\` and structured \`beliefImpact\`.
24501
24510
  - \`in_progress\`: a feasible, decision-relevant action remains.
24502
24511
  - \`pending\`: work is future or dependency-blocked.
24503
24512
  - \`interrupted\`: an external condition is missing; record the condition needed to resume.
24504
- - \`failed\`: no reasonable path remains; include a \`failureReason\`.
24513
+ - \`failed\`: no reasonable path remains; \`set_status\` with a \`failureReason\`.
24505
24514
  - \`cancelled\`: the goal or subgoal is no longer needed.
24506
24515
 
24507
24516
  For human judgment, use the actual HITL payload \`status: "interrupted"\` plus
@@ -25791,6 +25800,35 @@ Renew HITL approval when a foundational assumption or authority boundary changes
25791
25800
 
25792
25801
  **Full reference**: [[eval-verify]] implements the same loop for the eval fix loop, with the full six-heading format (## Observed Failure / ## Implicated Design Assumption / ## Candidate Change / ## Expected Improvement / ## Possible Regression / ## Cases That Can Falsify the Change). [[task-tracking]] implements the same loop for persistent task operations.
25793
25802
 
25803
+ ## Skill Loading Policy
25804
+
25805
+ Visible in <available_skills> does not mean loaded. Follow these three tiers.
25806
+
25807
+ ### Tier 1 \u2014 Session start (mandatory, unconditional)
25808
+ Load before any other work; the bootstrap prompt enforces this:
25809
+ - [[agent-architecture]] (this skill) \u2014 shared policy and routing.
25810
+ - [[task-tracking]] \u2014 before your first \`manage_task\` call; Task management is
25811
+ the planning surface and is gated again under Architect Task Policy.
25812
+
25813
+ ### Tier 2 \u2014 Scenario gates (mandatory before entering the scenario)
25814
+ Load the owning skill with the \`skill\` tool BEFORE the first action of that
25815
+ scenario. Never execute a scenario without its owning skill loaded:
25816
+ - Creating or modifying a Capability (\`react\`) or Orchestra (\`deep_agent\`)
25817
+ Agent \u2192 [[agent-build]]
25818
+ - Creating or modifying a Workflow (stable enumerable pipelines) \u2192 [[design-workflow]]
25819
+ - Learning a capability from source material \u2192 [[document-learning-learn-capability]]
25820
+ - Designing evals, running evals, or fixing eval failures \u2192 [[eval-verify]]
25821
+ - Claiming work is complete or delivered \u2192 [[completion-gate]]
25822
+ - Final configuration pre-check before delivery \u2192 [[review-agent]]
25823
+
25824
+ If a Tier 2 load fails, retry once, then stop and tell the user which
25825
+ capability is unavailable. Do not improvise the scenario from partial knowledge.
25826
+
25827
+ ### Tier 3 \u2014 Reference (load on demand, never preload)
25828
+ Deep details reachable through [[links]] inside loaded skills, and plugin
25829
+ skills outside this chain (for example task-definition for non-architect
25830
+ agents). Load one only when the current step actually needs it.
25831
+
25794
25832
  ## Agent Forms and Routing
25795
25833
  - **Capability** (\`react\`) for bounded direct work: [[agent-build]]
25796
25834
  - **Orchestra** (\`deep_agent\`) for open-ended delegated work: [[agent-build]]
@@ -25803,8 +25841,11 @@ Renew HITL approval when a foundational assumption or authority boundary changes
25803
25841
  ## Architect Task Policy
25804
25842
  The Agent Architect uses persistent TaskItems as its planning surface. Architect must not use
25805
25843
  \`write_todos\`. Create a persistent child only for an independently verifiable
25806
- outcome; tool calls and file reads are actions inside the active Task. Load
25807
- [[task-tracking]] for operation and status details.
25844
+ outcome; tool calls and file reads are actions inside the active Task.
25845
+ **MANDATORY: before your first \`manage_task\` call in this session, load
25846
+ [[task-tracking]] with the \`skill\` tool.** Do not create, update, or transition
25847
+ any Task until it is loaded. If the load fails, retry once, then tell the user
25848
+ task management is unavailable.
25808
25849
  Learning authority is **normal** or **bounded**: normal for fresh work without a
25809
25850
  bound round; bounded for learning rounds that bind an existing target and
25810
25851
  tracking Task with a confirmed goal. Identity remains fixed; materialization uses
@@ -26033,6 +26074,9 @@ ${TASK_BELIEF_REFERENCE_EXAMPLE}
26033
26074
 
26034
26075
  ## Status discipline \u2014 MANDATORY
26035
26076
 
26077
+ - All status transitions go through \`manage_task set_status\` (with
26078
+ \`result\` on completed, \`failureReason\` on failed). \`update\` is for
26079
+ content fields only and rejects a status field.
26036
26080
  - A subtask is \`completed\` ONLY when its work is actually finished.
26037
26081
  While fixing eval failures, keep it \`in_progress\` \u2014 never mark
26038
26082
  \`completed\` as a workaround (the state machine rejects illegal
@@ -28301,8 +28345,11 @@ var AGENT_ARCHITECT_PROMPT = `You are the Agent Architect.
28301
28345
 
28302
28346
  CRITICAL FIRST ACTION: Before any response or other action, call the \`skill\`
28303
28347
  tool with skill_name: "agent-architecture" to load agent-architecture and follow it.
28304
- Never announce the skill load. If it fails, retry once, then stop and explicitly
28305
- report that the required Agent Architect skill could not be loaded.`;
28348
+ Immediately after it loads, call the \`skill\` tool again with skill_name:
28349
+ "task-tracking" \u2014 persistent Task management is your core planning surface and
28350
+ you must have its operation reference before creating or updating any Task.
28351
+ Never announce skill loads. If a load fails, retry once, then stop and
28352
+ explicitly report that the required skill could not be loaded.`;
28306
28353
 
28307
28354
  // src/agent_lattice/agentReviewerConfig.ts
28308
28355
  var import_protocols18 = require("@axiom-lattice/protocols");
@@ -31299,7 +31346,8 @@ var RemoteSandboxProvider = class {
31299
31346
  kind: f.is_dir === true || f.size === null ? "directory" : "file",
31300
31347
  size: f.size ?? 0,
31301
31348
  mode: 0,
31302
- modified: f.modified_at ?? null
31349
+ modified: f.modified_at ?? null,
31350
+ created: f.created_at ?? null
31303
31351
  }));
31304
31352
  return entries;
31305
31353
  },
@@ -33046,8 +33094,12 @@ Note: if final_score >= 80 and there are no fatal errors, pass should be true; o
33046
33094
  });
33047
33095
  }
33048
33096
  } else if (parsedResult.pass !== void 0) {
33049
- pass = parsedResult.pass;
33050
- this.log("Pass determined from parsedResult.pass", { case_id: evalCase.caseId, pass });
33097
+ pass = false;
33098
+ parsedResult.final_score = 0;
33099
+ this.log("Pass without final_score \u2014 cannot verify threshold, defaulting to FAIL", {
33100
+ case_id: evalCase.caseId,
33101
+ pass_field: parsedResult.pass
33102
+ });
33051
33103
  } else if (parsedResult.final_score !== void 0) {
33052
33104
  pass = parsedResult.final_score >= 80;
33053
33105
  this.log("Pass determined from parsedResult.final_score", {
@@ -34795,7 +34847,11 @@ var TaskLifecycleService = class {
34795
34847
  ...event2.warning ? { warnings: [event2.warning] } : {}
34796
34848
  };
34797
34849
  }
34798
- if (task.status !== "interrupted") return failure2("TASK_STATUS_CONFLICT", "Task is not interrupted.");
34850
+ if (task.status !== "interrupted") return failure2(
34851
+ "TASK_STATUS_CONFLICT",
34852
+ `Task is in '${task.status}' status, not interrupted.`,
34853
+ "Only interrupted tasks can resume to in_progress."
34854
+ );
34799
34855
  if (interruption && typeof interruption === "object" && interruption.type === "review_required") {
34800
34856
  return failure2("REVIEW_APPROVAL_REQUIRED", "Review interruption requires explicit approval or rejection.");
34801
34857
  }
@@ -34892,7 +34948,11 @@ var TaskLifecycleService = class {
34892
34948
  task.updatedAt
34893
34949
  );
34894
34950
  } catch {
34895
- return { ...failure2("TASK_STORE_WRITE_FAILED", "Failed to update task lifecycle state."), transitioned: false };
34951
+ return { ...failure2(
34952
+ "TASK_STORE_WRITE_FAILED",
34953
+ "Failed to update task lifecycle state.",
34954
+ "The store rejected the write; this may be transient. Retry the same set_status."
34955
+ ), transitioned: false };
34896
34956
  }
34897
34957
  if (!updated) {
34898
34958
  let current;
@@ -34920,7 +34980,11 @@ var TaskLifecycleService = class {
34920
34980
  ...repaired.warning ? { warnings: [repaired.warning] } : {}
34921
34981
  };
34922
34982
  }
34923
- return { ...failure2("TASK_STATUS_CONFLICT", "Task changed concurrently."), transitioned: false };
34983
+ return { ...failure2(
34984
+ "TASK_STATUS_CONFLICT",
34985
+ "Task changed concurrently.",
34986
+ "Another writer modified the task between read and write. Use manage_task get to re-read its current state, then retry."
34987
+ ), transitioned: false };
34924
34988
  }
34925
34989
  const event = await this.writeStatusEvent(
34926
34990
  updated,
@@ -35064,10 +35128,18 @@ var TaskLifecycleService = class {
35064
35128
  const storedExternal = parseExternalDependency(currentInterruption);
35065
35129
  if (input.type === "external_dependency") {
35066
35130
  if (!external || !storedExternal || storedExternal.summary !== external.summary || canonicalJson(storedExternal.dependencyTaskIds) !== canonicalJson(external.dependencyTaskIds)) {
35067
- return failure2("TASK_STATUS_CONFLICT", "Task is interrupted by a different or malformed external dependency.");
35131
+ return failure2(
35132
+ "TASK_STATUS_CONFLICT",
35133
+ "Task is already interrupted by a different or malformed external dependency.",
35134
+ "Use manage_task get to inspect the existing interruption in task context.interruption."
35135
+ );
35068
35136
  }
35069
35137
  } else if (currentInterruption.type !== input.type || currentInterruption.summary !== summary) {
35070
- return failure2("TASK_STATUS_CONFLICT", "Task is interrupted by a different request.");
35138
+ return failure2(
35139
+ "TASK_STATUS_CONFLICT",
35140
+ "Task is already interrupted by a different request.",
35141
+ "Use manage_task get to inspect the existing interruption, or resume it first."
35142
+ );
35071
35143
  }
35072
35144
  const detail = storedExternal ? { ...storedExternal } : currentInterruption;
35073
35145
  const eventKey2 = this.statusEventKey(task, "interrupted", detail);
@@ -35084,7 +35156,11 @@ var TaskLifecycleService = class {
35084
35156
  ...warnings2.length ? { warnings: warnings2 } : {}
35085
35157
  };
35086
35158
  }
35087
- if (task.status !== "in_progress") return failure2("TASK_STATUS_CONFLICT", "Task is not in progress.");
35159
+ if (task.status !== "in_progress") return failure2(
35160
+ "TASK_STATUS_CONFLICT",
35161
+ `Task is in '${task.status}' status, not in progress.`,
35162
+ "Only in_progress tasks can be interrupted. Use manage_task get to check the current status."
35163
+ );
35088
35164
  if (external && isProjectLifecycleTask(task)) {
35089
35165
  const dependencyFailure = await this.validateExternalDependencies(task, external.dependencyTaskIds);
35090
35166
  if (dependencyFailure) return dependencyFailure;
@@ -35097,9 +35173,17 @@ var TaskLifecycleService = class {
35097
35173
  context: mergeInterruptionContext(task.context, interruption, input.threadId)
35098
35174
  }, ["in_progress"], task.updatedAt);
35099
35175
  } catch {
35100
- return failure2("TASK_STORE_WRITE_FAILED", "Failed to interrupt the task.");
35176
+ return failure2(
35177
+ "TASK_STORE_WRITE_FAILED",
35178
+ "Failed to interrupt the task.",
35179
+ "The store rejected the write; this may be transient. Retry the same set_status."
35180
+ );
35101
35181
  }
35102
- if (!updated) return failure2("TASK_STATUS_CONFLICT", "Task changed concurrently.");
35182
+ if (!updated) return failure2(
35183
+ "TASK_STATUS_CONFLICT",
35184
+ "Task changed concurrently.",
35185
+ "Another writer modified the task between read and write. Use manage_task get to re-read its current state, then retry."
35186
+ );
35103
35187
  const eventKey = this.statusEventKey(updated, "interrupted", interruption);
35104
35188
  const event = await this.writeStatusEvent(updated, input.actor, input.threadId, "interrupted", summary, interruption, eventKey);
35105
35189
  const warnings = event.warning ? [event.warning] : await this.notifyWinningTransition(updated, "interrupted", event);
@@ -35137,7 +35221,11 @@ var TaskLifecycleService = class {
35137
35221
  context: withCompletionAudit(prepared.task.context, prepared.evidence.id, prepared.eventKey)
35138
35222
  }, ["in_progress"]);
35139
35223
  } catch {
35140
- return failure2("TASK_STORE_WRITE_FAILED", "Failed to complete the task.");
35224
+ return failure2(
35225
+ "TASK_STORE_WRITE_FAILED",
35226
+ "Failed to complete the task.",
35227
+ "The store rejected the write; this may be transient. Retry the completion."
35228
+ );
35141
35229
  }
35142
35230
  if (!updated) {
35143
35231
  if (await this.hasStaleAgentParent(prepared)) {
@@ -35700,7 +35788,11 @@ var TaskLifecycleService = class {
35700
35788
  } catch {
35701
35789
  return failure2("TASK_STORE_WRITE_FAILED", "Failed to reconcile task description.");
35702
35790
  }
35703
- if (!updated) return failure2("TASK_STATUS_CONFLICT", "Task changed concurrently.");
35791
+ if (!updated) return failure2(
35792
+ "TASK_STATUS_CONFLICT",
35793
+ "Task changed concurrently.",
35794
+ "Another writer modified the task between read and write. Use manage_task get to re-read it, then retry the description update."
35795
+ );
35704
35796
  if (changedKeys.length === 0) {
35705
35797
  return {
35706
35798
  success: true,
@@ -40994,6 +41086,16 @@ function getRunConfig2(config) {
40994
41086
  const c = config;
40995
41087
  return c?.configurable?.runConfig ?? {};
40996
41088
  }
41089
+ function taskUpdateDebug(message, data) {
41090
+ try {
41091
+ console.log(JSON.stringify({ __taskUpdateDebug: true, message, ...data }));
41092
+ } catch {
41093
+ console.log(`[taskUpdateDebug] ${message}`);
41094
+ }
41095
+ }
41096
+ function taskUpdateBlocked(taskId, code, detail) {
41097
+ taskUpdateDebug("update:blocked", { taskId, code, ...detail });
41098
+ }
40997
41099
  function getRuntimeActor2(runConfig) {
40998
41100
  if (runConfig.assistant_id) return `agent:${String(runConfig.assistant_id)}`;
40999
41101
  if (runConfig.user_id) return `user:${String(runConfig.user_id)}`;
@@ -41220,6 +41322,7 @@ async function validateEffectiveDependencies(store, tenantId2, targetScope, depe
41220
41322
  if (blockedBy.length === 0) return void 0;
41221
41323
  return JSON.stringify({
41222
41324
  success: false,
41325
+ code: "DEPENDENCY_BLOCKED",
41223
41326
  error: `Cannot start task: ${blockedBy.length} dependencies not completed`,
41224
41327
  blockedBy,
41225
41328
  invalidScope,
@@ -41370,13 +41473,27 @@ function missingBeliefImpactError() {
41370
41473
  hint: "Provide beliefImpact: [{ key: '<belief-key>', after: <0-100>, basis: '<evidence>' }]"
41371
41474
  });
41372
41475
  }
41476
+ function reviewInterruption(task) {
41477
+ const value = task.context?.interruption;
41478
+ if (!value || typeof value !== "object") return void 0;
41479
+ const interruption = value;
41480
+ return interruption.type === "review_required" ? interruption : void 0;
41481
+ }
41482
+ function buildReviewMarkdown(task) {
41483
+ return genUIMarkdown("task_review", {
41484
+ taskId: task.id,
41485
+ title: task.title,
41486
+ description: task.description,
41487
+ result: task.result
41488
+ });
41489
+ }
41373
41490
  var manageTaskSchema = import_zod68.z.object({
41374
- action: import_zod68.z.enum(["create", "get", "list", "update", "add_activity", "delete"]).describe("Action to perform. Available: create, get, list, update, add_activity, delete. To mark a task complete, use update with status='completed'"),
41491
+ action: import_zod68.z.enum(["create", "get", "list", "update", "set_status", "add_activity", "delete"]).describe("Action to perform. Available: create, get, list, update, set_status, add_activity, delete. To change status, use set_status. To change content fields, use update."),
41375
41492
  id: import_zod68.z.string().optional().describe("Task ID (required for get, update, add_activity, and delete)"),
41376
41493
  title: import_zod68.z.string().optional().describe("Task title (required for create)"),
41377
41494
  description: import_zod68.z.string().optional().describe("Task description in Markdown"),
41378
41495
  priority: import_zod68.z.enum(["low", "medium", "high"]).optional().describe("Priority level"),
41379
- status: import_zod68.z.enum(["pending", "in_progress", "review", "failed", "interrupted", "completed", "cancelled"]).optional().describe("Task status. Agent summary-only interrupted updates default to missing_input"),
41496
+ status: import_zod68.z.enum(["pending", "in_progress", "review", "failed", "interrupted", "completed", "cancelled"]).optional().describe("Task status. For status-only changes, prefer set_status action. Agent summary-only interrupted updates default to missing_input"),
41380
41497
  dueDate: import_zod68.z.string().optional().describe("Due date (ISO 8601 format)"),
41381
41498
  metadata: import_zod68.z.record(import_zod68.z.unknown()).optional().describe("Structured metadata (e.g. projectId, module)"),
41382
41499
  parentId: import_zod68.z.string().optional().describe("Parent task ID for grouping subtasks"),
@@ -41387,8 +41504,8 @@ var manageTaskSchema = import_zod68.z.object({
41387
41504
  requireReview: import_zod68.z.boolean().optional().describe("If true, agent completion pauses as interrupted(review_required) for HITL approval"),
41388
41505
  dependencies: import_zod68.z.array(import_zod68.z.string()).optional().describe("List of task IDs that must be completed before this task can start"),
41389
41506
  dependencyTaskIds: import_zod68.z.array(import_zod68.z.string().trim().min(1)).optional().describe("Exact blocking task IDs required for an external_dependency interruption"),
41390
- result: import_zod68.z.string().optional().describe("Nonblank result summary required when creating or updating a task with status='completed'"),
41391
- failureReason: import_zod68.z.string().optional().describe("Nonblank failure reason required when creating or updating a task with status='failed'"),
41507
+ result: import_zod68.z.string().optional().describe("Result summary. Used with set_status status='completed' or update status='completed'"),
41508
+ failureReason: import_zod68.z.string().optional().describe("Failure reason. Used with set_status status='failed' or update status='failed'"),
41392
41509
  files: import_zod68.z.array(import_zod68.z.object({
41393
41510
  uri: import_zod68.z.string().describe("Uniquely locates the resource: http(s):// URL, /s/:token share, or sandbox path"),
41394
41511
  name: import_zod68.z.string().optional().describe("Display name"),
@@ -41407,11 +41524,11 @@ var manageTaskSchema = import_zod68.z.object({
41407
41524
  "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"
41408
41525
  )
41409
41526
  }).superRefine((input, context) => {
41410
- if (input.executionResultId && input.action !== "update" && input.action !== "add_activity") {
41527
+ if (input.executionResultId && input.action !== "update" && input.action !== "set_status" && input.action !== "add_activity") {
41411
41528
  context.addIssue({
41412
41529
  code: import_zod68.z.ZodIssueCode.custom,
41413
41530
  path: ["executionResultId"],
41414
- message: "executionResultId is valid only for update or add_activity"
41531
+ message: "executionResultId is valid only for update, set_status, or add_activity"
41415
41532
  });
41416
41533
  }
41417
41534
  });
@@ -41525,12 +41642,6 @@ function updateValuesEqual(field, requested, persisted) {
41525
41642
  }
41526
41643
  return valuesEqual(requested, persisted);
41527
41644
  }
41528
- function reviewInterruption(task) {
41529
- const value = task.context?.interruption;
41530
- if (!value || typeof value !== "object") return void 0;
41531
- const interruption = value;
41532
- return interruption.type === "review_required" ? interruption : void 0;
41533
- }
41534
41645
  function reviewModeDisabledResponse() {
41535
41646
  return JSON.stringify({
41536
41647
  success: false,
@@ -41539,14 +41650,6 @@ function reviewModeDisabledResponse() {
41539
41650
  hint: "Configure task middleware with reviewMode 'hitl' before enabling requireReview."
41540
41651
  });
41541
41652
  }
41542
- function buildReviewMarkdown(task) {
41543
- return genUIMarkdown("task_review", {
41544
- taskId: task.id,
41545
- title: task.title,
41546
- description: task.description,
41547
- result: task.result
41548
- });
41549
- }
41550
41653
  function createTaskMiddleware(options = {}) {
41551
41654
  const handleManageTaskAction = async (input, config, validateExecutionResult, markMutation) => {
41552
41655
  const rc = getRunConfig2(config);
@@ -41934,35 +42037,75 @@ function createTaskMiddleware(options = {}) {
41934
42037
  return JSON.stringify({ success: true, data: activity });
41935
42038
  }
41936
42039
  case "update": {
42040
+ taskUpdateDebug("update:enter", {
42041
+ id: input.id,
42042
+ action: input.action,
42043
+ status: input.status,
42044
+ hasResult: input.result !== void 0,
42045
+ hasDescription: input.description !== void 0,
42046
+ tenantId: tenantId2,
42047
+ workspaceId,
42048
+ projectId,
42049
+ authorityKind: delegatedTaskId ? "delegated" : trustedProject ? "trusted" : "ordinary",
42050
+ trustedKind: trustedProject ? trustedProject.projectTask ? "projectTask" : "projectRoom" : void 0
42051
+ });
41937
42052
  if (!input.id) {
42053
+ taskUpdateBlocked(input.id, "MISSING_TASK_ID", {});
41938
42054
  return JSON.stringify({
41939
42055
  success: false,
42056
+ code: "MISSING_TASK_ID",
41940
42057
  error: "id is required for update action",
41941
42058
  hint: "Pass the task ID you want to update"
41942
42059
  });
41943
42060
  }
41944
42061
  if (delegatedTaskId && input.id !== delegatedTaskId) {
42062
+ taskUpdateBlocked(input.id, "DELEGATED_TASK_SCOPE_VIOLATION", { delegatedTaskId });
41945
42063
  return delegatedTaskScopeError(delegatedTaskId);
41946
42064
  }
41947
- let existing = await store.getById(tenantId2, input.id);
42065
+ const existing = await store.getById(tenantId2, input.id);
42066
+ taskUpdateDebug("update:loaded", existing ? {
42067
+ status: existing.status,
42068
+ updatedAt: existing.updatedAt?.toISOString(),
42069
+ ownerType: existing.ownerType,
42070
+ ownerId: existing.ownerId,
42071
+ workspaceId: existing.workspaceId,
42072
+ projectId: existing.projectId
42073
+ } : { found: false });
41948
42074
  if (!existing) {
42075
+ taskUpdateBlocked(input.id, "TASK_NOT_FOUND", {});
41949
42076
  return JSON.stringify({
41950
42077
  success: false,
41951
- error: `Task '${input.id}' not found`,
41952
- hint: "Use list to see available tasks and their IDs"
42078
+ code: "TASK_NOT_FOUND",
42079
+ error: `Task '${input.id}' was not found.`,
42080
+ hint: "Use manage_task list to see available tasks and their correct IDs."
41953
42081
  });
41954
42082
  }
41955
42083
  if (!taskMatchesRuntimeScope3(existing, workspaceId, projectId)) {
42084
+ taskUpdateBlocked(input.id, "TASK_NOT_FOUND_OR_INACCESSIBLE", {
42085
+ taskWorkspaceId: existing.workspaceId,
42086
+ taskProjectId: existing.projectId,
42087
+ runtimeWorkspaceId: workspaceId,
42088
+ runtimeProjectId: projectId
42089
+ });
41956
42090
  return taskScopeAccessError(input.id);
41957
42091
  }
41958
42092
  if (trustedProject?.projectTask) {
41959
42093
  const trustedFailure = trustedTaskContextFailure(existing, trustedProject.projectTask);
41960
- if (trustedFailure) return trustedFailure;
42094
+ if (trustedFailure) {
42095
+ taskUpdateBlocked(input.id, "PROJECT_TASK_CONTEXT_INVALID", {
42096
+ taskOwnerId: existing.ownerId,
42097
+ trustedAssistantId: trustedProject.projectTask.assistantId,
42098
+ taskThreadId: existing.context?.thread_id,
42099
+ trustedThreadId: trustedProject.projectTask.threadId
42100
+ });
42101
+ return trustedFailure;
42102
+ }
41961
42103
  }
41962
42104
  if (trustedProject && input.dependencyTaskIds !== void 0) {
41963
42105
  const interruption = input.context?.interruption;
41964
42106
  const interruptionType2 = interruption && typeof interruption === "object" ? interruption.type : void 0;
41965
42107
  if (input.status !== "interrupted" || interruptionType2 !== "external_dependency") {
42108
+ taskUpdateBlocked(input.id, "INVALID_EXTERNAL_DEPENDENCY", {});
41966
42109
  return JSON.stringify({
41967
42110
  success: false,
41968
42111
  code: "INVALID_EXTERNAL_DEPENDENCY",
@@ -41971,24 +42114,26 @@ function createTaskMiddleware(options = {}) {
41971
42114
  }
41972
42115
  }
41973
42116
  if (trustedProject && (input.ownerType !== void 0 && input.ownerType !== existing.ownerType || input.ownerId !== void 0 && input.ownerId !== existing.ownerId)) {
42117
+ taskUpdateBlocked(input.id, "TASK_REASSIGN_ENDPOINT_REQUIRED", {
42118
+ inputOwnerType: input.ownerType,
42119
+ existingOwnerType: existing.ownerType,
42120
+ inputOwnerId: input.ownerId,
42121
+ existingOwnerId: existing.ownerId
42122
+ });
41974
42123
  return JSON.stringify({
41975
42124
  success: false,
41976
42125
  code: "TASK_REASSIGN_ENDPOINT_REQUIRED",
41977
42126
  error: "Project task ownership changes require the reassignment endpoint."
41978
42127
  });
41979
42128
  }
41980
- if (existing.status === "review" || input.status === "review") {
41981
- return JSON.stringify({
41982
- success: false,
41983
- code: "TASK_STATUS_UNSUPPORTED",
41984
- error: "Task status is not supported by the task lifecycle."
41985
- });
41986
- }
41987
42129
  const isAgentTask = existing.ownerType === "agent";
41988
- const candidateReviewInterruption = input.status === "interrupted" && input.context?.interruption && typeof input.context.interruption === "object" && input.context.interruption.type === "review_required" && !!input.result?.trim() && !!input.beliefImpact?.length;
41989
42130
  const changesOwnerType = input.ownerType !== void 0 && input.ownerType !== existing.ownerType;
41990
42131
  const changesAgentIdentity = isAgentTask && (input.ownerId !== void 0 && input.ownerId !== existing.ownerId || input.parentId !== void 0 && input.parentId !== existing.parentId);
41991
42132
  if (changesOwnerType || changesAgentIdentity) {
42133
+ taskUpdateBlocked(input.id, "TASK_OWNERSHIP_IMMUTABLE", {
42134
+ changesOwnerType,
42135
+ changesAgentIdentity
42136
+ });
41992
42137
  return JSON.stringify({
41993
42138
  success: false,
41994
42139
  code: "TASK_OWNERSHIP_IMMUTABLE",
@@ -41996,18 +42141,10 @@ function createTaskMiddleware(options = {}) {
41996
42141
  hint: "Create a separate task for different ownership or parentage."
41997
42142
  });
41998
42143
  }
41999
- const hasMismatchedAgentOutput = isAgentTask && (input.result !== void 0 && input.status !== "completed" && !candidateReviewInterruption || input.failureReason !== void 0 && input.status !== "failed");
42000
- if (hasMismatchedAgentOutput) {
42001
- return JSON.stringify({
42002
- success: false,
42003
- code: "TASK_LIFECYCLE_TRANSITION_REQUIRED",
42004
- error: "Agent task result and failureReason require a matching governed lifecycle transition.",
42005
- hint: "Provide result only with completion, or failureReason only with failure."
42006
- });
42007
- }
42008
42144
  const changesOwnership = input.ownerId !== void 0 && input.ownerId !== existing.ownerId || input.parentId !== void 0 && input.parentId !== existing.parentId;
42009
42145
  const changesGovernedState = input.status !== void 0 || input.description !== void 0 || input.result !== void 0 || input.failureReason !== void 0 || input.requireReview !== void 0 || input.context !== void 0;
42010
42146
  if (changesOwnership && changesGovernedState) {
42147
+ taskUpdateBlocked(input.id, "TASK_OWNERSHIP_MUTATION_CONFLICT", {});
42011
42148
  return JSON.stringify({
42012
42149
  success: false,
42013
42150
  code: "TASK_OWNERSHIP_MUTATION_CONFLICT",
@@ -42015,17 +42152,389 @@ function createTaskMiddleware(options = {}) {
42015
42152
  hint: "Persist ownership or parent changes separately before changing lifecycle or task content."
42016
42153
  });
42017
42154
  }
42155
+ if (existing.status === "review") {
42156
+ taskUpdateBlocked(input.id, "TASK_STATUS_UNSUPPORTED", {});
42157
+ return JSON.stringify({
42158
+ success: false,
42159
+ code: "TASK_STATUS_UNSUPPORTED",
42160
+ error: "Task status is not supported by the task lifecycle."
42161
+ });
42162
+ }
42163
+ if (input.status !== void 0) {
42164
+ taskUpdateBlocked(input.id, "STATUS_USES_SET_STATUS", { status: input.status });
42165
+ return JSON.stringify({
42166
+ success: false,
42167
+ code: "STATUS_USES_SET_STATUS",
42168
+ error: `Status changes must use the set_status action. Received status='${input.status}'.`,
42169
+ hint: "Call manage_task with action='set_status', id, and status to change the task status. Use action='update' for content fields only."
42170
+ });
42171
+ }
42172
+ if (isAgentTask && input.requireReview === true && options.reviewMode !== "hitl") {
42173
+ return reviewModeDisabledResponse();
42174
+ }
42175
+ if (["completed", "failed", "cancelled"].includes(existing.status) && input.requireReview !== void 0 && input.requireReview !== existing.requireReview) {
42176
+ taskUpdateBlocked(input.id, "TERMINAL_REVIEW_CONFIGURATION_LOCKED", { requireReview: input.requireReview });
42177
+ return JSON.stringify({
42178
+ success: false,
42179
+ code: "TERMINAL_REVIEW_CONFIGURATION_LOCKED",
42180
+ error: "requireReview cannot be changed on a terminal task",
42181
+ hint: "Configure requireReview before the task reaches a terminal status"
42182
+ });
42183
+ }
42184
+ if (existing.status !== "pending" && existing.requireReview === true && input.requireReview === false) {
42185
+ taskUpdateBlocked(input.id, "REVIEW_REQUIREMENT_LOCKED", {});
42186
+ return JSON.stringify({
42187
+ success: false,
42188
+ code: "REVIEW_REQUIREMENT_LOCKED",
42189
+ error: "requireReview cannot be disabled after a task leaves pending",
42190
+ hint: "Configure requireReview while the task is pending"
42191
+ });
42192
+ }
42193
+ if (existing.status === "completed" && input.result !== void 0) {
42194
+ const error = missingTerminalDetail("result", input.result ?? existing.result);
42195
+ if (error) return error;
42196
+ }
42197
+ if (existing.status === "failed" && input.failureReason !== void 0) {
42198
+ const error = missingTerminalDetail(
42199
+ "failureReason",
42200
+ input.failureReason ?? existing.failureReason
42201
+ );
42202
+ if (error) return error;
42203
+ }
42018
42204
  const actor = trustedActor(trustedProject, rc) ?? (existing.ownerType === "agent" ? `agent:${existing.ownerId}` : `user:${existing.ownerId ?? ownerId}`);
42019
- const threadId = trustedProject?.projectTask?.threadId ?? (trustedProject?.projectRoom ? void 0 : input.sourceId ?? rc.thread_id);
42205
+ const workItemStore = getTaskWorkItemStore();
42020
42206
  const lifecycle = isAgentTask ? createTaskLifecycleService({
42021
42207
  taskStore: store,
42022
42208
  workItemStore: trustedProject ? getProjectTaskWorkItemStore() : getTaskWorkItemStore()
42023
42209
  }) : void 0;
42210
+ let trustedReferenceSnapshots;
42211
+ if (input.parentId !== void 0 || input.dependencies !== void 0) {
42212
+ if (delegatedTaskId) {
42213
+ const delegatedDependencyError = await validateDelegatedDependencies(
42214
+ store,
42215
+ tenantId2,
42216
+ delegatedTaskId,
42217
+ { workspaceId: existing.workspaceId, projectId: existing.projectId },
42218
+ input.parentId,
42219
+ input.dependencies,
42220
+ input.id
42221
+ );
42222
+ if (delegatedDependencyError) {
42223
+ taskUpdateBlocked(input.id, "DELEGATED_TASK_SCOPE_VIOLATION", { delegatedDependencyError });
42224
+ return delegatedDependencyError;
42225
+ }
42226
+ }
42227
+ const referenceError = await validateReferencedTasks(
42228
+ store,
42229
+ tenantId2,
42230
+ { workspaceId: existing.workspaceId, projectId: existing.projectId },
42231
+ input.parentId,
42232
+ input.dependencies
42233
+ );
42234
+ if (referenceError) {
42235
+ taskUpdateBlocked(input.id, "INVALID_TASK_REFERENCES", { referenceError });
42236
+ return referenceError;
42237
+ }
42238
+ if (trustedProject) {
42239
+ trustedReferenceSnapshots = await captureReferencedTaskSnapshots(
42240
+ store,
42241
+ tenantId2,
42242
+ { workspaceId: existing.workspaceId, projectId: existing.projectId },
42243
+ input.parentId,
42244
+ input.dependencies
42245
+ );
42246
+ if (!trustedReferenceSnapshots) {
42247
+ taskUpdateBlocked(input.id, "PROJECT_TASK_CONTEXT_INVALID", { reason: "reference snapshots unavailable" });
42248
+ return trustedContextError();
42249
+ }
42250
+ }
42251
+ }
42252
+ const effectiveDependencies = input.dependencies ?? existing.dependencies ?? [];
42253
+ const effectiveStatus = input.status ?? existing.status;
42254
+ if (effectiveStatus === "in_progress" && effectiveDependencies.length > 0) {
42255
+ const dependencyError = await validateEffectiveDependencies(
42256
+ store,
42257
+ tenantId2,
42258
+ { workspaceId: existing.workspaceId, projectId: existing.projectId },
42259
+ effectiveDependencies
42260
+ );
42261
+ if (dependencyError) {
42262
+ const trustedException = trustedProject?.projectTask && input.dependencies !== void 0 ? await validateTrustedChildDependencyWait(
42263
+ store,
42264
+ tenantId2,
42265
+ existing,
42266
+ effectiveDependencies,
42267
+ trustedProject
42268
+ ) : void 0;
42269
+ if (trustedException === void 0) {
42270
+ taskUpdateBlocked(input.id, "DEPENDENCY_BLOCKED", { dependencyError });
42271
+ return dependencyError;
42272
+ }
42273
+ if (trustedException) return trustedException;
42274
+ }
42275
+ }
42276
+ let reconciledTask;
42277
+ let reconciliationMetadata = {};
42278
+ let descriptionMutated = false;
42279
+ if (isAgentTask && input.description !== void 0 && !valuesEqual(input.description, existing.description)) {
42280
+ const oldBelief = (0, import_protocols33.parseTaskBeliefState)(existing.description ?? "");
42281
+ const newBelief = (0, import_protocols33.parseTaskBeliefState)(input.description);
42282
+ const hasBeliefState = oldBelief.success || newBelief.success;
42283
+ if (hasBeliefState) {
42284
+ await validateExecutionResult();
42285
+ const reconciliation = await lifecycle.updateTaskDescriptionWithReconciliation({
42286
+ tenantId: tenantId2,
42287
+ taskId: input.id,
42288
+ description: input.description,
42289
+ actor,
42290
+ threadId: trustedProject?.projectTask?.threadId ?? (trustedProject?.projectRoom ? void 0 : input.sourceId ?? rc.thread_id)
42291
+ });
42292
+ if (!reconciliation.success) return JSON.stringify(reconciliation);
42293
+ reconciledTask = reconciliation.task;
42294
+ reconciliationMetadata = { ...reconciliation };
42295
+ delete reconciliationMetadata.task;
42296
+ descriptionMutated = reconciliation.mutated;
42297
+ if (descriptionMutated) markMutation();
42298
+ }
42299
+ }
42300
+ const updates = {};
42301
+ const settableFields = [
42302
+ "title",
42303
+ "description",
42304
+ "priority",
42305
+ "dueDate",
42306
+ "metadata",
42307
+ "parentId",
42308
+ "sourceId",
42309
+ "context",
42310
+ "ownerId",
42311
+ "result",
42312
+ "failureReason",
42313
+ "requireReview",
42314
+ "dependencies",
42315
+ "files"
42316
+ ];
42317
+ for (const field of settableFields) {
42318
+ if (trustedProject && (field === "sourceId" || field === "context" || field === "ownerId")) continue;
42319
+ if (field === "description" && reconciledTask) continue;
42320
+ const requested = input[field];
42321
+ const persisted = reconciledTask ?? existing;
42322
+ if (requested !== void 0 && !updateValuesEqual(field, requested, persisted[field])) {
42323
+ updates[field] = requested;
42324
+ }
42325
+ }
42326
+ if (!reconciledTask && Object.keys(updates).length > 0) {
42327
+ await validateExecutionResult();
42328
+ }
42329
+ if (trustedProject && (input.parentId !== void 0 || input.dependencies !== void 0)) {
42330
+ if (!await referencedTaskSnapshotsStillMatch(
42331
+ store,
42332
+ tenantId2,
42333
+ { workspaceId: existing.workspaceId, projectId: existing.projectId },
42334
+ trustedReferenceSnapshots
42335
+ )) {
42336
+ taskUpdateBlocked(input.id, "PROJECT_TASK_CONTEXT_INVALID", { reason: "referenced task changed" });
42337
+ return trustedContextError("Parent or dependency task changed before update.");
42338
+ }
42339
+ }
42340
+ if (trustedProject) {
42341
+ try {
42342
+ await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
42343
+ } catch (error) {
42344
+ taskUpdateBlocked(input.id, "PROJECT_POLICY_ERROR", { policyError: String(error) });
42345
+ return projectPolicyError(error);
42346
+ }
42347
+ }
42348
+ const snapshot = trustedProject ? taskMutationSnapshot(existing) : void 0;
42349
+ taskUpdateDebug("update:write", {
42350
+ updateKeys: Object.keys(updates),
42351
+ useCas: !!snapshot,
42352
+ storeMethod: snapshot ? "updateIfSnapshot" : "update"
42353
+ });
42354
+ const updated = Object.keys(updates).length > 0 ? snapshot ? await store.updateIfSnapshot(tenantId2, input.id, updates, snapshot) : await store.update(tenantId2, input.id, updates) : reconciledTask ?? existing;
42355
+ taskUpdateDebug("update:result", {
42356
+ updated: !!updated,
42357
+ resultStatus: updated?.status,
42358
+ resultUpdatedAt: updated?.updatedAt?.toISOString?.()
42359
+ });
42360
+ if (!updated) {
42361
+ taskUpdateBlocked(input.id, "TASK_UPDATE_FAILED", { storeMethod: snapshot ? "updateIfSnapshot" : "update" });
42362
+ return JSON.stringify({
42363
+ success: false,
42364
+ code: "TASK_UPDATE_FAILED",
42365
+ error: `Failed to update task '${input.id}'.`,
42366
+ hint: "The task may have been deleted, the ID may be incorrect, or the store rejected the write. Use manage_task get to verify the task still exists, then retry the update."
42367
+ });
42368
+ }
42369
+ if (Object.keys(updates).length > 0) markMutation();
42370
+ if (reconciledTask && Object.keys(updates).length === 0) {
42371
+ return successfulTaskResponse(input.id, updated, descriptionMutated, reconciliationMetadata);
42372
+ }
42373
+ if (Object.keys(updates).length === 0) {
42374
+ return successfulTaskResponse(input.id, updated, false);
42375
+ }
42376
+ const workItemAction = "updated";
42377
+ const workItemSummary = input.summary;
42378
+ let activityWarnings;
42379
+ try {
42380
+ if (trustedProject) {
42381
+ try {
42382
+ await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
42383
+ } catch (error) {
42384
+ return projectPolicyError(error);
42385
+ }
42386
+ }
42387
+ await workItemStore.create({
42388
+ taskId: input.id,
42389
+ tenantId: tenantId2,
42390
+ action: workItemAction,
42391
+ actor,
42392
+ threadId: trustedProject?.projectTask?.threadId ?? (trustedProject?.projectRoom ? void 0 : input.sourceId),
42393
+ summary: workItemSummary,
42394
+ detail: {
42395
+ ...input.result !== void 0 && { result: input.result },
42396
+ ...input.failureReason !== void 0 && { failureReason: input.failureReason }
42397
+ },
42398
+ workspaceId: updated.workspaceId,
42399
+ projectId: updated.projectId
42400
+ });
42401
+ } catch (error) {
42402
+ activityWarnings = [{
42403
+ code: "TASK_UPDATE_ACTIVITY_WRITE_FAILED",
42404
+ taskId: input.id,
42405
+ error: error instanceof Error ? error.message : String(error)
42406
+ }];
42407
+ }
42408
+ const lifecycleWarnings = Array.isArray(reconciliationMetadata.warnings) ? reconciliationMetadata.warnings : void 0;
42409
+ return successfulTaskResponse(input.id, updated, true, {
42410
+ ...reconciliationMetadata,
42411
+ warnings: mergeTaskUpdateWarnings(lifecycleWarnings, activityWarnings)
42412
+ });
42413
+ }
42414
+ case "set_status": {
42415
+ if (!input.id) {
42416
+ taskUpdateBlocked(input.id, "MISSING_TASK_ID", {});
42417
+ return JSON.stringify({
42418
+ success: false,
42419
+ code: "MISSING_TASK_ID",
42420
+ error: "id is required for set_status action",
42421
+ hint: "Pass the task ID you want to update"
42422
+ });
42423
+ }
42424
+ if (!input.status) {
42425
+ return JSON.stringify({
42426
+ success: false,
42427
+ code: "MISSING_STATUS",
42428
+ error: "status is required for set_status action",
42429
+ hint: "Pass the target status: pending, in_progress, completed, failed, interrupted, cancelled"
42430
+ });
42431
+ }
42432
+ if (delegatedTaskId && input.id !== delegatedTaskId) {
42433
+ return delegatedTaskScopeError(delegatedTaskId);
42434
+ }
42435
+ const existing = await store.getById(tenantId2, input.id);
42436
+ taskUpdateDebug("set_status:loaded", existing ? {
42437
+ status: existing.status,
42438
+ updatedAt: existing.updatedAt?.toISOString()
42439
+ } : { found: false });
42440
+ if (!existing) {
42441
+ taskUpdateBlocked(input.id, "TASK_NOT_FOUND", {});
42442
+ return JSON.stringify({
42443
+ success: false,
42444
+ code: "TASK_NOT_FOUND",
42445
+ error: `Task '${input.id}' was not found.`,
42446
+ hint: "Use manage_task list to see available tasks and their correct IDs."
42447
+ });
42448
+ }
42449
+ if (!taskMatchesRuntimeScope3(existing, workspaceId, projectId)) {
42450
+ taskUpdateBlocked(input.id, "TASK_NOT_FOUND_OR_INACCESSIBLE", {});
42451
+ return taskScopeAccessError(input.id);
42452
+ }
42453
+ if (trustedProject?.projectTask) {
42454
+ const trustedFailure = trustedTaskContextFailure(existing, trustedProject.projectTask);
42455
+ if (trustedFailure) {
42456
+ taskUpdateBlocked(input.id, "PROJECT_TASK_CONTEXT_INVALID", {
42457
+ taskOwnerId: existing.ownerId,
42458
+ trustedAssistantId: trustedProject.projectTask.assistantId,
42459
+ taskThreadId: existing.context?.thread_id,
42460
+ trustedThreadId: trustedProject.projectTask.threadId
42461
+ });
42462
+ return trustedFailure;
42463
+ }
42464
+ }
42465
+ if (trustedProject && input.dependencyTaskIds !== void 0) {
42466
+ const interruption = input.context?.interruption;
42467
+ const interruptionType2 = interruption && typeof interruption === "object" ? interruption.type : void 0;
42468
+ if (input.status !== "interrupted" || interruptionType2 !== "external_dependency") {
42469
+ taskUpdateBlocked(input.id, "INVALID_EXTERNAL_DEPENDENCY", {});
42470
+ return JSON.stringify({
42471
+ success: false,
42472
+ code: "INVALID_EXTERNAL_DEPENDENCY",
42473
+ error: "dependencyTaskIds are only valid for external dependency interruptions."
42474
+ });
42475
+ }
42476
+ }
42477
+ if (trustedProject && (input.ownerType !== void 0 && input.ownerType !== existing.ownerType || input.ownerId !== void 0 && input.ownerId !== existing.ownerId)) {
42478
+ taskUpdateBlocked(input.id, "TASK_REASSIGN_ENDPOINT_REQUIRED", {});
42479
+ return JSON.stringify({
42480
+ success: false,
42481
+ code: "TASK_REASSIGN_ENDPOINT_REQUIRED",
42482
+ error: "Project task ownership changes require the reassignment endpoint."
42483
+ });
42484
+ }
42485
+ if (existing.status === "review" || input.status === "review") {
42486
+ taskUpdateBlocked(input.id, "TASK_STATUS_UNSUPPORTED", {});
42487
+ return JSON.stringify({
42488
+ success: false,
42489
+ code: "TASK_STATUS_UNSUPPORTED",
42490
+ error: "Task status is not supported by the task lifecycle."
42491
+ });
42492
+ }
42493
+ const isAgentTask = existing.ownerType === "agent";
42494
+ const changesOwnerType = input.ownerType !== void 0 && input.ownerType !== existing.ownerType;
42495
+ const changesAgentIdentity = isAgentTask && (input.ownerId !== void 0 && input.ownerId !== existing.ownerId || input.parentId !== void 0 && input.parentId !== existing.parentId);
42496
+ if (changesOwnerType || changesAgentIdentity) {
42497
+ taskUpdateBlocked(input.id, "TASK_OWNERSHIP_IMMUTABLE", {});
42498
+ return JSON.stringify({
42499
+ success: false,
42500
+ code: "TASK_OWNERSHIP_IMMUTABLE",
42501
+ error: "Agent task ownerType, ownerId, and parentId cannot be changed after task creation.",
42502
+ hint: "Create a separate task for different ownership or parentage."
42503
+ });
42504
+ }
42505
+ const actor = trustedActor(trustedProject, rc) ?? (existing.ownerType === "agent" ? `agent:${existing.ownerId}` : `user:${existing.ownerId ?? ownerId}`);
42506
+ const statusWorkItemStore = trustedProject ? getProjectTaskWorkItemStore() : getTaskWorkItemStore();
42507
+ const lifecycle = isAgentTask ? createTaskLifecycleService({
42508
+ taskStore: store,
42509
+ workItemStore: statusWorkItemStore
42510
+ }) : void 0;
42024
42511
  const lifecycleMutationResponse = (result, extra = {}) => {
42025
42512
  if (result.success && result.mutated) markMutation();
42026
42513
  return lifecycleResponse(input.id, result, extra);
42027
42514
  };
42028
- const hasCarriedContentFields = () => ["title", "description", "priority", "dueDate", "metadata", "files"].some((key4) => input[key4] !== void 0);
42515
+ if (input.status === "in_progress" && (existing.dependencies ?? []).length > 0) {
42516
+ const dependencyError = await validateEffectiveDependencies(
42517
+ store,
42518
+ tenantId2,
42519
+ { workspaceId: existing.workspaceId, projectId: existing.projectId },
42520
+ existing.dependencies ?? []
42521
+ );
42522
+ if (dependencyError) {
42523
+ const trustedException = trustedProject?.projectTask ? await validateTrustedChildDependencyWait(
42524
+ store,
42525
+ tenantId2,
42526
+ existing,
42527
+ existing.dependencies ?? [],
42528
+ trustedProject
42529
+ ) : void 0;
42530
+ if (trustedException === void 0) {
42531
+ taskUpdateBlocked(input.id, "DEPENDENCY_BLOCKED", { dependencyError });
42532
+ return dependencyError;
42533
+ }
42534
+ if (trustedException) return trustedException;
42535
+ }
42536
+ }
42537
+ const statusThreadId = trustedProject?.projectTask?.threadId ?? (trustedProject?.projectRoom ? void 0 : input.sourceId ?? rc.thread_id);
42029
42538
  if (lifecycle && input.status === "failed") {
42030
42539
  await validateExecutionResult();
42031
42540
  const callerError = await revalidateCaller();
@@ -42035,11 +42544,9 @@ function createTaskMiddleware(options = {}) {
42035
42544
  taskId: input.id,
42036
42545
  failureReason: input.failureReason ?? existing.failureReason ?? "",
42037
42546
  actor,
42038
- threadId
42547
+ threadId: statusThreadId
42039
42548
  });
42040
- if (!failed.success) return lifecycleMutationResponse(failed);
42041
- if (trustedProject || !hasCarriedContentFields()) return lifecycleMutationResponse(failed);
42042
- existing = { ...existing, status: input.status };
42549
+ return lifecycleMutationResponse(failed);
42043
42550
  }
42044
42551
  if (lifecycle && input.status === "cancelled") {
42045
42552
  await validateExecutionResult();
@@ -42049,12 +42556,10 @@ function createTaskMiddleware(options = {}) {
42049
42556
  tenantId: tenantId2,
42050
42557
  taskId: input.id,
42051
42558
  actor,
42052
- threadId,
42559
+ threadId: statusThreadId,
42053
42560
  summary: input.summary
42054
42561
  });
42055
- if (!cancelled.success) return lifecycleMutationResponse(cancelled);
42056
- if (trustedProject || !hasCarriedContentFields()) return lifecycleMutationResponse(cancelled);
42057
- existing = { ...existing, status: input.status };
42562
+ return lifecycleMutationResponse(cancelled);
42058
42563
  }
42059
42564
  if (lifecycle && input.status === "interrupted" && !(input.context?.interruption && typeof input.context.interruption === "object" && input.context.interruption.type === "review_required")) {
42060
42565
  const interruption = input.context?.interruption;
@@ -42076,12 +42581,10 @@ function createTaskMiddleware(options = {}) {
42076
42581
  type,
42077
42582
  summary: input.summary ?? "",
42078
42583
  actor,
42079
- threadId,
42584
+ threadId: statusThreadId,
42080
42585
  dependencyTaskIds: input.dependencyTaskIds
42081
42586
  });
42082
- if (!interrupted.success) return lifecycleMutationResponse(interrupted);
42083
- if (trustedProject || !hasCarriedContentFields()) return lifecycleMutationResponse(interrupted);
42084
- existing = { ...existing, status: input.status };
42587
+ return lifecycleMutationResponse(interrupted);
42085
42588
  }
42086
42589
  if (lifecycle && input.status === "in_progress" && existing.status === "interrupted") {
42087
42590
  await validateExecutionResult();
@@ -42091,11 +42594,9 @@ function createTaskMiddleware(options = {}) {
42091
42594
  tenantId: tenantId2,
42092
42595
  taskId: input.id,
42093
42596
  actor,
42094
- threadId
42597
+ threadId: statusThreadId
42095
42598
  });
42096
- if (!resumed.success) return lifecycleMutationResponse(resumed);
42097
- if (trustedProject || !hasCarriedContentFields()) return lifecycleMutationResponse(resumed);
42098
- existing = { ...existing, status: input.status };
42599
+ return lifecycleMutationResponse(resumed);
42099
42600
  }
42100
42601
  if (lifecycle && input.status === "in_progress" && existing.status === "pending") {
42101
42602
  await validateExecutionResult();
@@ -42105,11 +42606,9 @@ function createTaskMiddleware(options = {}) {
42105
42606
  tenantId: tenantId2,
42106
42607
  taskId: input.id,
42107
42608
  actor,
42108
- threadId
42609
+ threadId: statusThreadId
42109
42610
  });
42110
- if (!started.success) return lifecycleMutationResponse(started);
42111
- if (trustedProject || !hasCarriedContentFields()) return lifecycleMutationResponse(started);
42112
- existing = { ...existing, status: input.status };
42611
+ return lifecycleMutationResponse(started);
42113
42612
  }
42114
42613
  if (lifecycle && input.status === "in_progress" && existing.status === "failed") {
42115
42614
  await validateExecutionResult();
@@ -42119,11 +42618,9 @@ function createTaskMiddleware(options = {}) {
42119
42618
  tenantId: tenantId2,
42120
42619
  taskId: input.id,
42121
42620
  actor,
42122
- threadId
42621
+ threadId: statusThreadId
42123
42622
  });
42124
- if (!retried.success) return lifecycleMutationResponse(retried);
42125
- if (trustedProject || !hasCarriedContentFields()) return lifecycleMutationResponse(retried);
42126
- existing = { ...existing, status: input.status };
42623
+ return lifecycleMutationResponse(retried);
42127
42624
  }
42128
42625
  if (isAgentTask && input.requireReview === true && options.reviewMode !== "hitl") {
42129
42626
  return reviewModeDisabledResponse();
@@ -42145,54 +42642,39 @@ function createTaskMiddleware(options = {}) {
42145
42642
  });
42146
42643
  }
42147
42644
  const effectiveRequireReview = existing.requireReview === true || input.requireReview === true;
42148
- const workItemStore = getTaskWorkItemStore();
42149
- const governedAgentCompletion = isAgentTask && (input.status === "completed" || candidateReviewInterruption && !!input.result?.trim() && !!input.beliefImpact?.length);
42645
+ const candidateReviewInterruption = input.status === "interrupted" && input.context?.interruption && typeof input.context.interruption === "object" && input.context.interruption.type === "review_required" && !!input.result?.trim() && !!input.beliefImpact?.length;
42646
+ const governedAgentCompletion = isAgentTask && (input.status === "completed" || candidateReviewInterruption);
42150
42647
  if (governedAgentCompletion) {
42151
- const guardedFields = [
42152
- "parentId",
42153
- "ownerType",
42154
- "ownerId",
42155
- "description"
42156
- ];
42157
- for (const field of guardedFields) {
42158
- const requestValue = input[field];
42159
- const existingValue = existing[field];
42160
- if (requestValue !== void 0 && requestValue !== existingValue) {
42161
- return JSON.stringify({
42162
- success: false,
42163
- code: "COMPLETION_CONTEXT_MUTATION",
42164
- error: `Cannot change ${field} while completing an agent task`,
42165
- hint: "Persist the context change in a separate update before completing the task"
42166
- });
42167
- }
42168
- }
42169
42648
  if (!input.beliefImpact?.length) return missingBeliefImpactError();
42170
42649
  const finalResult = input.result ?? existing.result ?? "";
42171
- const threadId2 = trustedProject?.projectTask?.threadId ?? (trustedProject?.projectRoom ? void 0 : input.sourceId ?? rc.thread_id);
42172
- const lifecycle2 = createTaskLifecycleService({
42173
- taskStore: store,
42174
- workItemStore: trustedProject ? getProjectTaskWorkItemStore() : getTaskWorkItemStore()
42175
- });
42650
+ if (!finalResult.trim()) {
42651
+ return JSON.stringify({
42652
+ success: false,
42653
+ code: "MISSING_RESULT",
42654
+ error: "result is required for completing a task",
42655
+ hint: "Provide a nonblank result"
42656
+ });
42657
+ }
42176
42658
  const completionInput = {
42177
42659
  tenantId: tenantId2,
42178
42660
  taskId: input.id,
42179
42661
  result: finalResult,
42180
42662
  beliefImpact: input.beliefImpact,
42181
42663
  actor,
42182
- threadId: threadId2,
42664
+ threadId: statusThreadId,
42183
42665
  sourceId: trustedProject ? void 0 : input.sourceId
42184
42666
  };
42185
42667
  await validateExecutionResult();
42186
- const needsReview = effectiveRequireReview || candidateReviewInterruption || !!reviewInterruption(existing);
42668
+ const needsReview = effectiveRequireReview || !!reviewInterruption(existing);
42187
42669
  if (!needsReview) {
42188
42670
  const callerError2 = await revalidateCaller();
42189
42671
  if (callerError2) return callerError2;
42190
- const result = existing.status === "completed" ? await lifecycle2.repairCompletion(completionInput) : await lifecycle2.completeAgentTask(completionInput);
42672
+ const result = existing.status === "completed" ? await lifecycle.repairCompletion(completionInput) : await lifecycle.completeAgentTask(completionInput);
42191
42673
  return lifecycleMutationResponse(result);
42192
42674
  }
42193
42675
  const callerError = await revalidateCaller();
42194
42676
  if (callerError) return callerError;
42195
- const submitted = await lifecycle2.submitReview({
42677
+ const submitted = await lifecycle.submitReview({
42196
42678
  ...completionInput,
42197
42679
  reviewMode: options.reviewMode ?? "disabled",
42198
42680
  configureRequireReview: input.requireReview === true && existing.requireReview !== true
@@ -42217,30 +42699,34 @@ function createTaskMiddleware(options = {}) {
42217
42699
  if (response?.action === "approve") {
42218
42700
  const approvalCallerError = await revalidateCaller();
42219
42701
  if (approvalCallerError) return approvalCallerError;
42220
- return lifecycleMutationResponse(await lifecycle2.approveInterrupted({
42702
+ return lifecycleMutationResponse(await lifecycle.approveInterrupted({
42221
42703
  tenantId: tenantId2,
42222
42704
  taskId: input.id,
42223
42705
  evidenceId,
42224
42706
  actor,
42225
- threadId: threadId2
42707
+ threadId: statusThreadId
42226
42708
  }), { reviewerAction: "approved" });
42227
42709
  }
42228
42710
  if (response?.action === "reject") {
42229
42711
  const note = response.data?.note?.trim() || "Changes requested.";
42230
42712
  const rejectionCallerError = await revalidateCaller();
42231
42713
  if (rejectionCallerError) return rejectionCallerError;
42232
- return lifecycleMutationResponse(await lifecycle2.rejectInterrupted({
42714
+ return lifecycleMutationResponse(await lifecycle.rejectInterrupted({
42233
42715
  tenantId: tenantId2,
42234
42716
  taskId: input.id,
42235
42717
  evidenceId,
42236
42718
  actor,
42237
- threadId: threadId2,
42719
+ threadId: statusThreadId,
42238
42720
  note
42239
42721
  }), { reviewerAction: "rejected", reviewerNote: note });
42240
42722
  }
42241
42723
  return lifecycleMutationResponse(submitted, { code: "REVIEW_REQUIRED" });
42242
42724
  }
42243
- if (isAgentTask && input.status !== void 0 && input.status !== existing.status) {
42725
+ if (isAgentTask && input.status !== existing.status) {
42726
+ taskUpdateBlocked(input.id, "AGENT_TASK_LIFECYCLE_REQUIRED", {
42727
+ currentStatus: existing.status,
42728
+ requestedStatus: input.status
42729
+ });
42244
42730
  return JSON.stringify({
42245
42731
  success: false,
42246
42732
  code: "AGENT_TASK_LIFECYCLE_REQUIRED",
@@ -42248,45 +42734,17 @@ function createTaskMiddleware(options = {}) {
42248
42734
  hint: "Valid transitions: pending\u2192in_progress, in_progress\u2192completed (requires result + beliefImpact), in_progress\u2192failed (requires failureReason), in_progress\u2192cancelled, in_progress\u2192interrupted. Check the current status with manage_task get first."
42249
42735
  });
42250
42736
  }
42251
- const persistedStatus = input.status;
42252
- let trustedReferenceSnapshots;
42253
- if (input.parentId !== void 0 || input.dependencies !== void 0) {
42254
- if (delegatedTaskId) {
42255
- const delegatedDependencyError = await validateDelegatedDependencies(
42256
- store,
42257
- tenantId2,
42258
- delegatedTaskId,
42259
- { workspaceId: existing.workspaceId, projectId: existing.projectId },
42260
- input.parentId,
42261
- input.dependencies,
42262
- input.id
42263
- );
42264
- if (delegatedDependencyError) return delegatedDependencyError;
42265
- }
42266
- const referenceError = await validateReferencedTasks(
42267
- store,
42268
- tenantId2,
42269
- { workspaceId: existing.workspaceId, projectId: existing.projectId },
42270
- input.parentId,
42271
- input.dependencies
42272
- );
42273
- if (referenceError) return referenceError;
42274
- if (trustedProject) {
42275
- trustedReferenceSnapshots = await captureReferencedTaskSnapshots(
42276
- store,
42277
- tenantId2,
42278
- { workspaceId: existing.workspaceId, projectId: existing.projectId },
42279
- input.parentId,
42280
- input.dependencies
42281
- );
42282
- if (!trustedReferenceSnapshots) return trustedContextError();
42283
- }
42284
- }
42285
42737
  if (input.status) {
42286
42738
  if (!isAgentTask && !isValidUserTransition(existing.status, input.status)) {
42287
42739
  const allowed = USER_VALID_TRANSITIONS[existing.status] || [];
42740
+ taskUpdateBlocked(input.id, "INVALID_USER_TRANSITION", {
42741
+ currentStatus: existing.status,
42742
+ requestedStatus: input.status,
42743
+ allowedTransitions: allowed
42744
+ });
42288
42745
  return JSON.stringify({
42289
42746
  success: false,
42747
+ code: "INVALID_USER_TRANSITION",
42290
42748
  error: `Cannot transition task from '${existing.status}' to '${input.status}'`,
42291
42749
  allowedTransitions: allowed,
42292
42750
  hint: `From '${existing.status}', valid transitions are: ${allowed.join(", ")}`
@@ -42304,154 +42762,47 @@ function createTaskMiddleware(options = {}) {
42304
42762
  );
42305
42763
  if (error) return error;
42306
42764
  }
42307
- const effectiveDependencies = input.dependencies ?? existing.dependencies ?? [];
42308
- const effectiveStatus = input.status ?? existing.status;
42309
- if (effectiveStatus === "in_progress" && effectiveDependencies.length > 0) {
42310
- const dependencyError = await validateEffectiveDependencies(
42311
- store,
42312
- tenantId2,
42313
- { workspaceId: existing.workspaceId, projectId: existing.projectId },
42314
- effectiveDependencies
42315
- );
42316
- if (dependencyError) {
42317
- const trustedException = trustedProject?.projectTask && input.dependencies !== void 0 ? await validateTrustedChildDependencyWait(
42318
- store,
42319
- tenantId2,
42320
- existing,
42321
- effectiveDependencies,
42322
- trustedProject
42323
- ) : void 0;
42324
- if (trustedException === void 0) return dependencyError;
42325
- if (trustedException) return trustedException;
42326
- }
42765
+ if (input.status === existing.status) {
42766
+ return successfulTaskResponse(input.id, existing, false);
42327
42767
  }
42328
- let reconciledTask;
42329
- let reconciliationMetadata = {};
42330
- let descriptionMutated = false;
42331
- if (isAgentTask && input.description !== void 0 && !valuesEqual(input.description, existing.description)) {
42332
- await validateExecutionResult();
42333
- const reconciliation = await lifecycle.updateTaskDescriptionWithReconciliation({
42334
- tenantId: tenantId2,
42335
- taskId: input.id,
42336
- description: input.description,
42337
- actor,
42338
- threadId: trustedProject?.projectTask?.threadId ?? (trustedProject?.projectRoom ? void 0 : input.sourceId ?? rc.thread_id)
42339
- });
42340
- if (!reconciliation.success) return JSON.stringify(reconciliation);
42341
- reconciledTask = reconciliation.task;
42342
- reconciliationMetadata = { ...reconciliation };
42343
- delete reconciliationMetadata.task;
42344
- descriptionMutated = reconciliation.mutated;
42345
- if (descriptionMutated) markMutation();
42346
- }
42347
- const updates = {};
42348
- const settableFields = [
42349
- "title",
42350
- "description",
42351
- "priority",
42352
- "dueDate",
42353
- "metadata",
42354
- "parentId",
42355
- "sourceId",
42356
- "context",
42357
- "ownerId",
42358
- "result",
42359
- "failureReason",
42360
- "requireReview",
42361
- "dependencies",
42362
- "files"
42363
- ];
42364
- for (const field of settableFields) {
42365
- if (trustedProject && (field === "sourceId" || field === "context" || field === "ownerId")) continue;
42366
- if (field === "description" && reconciledTask) continue;
42367
- const requested = input[field];
42368
- const persisted = reconciledTask ?? existing;
42369
- if (requested !== void 0 && !updateValuesEqual(field, requested, persisted[field])) {
42370
- updates[field] = requested;
42371
- }
42372
- }
42373
- if (persistedStatus !== void 0 && existing.status !== persistedStatus) {
42374
- updates.status = persistedStatus;
42375
- }
42376
- if (!reconciledTask && Object.keys(updates).length > 0) {
42377
- await validateExecutionResult();
42378
- }
42379
- if (trustedProject && (input.parentId !== void 0 || input.dependencies !== void 0)) {
42380
- if (!await referencedTaskSnapshotsStillMatch(
42381
- store,
42382
- tenantId2,
42383
- { workspaceId: existing.workspaceId, projectId: existing.projectId },
42384
- trustedReferenceSnapshots
42385
- )) return trustedContextError("Parent or dependency task changed before update.");
42386
- }
42387
- if (trustedProject) {
42388
- try {
42389
- await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
42390
- } catch (error) {
42391
- return projectPolicyError(error);
42392
- }
42393
- }
42394
- const snapshot = trustedProject ? taskMutationSnapshot(existing) : void 0;
42395
- const updated = Object.keys(updates).length > 0 ? snapshot ? await store.updateIfSnapshot(tenantId2, input.id, updates, snapshot) : await store.update(tenantId2, input.id, updates) : reconciledTask ?? existing;
42396
- if (!updated) {
42768
+ const statusUpdates = { status: input.status };
42769
+ if (input.status === "completed" && input.result !== void 0) statusUpdates.result = input.result;
42770
+ if (input.status === "failed" && input.failureReason !== void 0) statusUpdates.failureReason = input.failureReason;
42771
+ if (input.summary !== void 0) statusUpdates.summary = input.summary;
42772
+ const statusSnapshot = trustedProject ? taskMutationSnapshot(existing) : void 0;
42773
+ taskUpdateDebug("set_status:write", {
42774
+ status: input.status,
42775
+ useCas: !!statusSnapshot
42776
+ });
42777
+ const updatedStatus = await (statusSnapshot ? store.updateIfSnapshot(tenantId2, input.id, statusUpdates, statusSnapshot) : store.update(tenantId2, input.id, statusUpdates));
42778
+ taskUpdateDebug("set_status:result", {
42779
+ updated: !!updatedStatus,
42780
+ resultStatus: updatedStatus?.status
42781
+ });
42782
+ if (!updatedStatus) {
42783
+ taskUpdateBlocked(input.id, "TASK_UPDATE_FAILED", {});
42397
42784
  return JSON.stringify({
42398
42785
  success: false,
42399
- error: `Failed to update task '${input.id}'`,
42400
- hint: "The task may have been deleted or the ID is incorrect"
42786
+ code: "TASK_UPDATE_FAILED",
42787
+ error: `Failed to update status of task '${input.id}'.`,
42788
+ hint: "Use manage_task get to verify the task exists, then retry."
42401
42789
  });
42402
42790
  }
42403
- if (Object.keys(updates).length > 0) markMutation();
42404
- if (reconciledTask && Object.keys(updates).length === 0) {
42405
- return successfulTaskResponse(input.id, updated, descriptionMutated, reconciliationMetadata);
42406
- }
42407
- if (Object.keys(updates).length === 0) {
42408
- return successfulTaskResponse(input.id, updated, false);
42409
- }
42410
- const actionMap = {
42411
- pending: "pending",
42412
- in_progress: "started",
42413
- failed: "failed",
42414
- interrupted: "interrupted",
42415
- completed: "completed",
42416
- cancelled: "cancelled"
42417
- };
42418
- const workItemAction = persistedStatus ? actionMap[persistedStatus] || "updated" : "updated";
42419
- const workItemSummary = input.summary || (persistedStatus ? `Status changed to ${persistedStatus}` : void 0);
42420
- let activityWarnings;
42791
+ markMutation();
42421
42792
  try {
42422
- if (trustedProject) {
42423
- try {
42424
- await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
42425
- } catch (error) {
42426
- return projectPolicyError(error);
42427
- }
42428
- }
42429
- await workItemStore.create({
42793
+ await statusWorkItemStore.create({
42430
42794
  taskId: input.id,
42431
42795
  tenantId: tenantId2,
42432
- action: workItemAction,
42796
+ action: input.status,
42433
42797
  actor,
42434
- threadId: trustedProject?.projectTask?.threadId ?? (trustedProject?.projectRoom ? void 0 : input.sourceId),
42435
- summary: workItemSummary,
42436
- detail: {
42437
- ...input.result !== void 0 && { result: input.result },
42438
- ...input.failureReason !== void 0 && { failureReason: input.failureReason }
42439
- },
42440
- workspaceId: updated.workspaceId,
42441
- projectId: updated.projectId
42798
+ threadId: statusThreadId ?? input.sourceId,
42799
+ summary: input.summary || `Status changed to ${input.status}`,
42800
+ workspaceId: updatedStatus.workspaceId,
42801
+ projectId: updatedStatus.projectId
42442
42802
  });
42443
- } catch (error) {
42444
- activityWarnings = [{
42445
- code: "TASK_UPDATE_ACTIVITY_WRITE_FAILED",
42446
- taskId: input.id,
42447
- error: error instanceof Error ? error.message : String(error)
42448
- }];
42803
+ } catch {
42449
42804
  }
42450
- const lifecycleWarnings = Array.isArray(reconciliationMetadata.warnings) ? reconciliationMetadata.warnings : void 0;
42451
- return successfulTaskResponse(input.id, updated, true, {
42452
- ...reconciliationMetadata,
42453
- warnings: mergeTaskUpdateWarnings(lifecycleWarnings, activityWarnings)
42454
- });
42805
+ return successfulTaskResponse(input.id, updatedStatus, true);
42455
42806
  }
42456
42807
  case "delete": {
42457
42808
  if (!input.id) {
@@ -42468,8 +42819,9 @@ function createTaskMiddleware(options = {}) {
42468
42819
  if (!existing) {
42469
42820
  return JSON.stringify({
42470
42821
  success: false,
42471
- error: `Task '${input.id}' not found`,
42472
- hint: "Use list to see available tasks and their IDs"
42822
+ code: "TASK_NOT_FOUND",
42823
+ error: `Task '${input.id}' was not found.`,
42824
+ hint: "Use manage_task list to see available tasks and their correct IDs."
42473
42825
  });
42474
42826
  }
42475
42827
  if (!taskMatchesRuntimeScope3(existing, workspaceId, projectId)) {
@@ -42495,8 +42847,9 @@ function createTaskMiddleware(options = {}) {
42495
42847
  if (!deleted) {
42496
42848
  return JSON.stringify({
42497
42849
  success: false,
42498
- error: `Task '${input.id}' not found or could not be deleted`,
42499
- hint: "Use list to verify the task exists"
42850
+ code: "TASK_DELETE_FAILED",
42851
+ error: `Task '${input.id}' was not found or could not be deleted.`,
42852
+ hint: "Use manage_task list to verify the task exists and you have access to it."
42500
42853
  });
42501
42854
  }
42502
42855
  return JSON.stringify({ success: true, message: `Task '${input.id}' deleted` });
@@ -42511,7 +42864,7 @@ function createTaskMiddleware(options = {}) {
42511
42864
  }
42512
42865
  };
42513
42866
  const reconcileExplicitExecutionResult = async (input, config, response, validationError, didMutate) => {
42514
- if (input.action !== "update" && input.action !== "add_activity" || !input.id) return response;
42867
+ if (input.action !== "update" && input.action !== "set_status" && input.action !== "add_activity" || !input.id) return response;
42515
42868
  const authority = classifyTaskAuthority(getRunConfig2(config));
42516
42869
  if (authority.kind === "projectRoom" || authority.kind === "projectTask" || authority.kind === "invalid") {
42517
42870
  return response;
@@ -42705,14 +43058,18 @@ ${TASK_CONVERGENCE_GUIDANCE}
42705
43058
  - Explicit ownerId: assign to a specific agent (cross-agent delegation)
42706
43059
 
42707
43060
  ## Actions
42708
- - create: Create a task (title required; result required for completed; failureReason required for failed)
43061
+ - create: Create a task (title required)
42709
43062
  - get: Get one task and its newest 100 activities (id required)
42710
43063
  - list: List tasks, filterable by ownerType/status/priority/parentId
42711
- - update: Update a task (id required; pass only the fields to change)
42712
- To mark complete: update with status='completed', result='...' (a nonblank input or existing result is required)
42713
- To mark failed: update with status='failed', failureReason='...' (a nonblank input or existing failureReason is required)
42714
- To pause for missing input: update with status='interrupted', summary='what is needed' (defaults to interruption type missing_input)
42715
- Status transitions are validated \u2014 only allowed transitions will succeed.
43064
+ - update: Update a task's content fields (title/description/priority/dueDate/metadata/parentId/sourceId/context/ownerId/result/failureReason/requireReview/dependencies/files)
43065
+ Status changes can also be done here, but use set_status for a simpler dedicated status update.
43066
+ - set_status: Change a task's status (id and status required). Use this when you only need to change the status.
43067
+ Valid status values: pending, in_progress, review, failed, interrupted, completed, cancelled
43068
+ Companion fields: result (for completed), failureReason (for failed), summary (for any status)
43069
+ To mark complete: set_status with status='completed', result='...'
43070
+ To mark failed: set_status with status='failed', failureReason='...'
43071
+ To pause for input: set_status with status='interrupted', summary='what is needed'
43072
+ Status can be freely changed to any valid value \u2014 no restrictions on transitions.
42716
43073
  - add_activity: Add a Markdown activity without changing task fields or status (id and content required)
42717
43074
  - delete: Delete a task (id required)
42718
43075