@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.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +664 -307
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +665 -307
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
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
|
|
24478
|
-
|
|
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;
|
|
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;
|
|
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.
|
|
25807
|
-
|
|
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
|
-
|
|
28305
|
-
|
|
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 =
|
|
33050
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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("
|
|
41391
|
-
failureReason: import_zod68.z.string().optional().describe("
|
|
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
|
-
|
|
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
|
-
|
|
41952
|
-
|
|
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)
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
42149
|
-
const governedAgentCompletion = isAgentTask && (input.status === "completed" || candidateReviewInterruption
|
|
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
|
-
|
|
42172
|
-
|
|
42173
|
-
|
|
42174
|
-
|
|
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:
|
|
42664
|
+
threadId: statusThreadId,
|
|
42183
42665
|
sourceId: trustedProject ? void 0 : input.sourceId
|
|
42184
42666
|
};
|
|
42185
42667
|
await validateExecutionResult();
|
|
42186
|
-
const needsReview = effectiveRequireReview ||
|
|
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
|
|
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
|
|
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
|
|
42702
|
+
return lifecycleMutationResponse(await lifecycle.approveInterrupted({
|
|
42221
42703
|
tenantId: tenantId2,
|
|
42222
42704
|
taskId: input.id,
|
|
42223
42705
|
evidenceId,
|
|
42224
42706
|
actor,
|
|
42225
|
-
threadId:
|
|
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
|
|
42714
|
+
return lifecycleMutationResponse(await lifecycle.rejectInterrupted({
|
|
42233
42715
|
tenantId: tenantId2,
|
|
42234
42716
|
taskId: input.id,
|
|
42235
42717
|
evidenceId,
|
|
42236
42718
|
actor,
|
|
42237
|
-
threadId:
|
|
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 !==
|
|
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
|
-
|
|
42308
|
-
|
|
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
|
-
|
|
42329
|
-
|
|
42330
|
-
|
|
42331
|
-
if (
|
|
42332
|
-
|
|
42333
|
-
|
|
42334
|
-
|
|
42335
|
-
|
|
42336
|
-
|
|
42337
|
-
|
|
42338
|
-
|
|
42339
|
-
|
|
42340
|
-
|
|
42341
|
-
|
|
42342
|
-
|
|
42343
|
-
|
|
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
|
-
|
|
42400
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
42796
|
+
action: input.status,
|
|
42433
42797
|
actor,
|
|
42434
|
-
threadId:
|
|
42435
|
-
summary:
|
|
42436
|
-
|
|
42437
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
42472
|
-
|
|
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
|
-
|
|
42499
|
-
|
|
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
|
|
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
|
|
42712
|
-
|
|
42713
|
-
|
|
42714
|
-
|
|
42715
|
-
|
|
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
|
|