@axiom-lattice/core 4.2.4 → 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 +22 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.js +877 -340
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +878 -340
- 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) {
|
|
@@ -14183,6 +14187,18 @@ async function createCommonMiddlewares(middlewareConfigs, filesystemBackend, fsI
|
|
|
14183
14187
|
|
|
14184
14188
|
// src/deep_agent_new/backends/sandboxFiles.ts
|
|
14185
14189
|
var path3 = __toESM(require("path"));
|
|
14190
|
+
var import_micromatch2 = __toESM(require("micromatch"));
|
|
14191
|
+
function matchesGlobFilter(matchPath, searchPath, glob) {
|
|
14192
|
+
if (!glob || glob === "**/*") {
|
|
14193
|
+
return true;
|
|
14194
|
+
}
|
|
14195
|
+
if (!glob.includes("/")) {
|
|
14196
|
+
return import_micromatch2.default.isMatch(path3.basename(matchPath), glob, { dot: true });
|
|
14197
|
+
}
|
|
14198
|
+
const base = searchPath.endsWith("/") ? searchPath : `${searchPath}/`;
|
|
14199
|
+
const relative4 = matchPath.startsWith(base) ? matchPath.slice(base.length) : matchPath;
|
|
14200
|
+
return import_micromatch2.default.isMatch(relative4, glob, { dot: true });
|
|
14201
|
+
}
|
|
14186
14202
|
var SandboxFilesystem = class {
|
|
14187
14203
|
constructor(options = {}) {
|
|
14188
14204
|
const { maxFileSizeMb = 10, sandboxInstance } = options;
|
|
@@ -14309,6 +14325,16 @@ var SandboxFilesystem = class {
|
|
|
14309
14325
|
}
|
|
14310
14326
|
async grepRaw(pattern, searchPath = "/", glob = null) {
|
|
14311
14327
|
try {
|
|
14328
|
+
if (this.sandbox.file.grepRecursive) {
|
|
14329
|
+
const result2 = await this.sandbox.file.grepRecursive(
|
|
14330
|
+
pattern,
|
|
14331
|
+
searchPath || "/"
|
|
14332
|
+
);
|
|
14333
|
+
const globFilter = glob || "**/*";
|
|
14334
|
+
return result2.matches.filter(
|
|
14335
|
+
(match) => matchesGlobFilter(match.path, searchPath || "/", globFilter)
|
|
14336
|
+
);
|
|
14337
|
+
}
|
|
14312
14338
|
const result = await this.sandbox.file.findFiles(searchPath || "/", glob || "**/*");
|
|
14313
14339
|
const filePaths = result.files;
|
|
14314
14340
|
const matches = [];
|
|
@@ -20442,7 +20468,7 @@ var fsSync = __toESM(require("fs"));
|
|
|
20442
20468
|
var path4 = __toESM(require("path"));
|
|
20443
20469
|
var import_child_process = require("child_process");
|
|
20444
20470
|
var import_fast_glob = __toESM(require("fast-glob"));
|
|
20445
|
-
var
|
|
20471
|
+
var import_micromatch3 = __toESM(require("micromatch"));
|
|
20446
20472
|
var SUPPORTS_NOFOLLOW = fsSync.constants.O_NOFOLLOW !== void 0;
|
|
20447
20473
|
var FilesystemBackend = class {
|
|
20448
20474
|
constructor(options = {}) {
|
|
@@ -20943,7 +20969,7 @@ var FilesystemBackend = class {
|
|
|
20943
20969
|
});
|
|
20944
20970
|
for (const fp of files) {
|
|
20945
20971
|
try {
|
|
20946
|
-
if (includeGlob && !
|
|
20972
|
+
if (includeGlob && !import_micromatch3.default.isMatch(path4.basename(fp), includeGlob)) {
|
|
20947
20973
|
continue;
|
|
20948
20974
|
}
|
|
20949
20975
|
const stat5 = await fs2.stat(fp);
|
|
@@ -24452,8 +24478,12 @@ Otherwise, the owning caller interprets the returned observation.
|
|
|
24452
24478
|
An execution result is an observation, not automatic proof of business
|
|
24453
24479
|
completion. \`task\` returns its exact \`executionResultId\`. After \`task\`
|
|
24454
24480
|
returns, inspect the observation, then pass that \`executionResultId\` to the
|
|
24455
|
-
meaningful \`manage_task
|
|
24456
|
-
|
|
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
|
|
24457
24487
|
\`executionResultId\` leaves the result pending so forgotten handling remains
|
|
24458
24488
|
detectable. Reconciliation does not require the task to become \`completed\`;
|
|
24459
24489
|
choose the truthful status. \`manage_task get\` exposes pending execution-result
|
|
@@ -24473,13 +24503,14 @@ independently.
|
|
|
24473
24503
|
6. **Reconcile** - revise Belief, Task, plan, and next action on Prediction Error,
|
|
24474
24504
|
then repeat only while a decision-relevant action remains and stop at honest convergence.
|
|
24475
24505
|
|
|
24476
|
-
Converge using existing statuses:
|
|
24506
|
+
Converge through \`set_status\` using existing statuses:
|
|
24477
24507
|
|
|
24478
|
-
- \`completed\`: acceptance is satisfied by evidence;
|
|
24508
|
+
- \`completed\`: acceptance is satisfied by evidence; \`set_status\` with a
|
|
24509
|
+
\`result\` and structured \`beliefImpact\`.
|
|
24479
24510
|
- \`in_progress\`: a feasible, decision-relevant action remains.
|
|
24480
24511
|
- \`pending\`: work is future or dependency-blocked.
|
|
24481
24512
|
- \`interrupted\`: an external condition is missing; record the condition needed to resume.
|
|
24482
|
-
- \`failed\`: no reasonable path remains;
|
|
24513
|
+
- \`failed\`: no reasonable path remains; \`set_status\` with a \`failureReason\`.
|
|
24483
24514
|
- \`cancelled\`: the goal or subgoal is no longer needed.
|
|
24484
24515
|
|
|
24485
24516
|
For human judgment, use the actual HITL payload \`status: "interrupted"\` plus
|
|
@@ -25769,6 +25800,35 @@ Renew HITL approval when a foundational assumption or authority boundary changes
|
|
|
25769
25800
|
|
|
25770
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.
|
|
25771
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
|
+
|
|
25772
25832
|
## Agent Forms and Routing
|
|
25773
25833
|
- **Capability** (\`react\`) for bounded direct work: [[agent-build]]
|
|
25774
25834
|
- **Orchestra** (\`deep_agent\`) for open-ended delegated work: [[agent-build]]
|
|
@@ -25781,8 +25841,11 @@ Renew HITL approval when a foundational assumption or authority boundary changes
|
|
|
25781
25841
|
## Architect Task Policy
|
|
25782
25842
|
The Agent Architect uses persistent TaskItems as its planning surface. Architect must not use
|
|
25783
25843
|
\`write_todos\`. Create a persistent child only for an independently verifiable
|
|
25784
|
-
outcome; tool calls and file reads are actions inside the active Task.
|
|
25785
|
-
|
|
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.
|
|
25786
25849
|
Learning authority is **normal** or **bounded**: normal for fresh work without a
|
|
25787
25850
|
bound round; bounded for learning rounds that bind an existing target and
|
|
25788
25851
|
tracking Task with a confirmed goal. Identity remains fixed; materialization uses
|
|
@@ -26011,6 +26074,9 @@ ${TASK_BELIEF_REFERENCE_EXAMPLE}
|
|
|
26011
26074
|
|
|
26012
26075
|
## Status discipline \u2014 MANDATORY
|
|
26013
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.
|
|
26014
26080
|
- A subtask is \`completed\` ONLY when its work is actually finished.
|
|
26015
26081
|
While fixing eval failures, keep it \`in_progress\` \u2014 never mark
|
|
26016
26082
|
\`completed\` as a workaround (the state machine rejects illegal
|
|
@@ -26255,12 +26321,18 @@ flows the decomposition is presented for user confirmation first.
|
|
|
26255
26321
|
**3. Create each sub-agent.** After [[agent-architecture]] is loaded, per sub-agent:
|
|
26256
26322
|
Call \`create_agent(type: "react", skillLoaded: true, skills: ["[[skill-name]]", ...)\`
|
|
26257
26323
|
where skillLoaded: true is set only after [[agent-architecture]] is loaded.
|
|
26258
|
-
- Each sub-agent gets its OWN eval project
|
|
26324
|
+
- Each sub-agent gets its OWN eval project (eval-{sub-agent-id}); per [[eval-verify]]
|
|
26325
|
+
Setup, first resolve the sub-agent's exact id and check whether its project already
|
|
26326
|
+
exists \u2014 reuse it when it does; only create (and confirm) when it does not. Never
|
|
26327
|
+
create a duplicate project for an agent that already has one.
|
|
26259
26328
|
- Design eval cases per [[eval-design-tests]], run per [[eval-verify]]
|
|
26260
26329
|
- Sub-agent eval passes before you proceed to the next sub-agent
|
|
26261
26330
|
|
|
26262
26331
|
**4. Integration eval.** After ALL sub-agents pass their evals:
|
|
26263
|
-
-
|
|
26332
|
+
- The integration project for the parent (eval-{parent-id}) goes through the same
|
|
26333
|
+
[[eval-verify]] Setup check: confirm the parent's project does not already exist,
|
|
26334
|
+
present the proposed creation to the user, then
|
|
26335
|
+
\`manage_eval create_project(name: "eval-{parent-id}", targetAgentId: "{parent-id}", evalVerifyLoaded: true)\`.
|
|
26264
26336
|
- Integration eval tests the parent's delegation logic, not sub-agent correctness
|
|
26265
26337
|
- [[eval-verify]] owns the run
|
|
26266
26338
|
|
|
@@ -26493,14 +26565,39 @@ its evidence projection, not an independent source of goals or expectations.
|
|
|
26493
26565
|
before calling manage_eval") apply to every manage_eval call in this skill \u2014 not
|
|
26494
26566
|
just during the case design phase. Do not call manage_eval without presenting the
|
|
26495
26567
|
change first.
|
|
26496
|
-
1. **
|
|
26497
|
-
|
|
26498
|
-
|
|
26499
|
-
|
|
26500
|
-
|
|
26568
|
+
1. **Resolve the subject agent FIRST \u2014 one eval project per agent, never per task or per round.**
|
|
26569
|
+
An eval project belongs to exactly one agent-under-test, named \`eval-{agent-id}\`.
|
|
26570
|
+
The agent-id is the eval project's subject. Observability: from an agent's id you
|
|
26571
|
+
can find its eval project by naming convention. Before ANY project creation you MUST:
|
|
26572
|
+
- **Pin the exact subject agent-id.** The subject is the materialized target agent
|
|
26573
|
+
being evaluated: the id returned by \`create_agent\` / \`update_agent\` /
|
|
26574
|
+
\`create_workflow\` / \`update_workflow\`, or the exact bound target ID pinned by
|
|
26575
|
+
the learning kickoff / round task. It is NEVER the Architect session id, the
|
|
26576
|
+
round/task id, a skill name, or any invented label.
|
|
26577
|
+
- **If the exact agent-id is unknown or unconfirmed \u2014 STOP and ask.** Do NOT guess a
|
|
26578
|
+
name, do NOT create a project, and do NOT proceed to case design. Present which
|
|
26579
|
+
agent is under test and confirm with the user (\`ask_user_to_clarify\`) before
|
|
26580
|
+
touching any eval project. An eval project created without a real, confirmed
|
|
26581
|
+
subject is a hard error. If the agent is only planned (not yet materialized),
|
|
26582
|
+
evaluation must wait until materialization returns its id.
|
|
26583
|
+
- **Check existence before creating; reuse is the rule, creation is the exception.**
|
|
26584
|
+
1) \`read_eval list_projects\`
|
|
26585
|
+
2) Find the project whose \`targetAgentId\` equals the subject agent-id; fall back
|
|
26586
|
+
to the name \`eval-{agent-id}\` only when no pointer exists (legacy projects).
|
|
26587
|
+
3) Exists \u2192 reuse its projectId. NEVER create a second project for the same agent \u2014
|
|
26588
|
+
project names are unique per tenant and duplicate projects are forbidden.
|
|
26589
|
+
4) Not exists \u2192 present the proposed project (name \`eval-{agent-id}\` +
|
|
26590
|
+
\`targetAgentId\`) and confirm with the user, THEN
|
|
26591
|
+
\`manage_eval create_project(name: "eval-{agent-id}", targetAgentId: "{agent-id}", evalVerifyLoaded: true, ...)\`.
|
|
26592
|
+
The tool refuses create_project without \`evalVerifyLoaded: true\` \u2014 that flag
|
|
26593
|
+
confirms you are following THIS skill's Setup (resolve \u2192 check \u2192 reuse/confirm).
|
|
26594
|
+
Always pass \`targetAgentId\` so the agent\u2194project link is structural, not name-only.
|
|
26595
|
+
- Re-resolve on every round and every fix pass of the same agent. A new round or task
|
|
26596
|
+
is NOT a reason to create a new project \u2014 reuse the agent's canonical project.
|
|
26501
26597
|
- Orchestrator + subAgents \u2192 one eval project per sub-agent
|
|
26502
26598
|
(eval-{sub-agent-id}) PLUS one integration eval project for the
|
|
26503
|
-
parent (eval-{parent-id}) \u2014 see Layered verification below.
|
|
26599
|
+
parent (eval-{parent-id}) \u2014 see Layered verification below. Every project goes
|
|
26600
|
+
through the same resolve-then-confirm-then-create check above.
|
|
26504
26601
|
2. \`manage_eval create_case(suiteId, ...)\` per sample or scenario
|
|
26505
26602
|
Required: inputMessage, steps=[{agent_id}], outputType, contentAssertion
|
|
26506
26603
|
**contentAssertion MUST come from the confirmed goal, approved expected output,
|
|
@@ -27508,11 +27605,11 @@ function isUndecidedLearningPlaceholder(config) {
|
|
|
27508
27605
|
const metadata = getStringMetadata(config);
|
|
27509
27606
|
return config.type === import_protocols17.AgentType.REACT && metadata.learningPlaceholder === "true" && metadata.architectureStatus === "undecided";
|
|
27510
27607
|
}
|
|
27511
|
-
function
|
|
27512
|
-
if (
|
|
27608
|
+
function requireSkillDeclaration(skillLoaded) {
|
|
27609
|
+
if (skillLoaded !== true) {
|
|
27513
27610
|
return JSON.stringify({
|
|
27514
27611
|
success: false,
|
|
27515
|
-
error: "Load the 'agent-architecture' skill
|
|
27612
|
+
error: "Load the 'agent-architecture' skill via the skill tool (skill_name 'agent-architecture'), then retry this exact call with skillLoaded: true."
|
|
27516
27613
|
});
|
|
27517
27614
|
}
|
|
27518
27615
|
return void 0;
|
|
@@ -27625,7 +27722,7 @@ var middlewareConfigSchema = import_zod47.default.object({
|
|
|
27625
27722
|
config: import_zod47.default.record(import_zod47.default.any()).optional()
|
|
27626
27723
|
});
|
|
27627
27724
|
var createAgentSchema = import_zod47.default.object({
|
|
27628
|
-
skillLoaded: import_zod47.default.
|
|
27725
|
+
skillLoaded: import_zod47.default.boolean().optional().describe("Required on every call: load the 'agent-architecture' skill first via the skill tool (skill_name 'agent-architecture'), then pass skillLoaded: true. Calls without skillLoaded: true fail. Never omit or pass false."),
|
|
27629
27726
|
name: import_zod47.default.string().describe("Human-friendly display name for the agent. The machine ID (used in other tools) is auto-generated as a slug from this name (e.g. 'My Cool Agent' \u2192 'my-cool-agent')."),
|
|
27630
27727
|
description: import_zod47.default.string().optional().describe("Short description"),
|
|
27631
27728
|
type: import_zod47.default.enum(["react", "deep_agent"]).describe("Agent type. Use 'react' for simple single-responsibility agents, 'deep_agent' for complex open-ended agents. For PROCESSING agents (workflow orchestration), use create_processing_agent instead."),
|
|
@@ -27646,9 +27743,9 @@ registerToolLattice(
|
|
|
27646
27743
|
},
|
|
27647
27744
|
async (input, exeConfig) => {
|
|
27648
27745
|
try {
|
|
27649
|
-
const
|
|
27650
|
-
const skillError = requireArchitectSkill(input.skillLoaded, exeConfig);
|
|
27746
|
+
const skillError = requireSkillDeclaration(input.skillLoaded);
|
|
27651
27747
|
if (skillError) return skillError;
|
|
27748
|
+
const tenantId2 = getTenantId2(exeConfig);
|
|
27652
27749
|
const store = getAssistStore();
|
|
27653
27750
|
const taskConfigIssue = validateTaskMiddlewareConfig(input.middleware);
|
|
27654
27751
|
if (taskConfigIssue) return JSON.stringify(taskConfigIssue);
|
|
@@ -27683,7 +27780,7 @@ registerToolLattice(
|
|
|
27683
27780
|
var createWorkflowSchema = import_zod47.default.object({
|
|
27684
27781
|
name: import_zod47.default.string().describe("Display name for the workflow agent"),
|
|
27685
27782
|
description: import_zod47.default.string().optional().describe("Short description"),
|
|
27686
|
-
skillLoaded: import_zod47.default.
|
|
27783
|
+
skillLoaded: import_zod47.default.boolean().optional().describe("Required on every call: load the 'agent-architecture' skill first via the skill tool (skill_name 'agent-architecture'), then pass skillLoaded: true. Calls without skillLoaded: true fail. Never omit or pass false."),
|
|
27687
27784
|
yaml: import_zod47.default.string().describe("The YAML workflow definition in linear DSL format (steps execute top-to-bottom, use parallel: for concurrency)"),
|
|
27688
27785
|
tools: import_zod47.default.array(import_zod47.default.string()).optional().describe("Tool keys for the workflow agent"),
|
|
27689
27786
|
middleware: import_zod47.default.array(middlewareConfigSchema).optional().describe("Middleware configs"),
|
|
@@ -27698,6 +27795,8 @@ registerToolLattice(
|
|
|
27698
27795
|
},
|
|
27699
27796
|
async (input, exeConfig) => {
|
|
27700
27797
|
try {
|
|
27798
|
+
const skillError = requireSkillDeclaration(input.skillLoaded);
|
|
27799
|
+
if (skillError) return skillError;
|
|
27701
27800
|
const tenantId2 = getTenantId2(exeConfig);
|
|
27702
27801
|
const store = getAssistStore();
|
|
27703
27802
|
const taskConfigIssue = validateTaskMiddlewareConfig(input.middleware);
|
|
@@ -27838,7 +27937,7 @@ registerToolLattice(
|
|
|
27838
27937
|
);
|
|
27839
27938
|
var updateWorkflowSchema = import_zod47.default.object({
|
|
27840
27939
|
id: import_zod47.default.string().describe("The workflow agent ID to update"),
|
|
27841
|
-
skillLoaded: import_zod47.default.
|
|
27940
|
+
skillLoaded: import_zod47.default.boolean().optional().describe("Required on every call: load the 'agent-architecture' skill first via the skill tool (skill_name 'agent-architecture'), then pass skillLoaded: true. Calls without skillLoaded: true fail. Never omit or pass false."),
|
|
27842
27941
|
name: import_zod47.default.string().optional().describe("New display name"),
|
|
27843
27942
|
description: import_zod47.default.string().optional().describe("New description"),
|
|
27844
27943
|
yaml: import_zod47.default.string().optional().describe("Replacement YAML workflow DSL. Omit to keep existing."),
|
|
@@ -27850,13 +27949,13 @@ registerToolLattice(
|
|
|
27850
27949
|
"update_workflow",
|
|
27851
27950
|
{
|
|
27852
27951
|
name: "update_workflow",
|
|
27853
|
-
description: "Update an existing workflow agent or materialize an eligible marked learning placeholder.
|
|
27952
|
+
description: "Update an existing workflow agent or materialize an eligible marked learning placeholder. Pass skillLoaded: true on every call after loading agent-architecture (skill tool, skill_name 'agent-architecture'); calls without it fail. Placeholder eligibility is not proof that the user approved the architecture; approval remains a prompt/HITL contract.",
|
|
27854
27953
|
schema: updateWorkflowSchema
|
|
27855
27954
|
},
|
|
27856
27955
|
async (input, exeConfig) => {
|
|
27857
27956
|
console.log(`[update_workflow] CALLED id=${input.id} hasYaml=${input.yaml !== void 0}`);
|
|
27858
27957
|
try {
|
|
27859
|
-
const skillError =
|
|
27958
|
+
const skillError = requireSkillDeclaration(input.skillLoaded);
|
|
27860
27959
|
if (skillError) return skillError;
|
|
27861
27960
|
const tenantId2 = getTenantId2(exeConfig);
|
|
27862
27961
|
const store = getAssistStore();
|
|
@@ -27934,7 +28033,7 @@ registerToolLattice(
|
|
|
27934
28033
|
description: input.description !== void 0 ? input.description : existing.description,
|
|
27935
28034
|
graphDefinition: mergedConfig
|
|
27936
28035
|
});
|
|
27937
|
-
if (
|
|
28036
|
+
if (updated === null) {
|
|
27938
28037
|
return JSON.stringify({
|
|
27939
28038
|
success: false,
|
|
27940
28039
|
code: "ASSISTANT_UPDATE_FAILED",
|
|
@@ -27952,7 +28051,7 @@ registerToolLattice(
|
|
|
27952
28051
|
);
|
|
27953
28052
|
var updateAgentSchema = import_zod47.default.object({
|
|
27954
28053
|
id: import_zod47.default.string().describe("The agent ID to update"),
|
|
27955
|
-
skillLoaded: import_zod47.default.
|
|
28054
|
+
skillLoaded: import_zod47.default.boolean().optional().describe("Required on every call: load the 'agent-architecture' skill first via the skill tool (skill_name 'agent-architecture'), then pass skillLoaded: true. Calls without skillLoaded: true fail. Never omit or pass false."),
|
|
27956
28055
|
config: import_zod47.default.object({
|
|
27957
28056
|
name: import_zod47.default.string().optional().describe("New display name for the agent"),
|
|
27958
28057
|
description: import_zod47.default.string().optional().describe("New short description"),
|
|
@@ -27970,14 +28069,14 @@ registerToolLattice(
|
|
|
27970
28069
|
"update_agent",
|
|
27971
28070
|
{
|
|
27972
28071
|
name: "update_agent",
|
|
27973
|
-
description: "Update an existing agent's configuration. Provide the agent ID and the fields to change. Returns the updated agent's ID and name. NOTE: For user approval/confirmation scenarios, add middleware with type: 'ask_user_to_clarify'. IMPORTANT: do NOT set 'modelKey' unless the user explicitly specified a model \u2014 leaving it unset makes the runtime use the 'default' model.",
|
|
28072
|
+
description: "Update an existing agent's configuration. Provide the agent ID and the fields to change. Returns the updated agent's ID and name. Pass skillLoaded: true on every call after loading agent-architecture (skill tool, skill_name 'agent-architecture'); calls without it fail. NOTE: For user approval/confirmation scenarios, add middleware with type: 'ask_user_to_clarify'. IMPORTANT: do NOT set 'modelKey' unless the user explicitly specified a model \u2014 leaving it unset makes the runtime use the 'default' model.",
|
|
27974
28073
|
schema: updateAgentSchema
|
|
27975
28074
|
},
|
|
27976
28075
|
async (input, exeConfig) => {
|
|
27977
28076
|
try {
|
|
27978
|
-
const
|
|
27979
|
-
const skillError = requireArchitectSkill(input.skillLoaded, exeConfig);
|
|
28077
|
+
const skillError = requireSkillDeclaration(input.skillLoaded);
|
|
27980
28078
|
if (skillError) return skillError;
|
|
28079
|
+
const tenantId2 = getTenantId2(exeConfig);
|
|
27981
28080
|
const store = getAssistStore();
|
|
27982
28081
|
const existing = await store.getAssistantById(tenantId2, input.id);
|
|
27983
28082
|
if (!existing) {
|
|
@@ -28017,7 +28116,7 @@ registerToolLattice(
|
|
|
28017
28116
|
description: input.config.description !== void 0 ? input.config.description : existing.description,
|
|
28018
28117
|
graphDefinition: mergedConfig
|
|
28019
28118
|
});
|
|
28020
|
-
if (
|
|
28119
|
+
if (updated === null) {
|
|
28021
28120
|
return JSON.stringify({
|
|
28022
28121
|
success: false,
|
|
28023
28122
|
code: "ASSISTANT_UPDATE_FAILED",
|
|
@@ -28246,8 +28345,11 @@ var AGENT_ARCHITECT_PROMPT = `You are the Agent Architect.
|
|
|
28246
28345
|
|
|
28247
28346
|
CRITICAL FIRST ACTION: Before any response or other action, call the \`skill\`
|
|
28248
28347
|
tool with skill_name: "agent-architecture" to load agent-architecture and follow it.
|
|
28249
|
-
|
|
28250
|
-
|
|
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.`;
|
|
28251
28353
|
|
|
28252
28354
|
// src/agent_lattice/agentReviewerConfig.ts
|
|
28253
28355
|
var import_protocols18 = require("@axiom-lattice/protocols");
|
|
@@ -30239,6 +30341,25 @@ var mcpManager = McpLatticeManager.getInstance();
|
|
|
30239
30341
|
// src/sandbox_lattice/MicrosandboxRemoteInstance.ts
|
|
30240
30342
|
var posix3 = __toESM(require("path/posix"));
|
|
30241
30343
|
|
|
30344
|
+
// src/sandbox_lattice/grepUtils.ts
|
|
30345
|
+
function buildRecursiveGrepCommand(pattern, path8) {
|
|
30346
|
+
return `grep -r -n -I -E -e ${quotePosixShellArg(pattern)} ${quotePosixShellArg(path8)}`;
|
|
30347
|
+
}
|
|
30348
|
+
function parseRecursiveGrepOutput(output) {
|
|
30349
|
+
const matches = [];
|
|
30350
|
+
for (const line of output.split("\n")) {
|
|
30351
|
+
if (!line) continue;
|
|
30352
|
+
const match = /^(.*):(\d+):(.*)$/.exec(line);
|
|
30353
|
+
if (!match) continue;
|
|
30354
|
+
matches.push({
|
|
30355
|
+
path: match[1],
|
|
30356
|
+
line: Number.parseInt(match[2], 10),
|
|
30357
|
+
text: match[3]
|
|
30358
|
+
});
|
|
30359
|
+
}
|
|
30360
|
+
return matches;
|
|
30361
|
+
}
|
|
30362
|
+
|
|
30242
30363
|
// src/sandbox_lattice/packDirectory.ts
|
|
30243
30364
|
var import_node_crypto4 = require("crypto");
|
|
30244
30365
|
var posix2 = __toESM(require("path/posix"));
|
|
@@ -30374,6 +30495,15 @@ var MicrosandboxRemoteInstance = class {
|
|
|
30374
30495
|
line_numbers: result.matches.map((match) => match.line)
|
|
30375
30496
|
};
|
|
30376
30497
|
},
|
|
30498
|
+
grepRecursive: async (pattern, searchPath) => {
|
|
30499
|
+
const result = await this.shell.execCommand({
|
|
30500
|
+
command: buildRecursiveGrepCommand(
|
|
30501
|
+
pattern,
|
|
30502
|
+
normalizeExternalSandboxPath(searchPath)
|
|
30503
|
+
)
|
|
30504
|
+
});
|
|
30505
|
+
return { matches: parseRecursiveGrepOutput(result.output) };
|
|
30506
|
+
},
|
|
30377
30507
|
strReplaceEditor: async (params) => {
|
|
30378
30508
|
await this.client.replaceInFile(this.name, {
|
|
30379
30509
|
path: normalizeExternalSandboxPath(params.path),
|
|
@@ -30906,6 +31036,13 @@ var RemoteSandboxInstance = class {
|
|
|
30906
31036
|
line_numbers: result.body.data?.line_numbers || []
|
|
30907
31037
|
};
|
|
30908
31038
|
},
|
|
31039
|
+
grepRecursive: async (pattern, searchPath) => {
|
|
31040
|
+
const resolved = this.resolvePath(searchPath);
|
|
31041
|
+
const result = await this.shell.execCommand({
|
|
31042
|
+
command: buildRecursiveGrepCommand(pattern, resolved)
|
|
31043
|
+
});
|
|
31044
|
+
return { matches: parseRecursiveGrepOutput(result.output) };
|
|
31045
|
+
},
|
|
30909
31046
|
strReplaceEditor: async (params) => {
|
|
30910
31047
|
const resolved = this.resolvePath(params.path);
|
|
30911
31048
|
const result = await this.client.file.strReplaceEditor({
|
|
@@ -31209,7 +31346,8 @@ var RemoteSandboxProvider = class {
|
|
|
31209
31346
|
kind: f.is_dir === true || f.size === null ? "directory" : "file",
|
|
31210
31347
|
size: f.size ?? 0,
|
|
31211
31348
|
mode: 0,
|
|
31212
|
-
modified: f.modified_at ?? null
|
|
31349
|
+
modified: f.modified_at ?? null,
|
|
31350
|
+
created: f.created_at ?? null
|
|
31213
31351
|
}));
|
|
31214
31352
|
return entries;
|
|
31215
31353
|
},
|
|
@@ -31285,6 +31423,12 @@ var E2BInstance = class {
|
|
|
31285
31423
|
}
|
|
31286
31424
|
return { matches, line_numbers };
|
|
31287
31425
|
},
|
|
31426
|
+
grepRecursive: async (pattern, searchPath) => {
|
|
31427
|
+
const result = await this.native.commands.run(
|
|
31428
|
+
buildRecursiveGrepCommand(pattern, searchPath)
|
|
31429
|
+
);
|
|
31430
|
+
return { matches: parseRecursiveGrepOutput(result.stdout) };
|
|
31431
|
+
},
|
|
31288
31432
|
strReplaceEditor: async (params) => {
|
|
31289
31433
|
const { path: path8, old_str, new_str, replace_mode } = params;
|
|
31290
31434
|
const delim = "#";
|
|
@@ -31483,6 +31627,21 @@ var DaytonaInstance = class {
|
|
|
31483
31627
|
}
|
|
31484
31628
|
return { matches: matchTexts, line_numbers };
|
|
31485
31629
|
},
|
|
31630
|
+
grepRecursive: async (pattern, searchPath) => {
|
|
31631
|
+
const matches = await this.native.fs.findFiles(
|
|
31632
|
+
toRelativePath(searchPath),
|
|
31633
|
+
pattern
|
|
31634
|
+
);
|
|
31635
|
+
const results = [];
|
|
31636
|
+
for (const match of matches) {
|
|
31637
|
+
results.push({
|
|
31638
|
+
path: normalizeExternalSandboxPath(match.file ?? ""),
|
|
31639
|
+
line: match.line ?? 0,
|
|
31640
|
+
text: match.content ?? ""
|
|
31641
|
+
});
|
|
31642
|
+
}
|
|
31643
|
+
return { matches: results };
|
|
31644
|
+
},
|
|
31486
31645
|
strReplaceEditor: async (params) => {
|
|
31487
31646
|
const { path: path8, old_str, new_str, replace_mode } = params;
|
|
31488
31647
|
const relPath = toRelativePath(path8);
|
|
@@ -31865,6 +32024,37 @@ var LocalSandboxInstance = class {
|
|
|
31865
32024
|
}
|
|
31866
32025
|
return { matches, line_numbers };
|
|
31867
32026
|
},
|
|
32027
|
+
grepRecursive: async (pattern, searchPath) => {
|
|
32028
|
+
const hp = this.hostPath(searchPath);
|
|
32029
|
+
let regex;
|
|
32030
|
+
try {
|
|
32031
|
+
regex = new RegExp(pattern);
|
|
32032
|
+
} catch {
|
|
32033
|
+
return { matches: [] };
|
|
32034
|
+
}
|
|
32035
|
+
const hostFiles = [];
|
|
32036
|
+
await this.walkDirFilter(hp, /.+/, hostFiles);
|
|
32037
|
+
const hpNorm = hp.endsWith(path5.sep) ? hp : hp + path5.sep;
|
|
32038
|
+
const toSandboxPath = (hostFilePath) => posix5.join(searchPath, hostFilePath.slice(hpNorm.length).split(path5.sep).join("/"));
|
|
32039
|
+
const matches = [];
|
|
32040
|
+
for (const hostFile of hostFiles) {
|
|
32041
|
+
const content = await fs3.readFile(hostFile, "utf-8").catch(() => null);
|
|
32042
|
+
if (content === null || content.includes("\0")) {
|
|
32043
|
+
continue;
|
|
32044
|
+
}
|
|
32045
|
+
const lines = content.split("\n");
|
|
32046
|
+
for (let i = 0; i < lines.length; i++) {
|
|
32047
|
+
if (regex.test(lines[i])) {
|
|
32048
|
+
matches.push({
|
|
32049
|
+
path: toSandboxPath(hostFile),
|
|
32050
|
+
line: i + 1,
|
|
32051
|
+
text: lines[i]
|
|
32052
|
+
});
|
|
32053
|
+
}
|
|
32054
|
+
}
|
|
32055
|
+
}
|
|
32056
|
+
return { matches };
|
|
32057
|
+
},
|
|
31868
32058
|
strReplaceEditor: async (params) => {
|
|
31869
32059
|
const content = await fs3.readFile(this.hostPath(params.path), "utf-8");
|
|
31870
32060
|
let result;
|
|
@@ -32904,8 +33094,12 @@ Note: if final_score >= 80 and there are no fatal errors, pass should be true; o
|
|
|
32904
33094
|
});
|
|
32905
33095
|
}
|
|
32906
33096
|
} else if (parsedResult.pass !== void 0) {
|
|
32907
|
-
pass =
|
|
32908
|
-
|
|
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
|
+
});
|
|
32909
33103
|
} else if (parsedResult.final_score !== void 0) {
|
|
32910
33104
|
pass = parsedResult.final_score >= 80;
|
|
32911
33105
|
this.log("Pass determined from parsedResult.final_score", {
|
|
@@ -34653,7 +34847,11 @@ var TaskLifecycleService = class {
|
|
|
34653
34847
|
...event2.warning ? { warnings: [event2.warning] } : {}
|
|
34654
34848
|
};
|
|
34655
34849
|
}
|
|
34656
|
-
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
|
+
);
|
|
34657
34855
|
if (interruption && typeof interruption === "object" && interruption.type === "review_required") {
|
|
34658
34856
|
return failure2("REVIEW_APPROVAL_REQUIRED", "Review interruption requires explicit approval or rejection.");
|
|
34659
34857
|
}
|
|
@@ -34750,7 +34948,11 @@ var TaskLifecycleService = class {
|
|
|
34750
34948
|
task.updatedAt
|
|
34751
34949
|
);
|
|
34752
34950
|
} catch {
|
|
34753
|
-
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 };
|
|
34754
34956
|
}
|
|
34755
34957
|
if (!updated) {
|
|
34756
34958
|
let current;
|
|
@@ -34778,7 +34980,11 @@ var TaskLifecycleService = class {
|
|
|
34778
34980
|
...repaired.warning ? { warnings: [repaired.warning] } : {}
|
|
34779
34981
|
};
|
|
34780
34982
|
}
|
|
34781
|
-
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 };
|
|
34782
34988
|
}
|
|
34783
34989
|
const event = await this.writeStatusEvent(
|
|
34784
34990
|
updated,
|
|
@@ -34922,10 +35128,18 @@ var TaskLifecycleService = class {
|
|
|
34922
35128
|
const storedExternal = parseExternalDependency(currentInterruption);
|
|
34923
35129
|
if (input.type === "external_dependency") {
|
|
34924
35130
|
if (!external || !storedExternal || storedExternal.summary !== external.summary || canonicalJson(storedExternal.dependencyTaskIds) !== canonicalJson(external.dependencyTaskIds)) {
|
|
34925
|
-
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
|
+
);
|
|
34926
35136
|
}
|
|
34927
35137
|
} else if (currentInterruption.type !== input.type || currentInterruption.summary !== summary) {
|
|
34928
|
-
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
|
+
);
|
|
34929
35143
|
}
|
|
34930
35144
|
const detail = storedExternal ? { ...storedExternal } : currentInterruption;
|
|
34931
35145
|
const eventKey2 = this.statusEventKey(task, "interrupted", detail);
|
|
@@ -34942,7 +35156,11 @@ var TaskLifecycleService = class {
|
|
|
34942
35156
|
...warnings2.length ? { warnings: warnings2 } : {}
|
|
34943
35157
|
};
|
|
34944
35158
|
}
|
|
34945
|
-
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
|
+
);
|
|
34946
35164
|
if (external && isProjectLifecycleTask(task)) {
|
|
34947
35165
|
const dependencyFailure = await this.validateExternalDependencies(task, external.dependencyTaskIds);
|
|
34948
35166
|
if (dependencyFailure) return dependencyFailure;
|
|
@@ -34955,9 +35173,17 @@ var TaskLifecycleService = class {
|
|
|
34955
35173
|
context: mergeInterruptionContext(task.context, interruption, input.threadId)
|
|
34956
35174
|
}, ["in_progress"], task.updatedAt);
|
|
34957
35175
|
} catch {
|
|
34958
|
-
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
|
+
);
|
|
34959
35181
|
}
|
|
34960
|
-
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
|
+
);
|
|
34961
35187
|
const eventKey = this.statusEventKey(updated, "interrupted", interruption);
|
|
34962
35188
|
const event = await this.writeStatusEvent(updated, input.actor, input.threadId, "interrupted", summary, interruption, eventKey);
|
|
34963
35189
|
const warnings = event.warning ? [event.warning] : await this.notifyWinningTransition(updated, "interrupted", event);
|
|
@@ -34995,7 +35221,11 @@ var TaskLifecycleService = class {
|
|
|
34995
35221
|
context: withCompletionAudit(prepared.task.context, prepared.evidence.id, prepared.eventKey)
|
|
34996
35222
|
}, ["in_progress"]);
|
|
34997
35223
|
} catch {
|
|
34998
|
-
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
|
+
);
|
|
34999
35229
|
}
|
|
35000
35230
|
if (!updated) {
|
|
35001
35231
|
if (await this.hasStaleAgentParent(prepared)) {
|
|
@@ -35558,7 +35788,11 @@ var TaskLifecycleService = class {
|
|
|
35558
35788
|
} catch {
|
|
35559
35789
|
return failure2("TASK_STORE_WRITE_FAILED", "Failed to reconcile task description.");
|
|
35560
35790
|
}
|
|
35561
|
-
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
|
+
);
|
|
35562
35796
|
if (changedKeys.length === 0) {
|
|
35563
35797
|
return {
|
|
35564
35798
|
success: true,
|
|
@@ -38342,7 +38576,7 @@ var import_zod54 = __toESM(require("zod"));
|
|
|
38342
38576
|
var import_langchain67 = require("langchain");
|
|
38343
38577
|
var DESCRIPTION3 = `RUNTIME QUERY SURFACE \u2014 read what is published and answer business questions with numbers. Business agents use ONLY this tool; Builder agents also use it to verify freshly published metrics.
|
|
38344
38578
|
|
|
38345
|
-
OWNS: read_semantic_catalog (the published semantic model for a datasource: tables, metrics, dimensions, filters) and query_metrics (the semantic metric query: metrics / groupBy / filters / orderBy / limit \u2014 the server generates the SQL, so there is no free-form SQL here).
|
|
38579
|
+
OWNS: list_datasources (self-contained datasource discovery \u2014 redacted output, the first step before anything else), read_semantic_catalog (the published semantic model for a datasource: tables, metrics, dimensions, filters) and query_metrics (the semantic metric query: metrics / groupBy / filters / orderBy / limit \u2014 the server generates the SQL, so there is no free-form SQL here).
|
|
38346
38580
|
|
|
38347
38581
|
DOES NOT OWN:
|
|
38348
38582
|
- Publishing or correcting semantic tables/metrics \u2192 metrics_meta_tool (create_table/update_table/create_metric/update_metric/list_tables/read_table_meta/list_metrics/read_metric_meta).
|
|
@@ -38363,6 +38597,18 @@ function createMetricsRuntimeTool(params) {
|
|
|
38363
38597
|
const client = await resolveClientFromConnections(input.connectionKey, resolvedConnections, readToolRunConfig(exeConfig));
|
|
38364
38598
|
const selected = effectiveDatasourceScope(client.getSelectedDataSources(), selectedDataSources);
|
|
38365
38599
|
switch (input.action) {
|
|
38600
|
+
case "list_datasources": {
|
|
38601
|
+
const result = await client.listDatasources();
|
|
38602
|
+
const filtered = selected.length > 0 ? result.filter((d) => selected.includes(Number(d.id))) : result;
|
|
38603
|
+
const safe = filtered.map((d) => ({
|
|
38604
|
+
id: d.id,
|
|
38605
|
+
name: d.name,
|
|
38606
|
+
sourceType: d.sourceType,
|
|
38607
|
+
description: d.description,
|
|
38608
|
+
statusLabel: d.statusLabel
|
|
38609
|
+
}));
|
|
38610
|
+
return JSON.stringify(safe, null, 2);
|
|
38611
|
+
}
|
|
38366
38612
|
case "read_semantic_catalog": {
|
|
38367
38613
|
const ds = resolveDatasourceId(input, exeConfig);
|
|
38368
38614
|
assertDatasourceSelected(selected, ds);
|
|
@@ -38385,11 +38631,11 @@ function createMetricsRuntimeTool(params) {
|
|
|
38385
38631
|
name: "metrics_runtime_tool",
|
|
38386
38632
|
description: DESCRIPTION3,
|
|
38387
38633
|
schema: import_zod54.default.object({
|
|
38388
|
-
action: import_zod54.default.enum(["read_semantic_catalog", "query_metrics"]).describe(
|
|
38389
|
-
"Actions ONLY in this runtime tool: read_semantic_catalog (read the published semantic model: tables, metrics, dimensions
|
|
38634
|
+
action: import_zod54.default.enum(["list_datasources", "read_semantic_catalog", "query_metrics"]).describe(
|
|
38635
|
+
"Actions ONLY in this runtime tool: list_datasources (list available datasources \u2014 ALWAYS call this first to obtain the datasourceId; output is redacted to non-sensitive fields), read_semantic_catalog (read the published semantic model: tables, metrics, dimensions), query_metrics (run a semantic metric query \u2014 the only way to get business numbers). Do NOT put meta-tool actions (list_tables/read_table_meta/create_table/update_table/list_metrics/read_metric_meta/create_metric/update_metric) here"
|
|
38390
38636
|
),
|
|
38391
38637
|
connectionKey: import_zod54.default.string().optional().describe("Connection key. Omit when only one semantic-metrics connection exists"),
|
|
38392
|
-
datasourceId: import_zod54.default.coerce.number().optional().describe("Numeric datasource id, e.g. 15 (optional if set in runConfig.metricsDataSource)"),
|
|
38638
|
+
datasourceId: import_zod54.default.coerce.number().optional().describe("Numeric datasource id, e.g. 15 (required for read_semantic_catalog; optional if set in runConfig.metricsDataSource)"),
|
|
38393
38639
|
query: import_zod54.default.record(import_zod54.default.unknown()).optional().describe('Semantic metric query request. Required for the query_metrics action, e.g. { datasourceId: 15, metrics: ["sell_in_nes"], groupBy: ["sales_team"], filters: [{ dimension: "posting_year", operator: "GTE", values: [2024] }], limit: 10 }')
|
|
38394
38640
|
})
|
|
38395
38641
|
}
|
|
@@ -38854,7 +39100,7 @@ var semanticMetricsPlugin = {
|
|
|
38854
39100
|
configSchema: {
|
|
38855
39101
|
type: "object",
|
|
38856
39102
|
title: "Semantic Metrics Configuration",
|
|
38857
|
-
description: "First select connections (connections or connectAll). Then scope tools by role via allowedTools: QUERY-ONLY agents (metric definitions + data) set allowedTools to ['metrics_runtime_tool'] \u2014
|
|
39103
|
+
description: "First select connections (connections or connectAll). Then scope tools by role via allowedTools: QUERY-ONLY agents (metric definitions + data) set allowedTools to ['metrics_runtime_tool'] \u2014 it is self-contained (list_datasources, read_semantic_catalog, query_metrics); metric DESIGNERS keep all three tools (datasource exploration, meta publishing, runtime verification).",
|
|
38858
39104
|
properties: {
|
|
38859
39105
|
connections: {
|
|
38860
39106
|
type: "array",
|
|
@@ -40840,6 +41086,16 @@ function getRunConfig2(config) {
|
|
|
40840
41086
|
const c = config;
|
|
40841
41087
|
return c?.configurable?.runConfig ?? {};
|
|
40842
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
|
+
}
|
|
40843
41099
|
function getRuntimeActor2(runConfig) {
|
|
40844
41100
|
if (runConfig.assistant_id) return `agent:${String(runConfig.assistant_id)}`;
|
|
40845
41101
|
if (runConfig.user_id) return `user:${String(runConfig.user_id)}`;
|
|
@@ -41066,6 +41322,7 @@ async function validateEffectiveDependencies(store, tenantId2, targetScope, depe
|
|
|
41066
41322
|
if (blockedBy.length === 0) return void 0;
|
|
41067
41323
|
return JSON.stringify({
|
|
41068
41324
|
success: false,
|
|
41325
|
+
code: "DEPENDENCY_BLOCKED",
|
|
41069
41326
|
error: `Cannot start task: ${blockedBy.length} dependencies not completed`,
|
|
41070
41327
|
blockedBy,
|
|
41071
41328
|
invalidScope,
|
|
@@ -41216,13 +41473,27 @@ function missingBeliefImpactError() {
|
|
|
41216
41473
|
hint: "Provide beliefImpact: [{ key: '<belief-key>', after: <0-100>, basis: '<evidence>' }]"
|
|
41217
41474
|
});
|
|
41218
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
|
+
}
|
|
41219
41490
|
var manageTaskSchema = import_zod68.z.object({
|
|
41220
|
-
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."),
|
|
41221
41492
|
id: import_zod68.z.string().optional().describe("Task ID (required for get, update, add_activity, and delete)"),
|
|
41222
41493
|
title: import_zod68.z.string().optional().describe("Task title (required for create)"),
|
|
41223
41494
|
description: import_zod68.z.string().optional().describe("Task description in Markdown"),
|
|
41224
41495
|
priority: import_zod68.z.enum(["low", "medium", "high"]).optional().describe("Priority level"),
|
|
41225
|
-
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"),
|
|
41226
41497
|
dueDate: import_zod68.z.string().optional().describe("Due date (ISO 8601 format)"),
|
|
41227
41498
|
metadata: import_zod68.z.record(import_zod68.z.unknown()).optional().describe("Structured metadata (e.g. projectId, module)"),
|
|
41228
41499
|
parentId: import_zod68.z.string().optional().describe("Parent task ID for grouping subtasks"),
|
|
@@ -41233,8 +41504,8 @@ var manageTaskSchema = import_zod68.z.object({
|
|
|
41233
41504
|
requireReview: import_zod68.z.boolean().optional().describe("If true, agent completion pauses as interrupted(review_required) for HITL approval"),
|
|
41234
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"),
|
|
41235
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"),
|
|
41236
|
-
result: import_zod68.z.string().optional().describe("
|
|
41237
|
-
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'"),
|
|
41238
41509
|
files: import_zod68.z.array(import_zod68.z.object({
|
|
41239
41510
|
uri: import_zod68.z.string().describe("Uniquely locates the resource: http(s):// URL, /s/:token share, or sandbox path"),
|
|
41240
41511
|
name: import_zod68.z.string().optional().describe("Display name"),
|
|
@@ -41253,11 +41524,11 @@ var manageTaskSchema = import_zod68.z.object({
|
|
|
41253
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"
|
|
41254
41525
|
)
|
|
41255
41526
|
}).superRefine((input, context) => {
|
|
41256
|
-
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") {
|
|
41257
41528
|
context.addIssue({
|
|
41258
41529
|
code: import_zod68.z.ZodIssueCode.custom,
|
|
41259
41530
|
path: ["executionResultId"],
|
|
41260
|
-
message: "executionResultId is valid only for update or add_activity"
|
|
41531
|
+
message: "executionResultId is valid only for update, set_status, or add_activity"
|
|
41261
41532
|
});
|
|
41262
41533
|
}
|
|
41263
41534
|
});
|
|
@@ -41371,12 +41642,6 @@ function updateValuesEqual(field, requested, persisted) {
|
|
|
41371
41642
|
}
|
|
41372
41643
|
return valuesEqual(requested, persisted);
|
|
41373
41644
|
}
|
|
41374
|
-
function reviewInterruption(task) {
|
|
41375
|
-
const value = task.context?.interruption;
|
|
41376
|
-
if (!value || typeof value !== "object") return void 0;
|
|
41377
|
-
const interruption = value;
|
|
41378
|
-
return interruption.type === "review_required" ? interruption : void 0;
|
|
41379
|
-
}
|
|
41380
41645
|
function reviewModeDisabledResponse() {
|
|
41381
41646
|
return JSON.stringify({
|
|
41382
41647
|
success: false,
|
|
@@ -41385,14 +41650,6 @@ function reviewModeDisabledResponse() {
|
|
|
41385
41650
|
hint: "Configure task middleware with reviewMode 'hitl' before enabling requireReview."
|
|
41386
41651
|
});
|
|
41387
41652
|
}
|
|
41388
|
-
function buildReviewMarkdown(task) {
|
|
41389
|
-
return genUIMarkdown("task_review", {
|
|
41390
|
-
taskId: task.id,
|
|
41391
|
-
title: task.title,
|
|
41392
|
-
description: task.description,
|
|
41393
|
-
result: task.result
|
|
41394
|
-
});
|
|
41395
|
-
}
|
|
41396
41653
|
function createTaskMiddleware(options = {}) {
|
|
41397
41654
|
const handleManageTaskAction = async (input, config, validateExecutionResult, markMutation) => {
|
|
41398
41655
|
const rc = getRunConfig2(config);
|
|
@@ -41780,35 +42037,75 @@ function createTaskMiddleware(options = {}) {
|
|
|
41780
42037
|
return JSON.stringify({ success: true, data: activity });
|
|
41781
42038
|
}
|
|
41782
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
|
+
});
|
|
41783
42052
|
if (!input.id) {
|
|
42053
|
+
taskUpdateBlocked(input.id, "MISSING_TASK_ID", {});
|
|
41784
42054
|
return JSON.stringify({
|
|
41785
42055
|
success: false,
|
|
42056
|
+
code: "MISSING_TASK_ID",
|
|
41786
42057
|
error: "id is required for update action",
|
|
41787
42058
|
hint: "Pass the task ID you want to update"
|
|
41788
42059
|
});
|
|
41789
42060
|
}
|
|
41790
42061
|
if (delegatedTaskId && input.id !== delegatedTaskId) {
|
|
42062
|
+
taskUpdateBlocked(input.id, "DELEGATED_TASK_SCOPE_VIOLATION", { delegatedTaskId });
|
|
41791
42063
|
return delegatedTaskScopeError(delegatedTaskId);
|
|
41792
42064
|
}
|
|
41793
|
-
|
|
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 });
|
|
41794
42074
|
if (!existing) {
|
|
42075
|
+
taskUpdateBlocked(input.id, "TASK_NOT_FOUND", {});
|
|
41795
42076
|
return JSON.stringify({
|
|
41796
42077
|
success: false,
|
|
41797
|
-
|
|
41798
|
-
|
|
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."
|
|
41799
42081
|
});
|
|
41800
42082
|
}
|
|
41801
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
|
+
});
|
|
41802
42090
|
return taskScopeAccessError(input.id);
|
|
41803
42091
|
}
|
|
41804
42092
|
if (trustedProject?.projectTask) {
|
|
41805
42093
|
const trustedFailure = trustedTaskContextFailure(existing, trustedProject.projectTask);
|
|
41806
|
-
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
|
+
}
|
|
41807
42103
|
}
|
|
41808
42104
|
if (trustedProject && input.dependencyTaskIds !== void 0) {
|
|
41809
42105
|
const interruption = input.context?.interruption;
|
|
41810
42106
|
const interruptionType2 = interruption && typeof interruption === "object" ? interruption.type : void 0;
|
|
41811
42107
|
if (input.status !== "interrupted" || interruptionType2 !== "external_dependency") {
|
|
42108
|
+
taskUpdateBlocked(input.id, "INVALID_EXTERNAL_DEPENDENCY", {});
|
|
41812
42109
|
return JSON.stringify({
|
|
41813
42110
|
success: false,
|
|
41814
42111
|
code: "INVALID_EXTERNAL_DEPENDENCY",
|
|
@@ -41817,24 +42114,26 @@ function createTaskMiddleware(options = {}) {
|
|
|
41817
42114
|
}
|
|
41818
42115
|
}
|
|
41819
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
|
+
});
|
|
41820
42123
|
return JSON.stringify({
|
|
41821
42124
|
success: false,
|
|
41822
42125
|
code: "TASK_REASSIGN_ENDPOINT_REQUIRED",
|
|
41823
42126
|
error: "Project task ownership changes require the reassignment endpoint."
|
|
41824
42127
|
});
|
|
41825
42128
|
}
|
|
41826
|
-
if (existing.status === "review" || input.status === "review") {
|
|
41827
|
-
return JSON.stringify({
|
|
41828
|
-
success: false,
|
|
41829
|
-
code: "TASK_STATUS_UNSUPPORTED",
|
|
41830
|
-
error: "Task status is not supported by the task lifecycle."
|
|
41831
|
-
});
|
|
41832
|
-
}
|
|
41833
42129
|
const isAgentTask = existing.ownerType === "agent";
|
|
41834
|
-
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;
|
|
41835
42130
|
const changesOwnerType = input.ownerType !== void 0 && input.ownerType !== existing.ownerType;
|
|
41836
42131
|
const changesAgentIdentity = isAgentTask && (input.ownerId !== void 0 && input.ownerId !== existing.ownerId || input.parentId !== void 0 && input.parentId !== existing.parentId);
|
|
41837
42132
|
if (changesOwnerType || changesAgentIdentity) {
|
|
42133
|
+
taskUpdateBlocked(input.id, "TASK_OWNERSHIP_IMMUTABLE", {
|
|
42134
|
+
changesOwnerType,
|
|
42135
|
+
changesAgentIdentity
|
|
42136
|
+
});
|
|
41838
42137
|
return JSON.stringify({
|
|
41839
42138
|
success: false,
|
|
41840
42139
|
code: "TASK_OWNERSHIP_IMMUTABLE",
|
|
@@ -41842,18 +42141,10 @@ function createTaskMiddleware(options = {}) {
|
|
|
41842
42141
|
hint: "Create a separate task for different ownership or parentage."
|
|
41843
42142
|
});
|
|
41844
42143
|
}
|
|
41845
|
-
const hasMismatchedAgentOutput = isAgentTask && (input.result !== void 0 && input.status !== "completed" && !candidateReviewInterruption || input.failureReason !== void 0 && input.status !== "failed");
|
|
41846
|
-
if (hasMismatchedAgentOutput) {
|
|
41847
|
-
return JSON.stringify({
|
|
41848
|
-
success: false,
|
|
41849
|
-
code: "TASK_LIFECYCLE_TRANSITION_REQUIRED",
|
|
41850
|
-
error: "Agent task result and failureReason require a matching governed lifecycle transition.",
|
|
41851
|
-
hint: "Provide result only with completion, or failureReason only with failure."
|
|
41852
|
-
});
|
|
41853
|
-
}
|
|
41854
42144
|
const changesOwnership = input.ownerId !== void 0 && input.ownerId !== existing.ownerId || input.parentId !== void 0 && input.parentId !== existing.parentId;
|
|
41855
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;
|
|
41856
42146
|
if (changesOwnership && changesGovernedState) {
|
|
42147
|
+
taskUpdateBlocked(input.id, "TASK_OWNERSHIP_MUTATION_CONFLICT", {});
|
|
41857
42148
|
return JSON.stringify({
|
|
41858
42149
|
success: false,
|
|
41859
42150
|
code: "TASK_OWNERSHIP_MUTATION_CONFLICT",
|
|
@@ -41861,17 +42152,389 @@ function createTaskMiddleware(options = {}) {
|
|
|
41861
42152
|
hint: "Persist ownership or parent changes separately before changing lifecycle or task content."
|
|
41862
42153
|
});
|
|
41863
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
|
+
}
|
|
41864
42204
|
const actor = trustedActor(trustedProject, rc) ?? (existing.ownerType === "agent" ? `agent:${existing.ownerId}` : `user:${existing.ownerId ?? ownerId}`);
|
|
41865
|
-
const
|
|
42205
|
+
const workItemStore = getTaskWorkItemStore();
|
|
41866
42206
|
const lifecycle = isAgentTask ? createTaskLifecycleService({
|
|
41867
42207
|
taskStore: store,
|
|
41868
42208
|
workItemStore: trustedProject ? getProjectTaskWorkItemStore() : getTaskWorkItemStore()
|
|
41869
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;
|
|
41870
42511
|
const lifecycleMutationResponse = (result, extra = {}) => {
|
|
41871
42512
|
if (result.success && result.mutated) markMutation();
|
|
41872
42513
|
return lifecycleResponse(input.id, result, extra);
|
|
41873
42514
|
};
|
|
41874
|
-
|
|
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);
|
|
41875
42538
|
if (lifecycle && input.status === "failed") {
|
|
41876
42539
|
await validateExecutionResult();
|
|
41877
42540
|
const callerError = await revalidateCaller();
|
|
@@ -41881,11 +42544,9 @@ function createTaskMiddleware(options = {}) {
|
|
|
41881
42544
|
taskId: input.id,
|
|
41882
42545
|
failureReason: input.failureReason ?? existing.failureReason ?? "",
|
|
41883
42546
|
actor,
|
|
41884
|
-
threadId
|
|
42547
|
+
threadId: statusThreadId
|
|
41885
42548
|
});
|
|
41886
|
-
|
|
41887
|
-
if (trustedProject || !hasCarriedContentFields()) return lifecycleMutationResponse(failed);
|
|
41888
|
-
existing = { ...existing, status: input.status };
|
|
42549
|
+
return lifecycleMutationResponse(failed);
|
|
41889
42550
|
}
|
|
41890
42551
|
if (lifecycle && input.status === "cancelled") {
|
|
41891
42552
|
await validateExecutionResult();
|
|
@@ -41895,12 +42556,10 @@ function createTaskMiddleware(options = {}) {
|
|
|
41895
42556
|
tenantId: tenantId2,
|
|
41896
42557
|
taskId: input.id,
|
|
41897
42558
|
actor,
|
|
41898
|
-
threadId,
|
|
42559
|
+
threadId: statusThreadId,
|
|
41899
42560
|
summary: input.summary
|
|
41900
42561
|
});
|
|
41901
|
-
|
|
41902
|
-
if (trustedProject || !hasCarriedContentFields()) return lifecycleMutationResponse(cancelled);
|
|
41903
|
-
existing = { ...existing, status: input.status };
|
|
42562
|
+
return lifecycleMutationResponse(cancelled);
|
|
41904
42563
|
}
|
|
41905
42564
|
if (lifecycle && input.status === "interrupted" && !(input.context?.interruption && typeof input.context.interruption === "object" && input.context.interruption.type === "review_required")) {
|
|
41906
42565
|
const interruption = input.context?.interruption;
|
|
@@ -41922,12 +42581,10 @@ function createTaskMiddleware(options = {}) {
|
|
|
41922
42581
|
type,
|
|
41923
42582
|
summary: input.summary ?? "",
|
|
41924
42583
|
actor,
|
|
41925
|
-
threadId,
|
|
42584
|
+
threadId: statusThreadId,
|
|
41926
42585
|
dependencyTaskIds: input.dependencyTaskIds
|
|
41927
42586
|
});
|
|
41928
|
-
|
|
41929
|
-
if (trustedProject || !hasCarriedContentFields()) return lifecycleMutationResponse(interrupted);
|
|
41930
|
-
existing = { ...existing, status: input.status };
|
|
42587
|
+
return lifecycleMutationResponse(interrupted);
|
|
41931
42588
|
}
|
|
41932
42589
|
if (lifecycle && input.status === "in_progress" && existing.status === "interrupted") {
|
|
41933
42590
|
await validateExecutionResult();
|
|
@@ -41937,11 +42594,9 @@ function createTaskMiddleware(options = {}) {
|
|
|
41937
42594
|
tenantId: tenantId2,
|
|
41938
42595
|
taskId: input.id,
|
|
41939
42596
|
actor,
|
|
41940
|
-
threadId
|
|
42597
|
+
threadId: statusThreadId
|
|
41941
42598
|
});
|
|
41942
|
-
|
|
41943
|
-
if (trustedProject || !hasCarriedContentFields()) return lifecycleMutationResponse(resumed);
|
|
41944
|
-
existing = { ...existing, status: input.status };
|
|
42599
|
+
return lifecycleMutationResponse(resumed);
|
|
41945
42600
|
}
|
|
41946
42601
|
if (lifecycle && input.status === "in_progress" && existing.status === "pending") {
|
|
41947
42602
|
await validateExecutionResult();
|
|
@@ -41951,11 +42606,9 @@ function createTaskMiddleware(options = {}) {
|
|
|
41951
42606
|
tenantId: tenantId2,
|
|
41952
42607
|
taskId: input.id,
|
|
41953
42608
|
actor,
|
|
41954
|
-
threadId
|
|
42609
|
+
threadId: statusThreadId
|
|
41955
42610
|
});
|
|
41956
|
-
|
|
41957
|
-
if (trustedProject || !hasCarriedContentFields()) return lifecycleMutationResponse(started);
|
|
41958
|
-
existing = { ...existing, status: input.status };
|
|
42611
|
+
return lifecycleMutationResponse(started);
|
|
41959
42612
|
}
|
|
41960
42613
|
if (lifecycle && input.status === "in_progress" && existing.status === "failed") {
|
|
41961
42614
|
await validateExecutionResult();
|
|
@@ -41965,11 +42618,9 @@ function createTaskMiddleware(options = {}) {
|
|
|
41965
42618
|
tenantId: tenantId2,
|
|
41966
42619
|
taskId: input.id,
|
|
41967
42620
|
actor,
|
|
41968
|
-
threadId
|
|
42621
|
+
threadId: statusThreadId
|
|
41969
42622
|
});
|
|
41970
|
-
|
|
41971
|
-
if (trustedProject || !hasCarriedContentFields()) return lifecycleMutationResponse(retried);
|
|
41972
|
-
existing = { ...existing, status: input.status };
|
|
42623
|
+
return lifecycleMutationResponse(retried);
|
|
41973
42624
|
}
|
|
41974
42625
|
if (isAgentTask && input.requireReview === true && options.reviewMode !== "hitl") {
|
|
41975
42626
|
return reviewModeDisabledResponse();
|
|
@@ -41991,54 +42642,39 @@ function createTaskMiddleware(options = {}) {
|
|
|
41991
42642
|
});
|
|
41992
42643
|
}
|
|
41993
42644
|
const effectiveRequireReview = existing.requireReview === true || input.requireReview === true;
|
|
41994
|
-
const
|
|
41995
|
-
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);
|
|
41996
42647
|
if (governedAgentCompletion) {
|
|
41997
|
-
const guardedFields = [
|
|
41998
|
-
"parentId",
|
|
41999
|
-
"ownerType",
|
|
42000
|
-
"ownerId",
|
|
42001
|
-
"description"
|
|
42002
|
-
];
|
|
42003
|
-
for (const field of guardedFields) {
|
|
42004
|
-
const requestValue = input[field];
|
|
42005
|
-
const existingValue = existing[field];
|
|
42006
|
-
if (requestValue !== void 0 && requestValue !== existingValue) {
|
|
42007
|
-
return JSON.stringify({
|
|
42008
|
-
success: false,
|
|
42009
|
-
code: "COMPLETION_CONTEXT_MUTATION",
|
|
42010
|
-
error: `Cannot change ${field} while completing an agent task`,
|
|
42011
|
-
hint: "Persist the context change in a separate update before completing the task"
|
|
42012
|
-
});
|
|
42013
|
-
}
|
|
42014
|
-
}
|
|
42015
42648
|
if (!input.beliefImpact?.length) return missingBeliefImpactError();
|
|
42016
42649
|
const finalResult = input.result ?? existing.result ?? "";
|
|
42017
|
-
|
|
42018
|
-
|
|
42019
|
-
|
|
42020
|
-
|
|
42021
|
-
|
|
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
|
+
}
|
|
42022
42658
|
const completionInput = {
|
|
42023
42659
|
tenantId: tenantId2,
|
|
42024
42660
|
taskId: input.id,
|
|
42025
42661
|
result: finalResult,
|
|
42026
42662
|
beliefImpact: input.beliefImpact,
|
|
42027
42663
|
actor,
|
|
42028
|
-
threadId:
|
|
42664
|
+
threadId: statusThreadId,
|
|
42029
42665
|
sourceId: trustedProject ? void 0 : input.sourceId
|
|
42030
42666
|
};
|
|
42031
42667
|
await validateExecutionResult();
|
|
42032
|
-
const needsReview = effectiveRequireReview ||
|
|
42668
|
+
const needsReview = effectiveRequireReview || !!reviewInterruption(existing);
|
|
42033
42669
|
if (!needsReview) {
|
|
42034
42670
|
const callerError2 = await revalidateCaller();
|
|
42035
42671
|
if (callerError2) return callerError2;
|
|
42036
|
-
const result = existing.status === "completed" ? await
|
|
42672
|
+
const result = existing.status === "completed" ? await lifecycle.repairCompletion(completionInput) : await lifecycle.completeAgentTask(completionInput);
|
|
42037
42673
|
return lifecycleMutationResponse(result);
|
|
42038
42674
|
}
|
|
42039
42675
|
const callerError = await revalidateCaller();
|
|
42040
42676
|
if (callerError) return callerError;
|
|
42041
|
-
const submitted = await
|
|
42677
|
+
const submitted = await lifecycle.submitReview({
|
|
42042
42678
|
...completionInput,
|
|
42043
42679
|
reviewMode: options.reviewMode ?? "disabled",
|
|
42044
42680
|
configureRequireReview: input.requireReview === true && existing.requireReview !== true
|
|
@@ -42063,30 +42699,34 @@ function createTaskMiddleware(options = {}) {
|
|
|
42063
42699
|
if (response?.action === "approve") {
|
|
42064
42700
|
const approvalCallerError = await revalidateCaller();
|
|
42065
42701
|
if (approvalCallerError) return approvalCallerError;
|
|
42066
|
-
return lifecycleMutationResponse(await
|
|
42702
|
+
return lifecycleMutationResponse(await lifecycle.approveInterrupted({
|
|
42067
42703
|
tenantId: tenantId2,
|
|
42068
42704
|
taskId: input.id,
|
|
42069
42705
|
evidenceId,
|
|
42070
42706
|
actor,
|
|
42071
|
-
threadId:
|
|
42707
|
+
threadId: statusThreadId
|
|
42072
42708
|
}), { reviewerAction: "approved" });
|
|
42073
42709
|
}
|
|
42074
42710
|
if (response?.action === "reject") {
|
|
42075
42711
|
const note = response.data?.note?.trim() || "Changes requested.";
|
|
42076
42712
|
const rejectionCallerError = await revalidateCaller();
|
|
42077
42713
|
if (rejectionCallerError) return rejectionCallerError;
|
|
42078
|
-
return lifecycleMutationResponse(await
|
|
42714
|
+
return lifecycleMutationResponse(await lifecycle.rejectInterrupted({
|
|
42079
42715
|
tenantId: tenantId2,
|
|
42080
42716
|
taskId: input.id,
|
|
42081
42717
|
evidenceId,
|
|
42082
42718
|
actor,
|
|
42083
|
-
threadId:
|
|
42719
|
+
threadId: statusThreadId,
|
|
42084
42720
|
note
|
|
42085
42721
|
}), { reviewerAction: "rejected", reviewerNote: note });
|
|
42086
42722
|
}
|
|
42087
42723
|
return lifecycleMutationResponse(submitted, { code: "REVIEW_REQUIRED" });
|
|
42088
42724
|
}
|
|
42089
|
-
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
|
+
});
|
|
42090
42730
|
return JSON.stringify({
|
|
42091
42731
|
success: false,
|
|
42092
42732
|
code: "AGENT_TASK_LIFECYCLE_REQUIRED",
|
|
@@ -42094,45 +42734,17 @@ function createTaskMiddleware(options = {}) {
|
|
|
42094
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."
|
|
42095
42735
|
});
|
|
42096
42736
|
}
|
|
42097
|
-
const persistedStatus = input.status;
|
|
42098
|
-
let trustedReferenceSnapshots;
|
|
42099
|
-
if (input.parentId !== void 0 || input.dependencies !== void 0) {
|
|
42100
|
-
if (delegatedTaskId) {
|
|
42101
|
-
const delegatedDependencyError = await validateDelegatedDependencies(
|
|
42102
|
-
store,
|
|
42103
|
-
tenantId2,
|
|
42104
|
-
delegatedTaskId,
|
|
42105
|
-
{ workspaceId: existing.workspaceId, projectId: existing.projectId },
|
|
42106
|
-
input.parentId,
|
|
42107
|
-
input.dependencies,
|
|
42108
|
-
input.id
|
|
42109
|
-
);
|
|
42110
|
-
if (delegatedDependencyError) return delegatedDependencyError;
|
|
42111
|
-
}
|
|
42112
|
-
const referenceError = await validateReferencedTasks(
|
|
42113
|
-
store,
|
|
42114
|
-
tenantId2,
|
|
42115
|
-
{ workspaceId: existing.workspaceId, projectId: existing.projectId },
|
|
42116
|
-
input.parentId,
|
|
42117
|
-
input.dependencies
|
|
42118
|
-
);
|
|
42119
|
-
if (referenceError) return referenceError;
|
|
42120
|
-
if (trustedProject) {
|
|
42121
|
-
trustedReferenceSnapshots = await captureReferencedTaskSnapshots(
|
|
42122
|
-
store,
|
|
42123
|
-
tenantId2,
|
|
42124
|
-
{ workspaceId: existing.workspaceId, projectId: existing.projectId },
|
|
42125
|
-
input.parentId,
|
|
42126
|
-
input.dependencies
|
|
42127
|
-
);
|
|
42128
|
-
if (!trustedReferenceSnapshots) return trustedContextError();
|
|
42129
|
-
}
|
|
42130
|
-
}
|
|
42131
42737
|
if (input.status) {
|
|
42132
42738
|
if (!isAgentTask && !isValidUserTransition(existing.status, input.status)) {
|
|
42133
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
|
+
});
|
|
42134
42745
|
return JSON.stringify({
|
|
42135
42746
|
success: false,
|
|
42747
|
+
code: "INVALID_USER_TRANSITION",
|
|
42136
42748
|
error: `Cannot transition task from '${existing.status}' to '${input.status}'`,
|
|
42137
42749
|
allowedTransitions: allowed,
|
|
42138
42750
|
hint: `From '${existing.status}', valid transitions are: ${allowed.join(", ")}`
|
|
@@ -42150,154 +42762,47 @@ function createTaskMiddleware(options = {}) {
|
|
|
42150
42762
|
);
|
|
42151
42763
|
if (error) return error;
|
|
42152
42764
|
}
|
|
42153
|
-
|
|
42154
|
-
|
|
42155
|
-
if (effectiveStatus === "in_progress" && effectiveDependencies.length > 0) {
|
|
42156
|
-
const dependencyError = await validateEffectiveDependencies(
|
|
42157
|
-
store,
|
|
42158
|
-
tenantId2,
|
|
42159
|
-
{ workspaceId: existing.workspaceId, projectId: existing.projectId },
|
|
42160
|
-
effectiveDependencies
|
|
42161
|
-
);
|
|
42162
|
-
if (dependencyError) {
|
|
42163
|
-
const trustedException = trustedProject?.projectTask && input.dependencies !== void 0 ? await validateTrustedChildDependencyWait(
|
|
42164
|
-
store,
|
|
42165
|
-
tenantId2,
|
|
42166
|
-
existing,
|
|
42167
|
-
effectiveDependencies,
|
|
42168
|
-
trustedProject
|
|
42169
|
-
) : void 0;
|
|
42170
|
-
if (trustedException === void 0) return dependencyError;
|
|
42171
|
-
if (trustedException) return trustedException;
|
|
42172
|
-
}
|
|
42765
|
+
if (input.status === existing.status) {
|
|
42766
|
+
return successfulTaskResponse(input.id, existing, false);
|
|
42173
42767
|
}
|
|
42174
|
-
|
|
42175
|
-
|
|
42176
|
-
|
|
42177
|
-
if (
|
|
42178
|
-
|
|
42179
|
-
|
|
42180
|
-
|
|
42181
|
-
|
|
42182
|
-
|
|
42183
|
-
|
|
42184
|
-
|
|
42185
|
-
|
|
42186
|
-
|
|
42187
|
-
|
|
42188
|
-
|
|
42189
|
-
|
|
42190
|
-
descriptionMutated = reconciliation.mutated;
|
|
42191
|
-
if (descriptionMutated) markMutation();
|
|
42192
|
-
}
|
|
42193
|
-
const updates = {};
|
|
42194
|
-
const settableFields = [
|
|
42195
|
-
"title",
|
|
42196
|
-
"description",
|
|
42197
|
-
"priority",
|
|
42198
|
-
"dueDate",
|
|
42199
|
-
"metadata",
|
|
42200
|
-
"parentId",
|
|
42201
|
-
"sourceId",
|
|
42202
|
-
"context",
|
|
42203
|
-
"ownerId",
|
|
42204
|
-
"result",
|
|
42205
|
-
"failureReason",
|
|
42206
|
-
"requireReview",
|
|
42207
|
-
"dependencies",
|
|
42208
|
-
"files"
|
|
42209
|
-
];
|
|
42210
|
-
for (const field of settableFields) {
|
|
42211
|
-
if (trustedProject && (field === "sourceId" || field === "context" || field === "ownerId")) continue;
|
|
42212
|
-
if (field === "description" && reconciledTask) continue;
|
|
42213
|
-
const requested = input[field];
|
|
42214
|
-
const persisted = reconciledTask ?? existing;
|
|
42215
|
-
if (requested !== void 0 && !updateValuesEqual(field, requested, persisted[field])) {
|
|
42216
|
-
updates[field] = requested;
|
|
42217
|
-
}
|
|
42218
|
-
}
|
|
42219
|
-
if (persistedStatus !== void 0 && existing.status !== persistedStatus) {
|
|
42220
|
-
updates.status = persistedStatus;
|
|
42221
|
-
}
|
|
42222
|
-
if (!reconciledTask && Object.keys(updates).length > 0) {
|
|
42223
|
-
await validateExecutionResult();
|
|
42224
|
-
}
|
|
42225
|
-
if (trustedProject && (input.parentId !== void 0 || input.dependencies !== void 0)) {
|
|
42226
|
-
if (!await referencedTaskSnapshotsStillMatch(
|
|
42227
|
-
store,
|
|
42228
|
-
tenantId2,
|
|
42229
|
-
{ workspaceId: existing.workspaceId, projectId: existing.projectId },
|
|
42230
|
-
trustedReferenceSnapshots
|
|
42231
|
-
)) return trustedContextError("Parent or dependency task changed before update.");
|
|
42232
|
-
}
|
|
42233
|
-
if (trustedProject) {
|
|
42234
|
-
try {
|
|
42235
|
-
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
42236
|
-
} catch (error) {
|
|
42237
|
-
return projectPolicyError(error);
|
|
42238
|
-
}
|
|
42239
|
-
}
|
|
42240
|
-
const snapshot = trustedProject ? taskMutationSnapshot(existing) : void 0;
|
|
42241
|
-
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;
|
|
42242
|
-
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", {});
|
|
42243
42784
|
return JSON.stringify({
|
|
42244
42785
|
success: false,
|
|
42245
|
-
|
|
42246
|
-
|
|
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."
|
|
42247
42789
|
});
|
|
42248
42790
|
}
|
|
42249
|
-
|
|
42250
|
-
if (reconciledTask && Object.keys(updates).length === 0) {
|
|
42251
|
-
return successfulTaskResponse(input.id, updated, descriptionMutated, reconciliationMetadata);
|
|
42252
|
-
}
|
|
42253
|
-
if (Object.keys(updates).length === 0) {
|
|
42254
|
-
return successfulTaskResponse(input.id, updated, false);
|
|
42255
|
-
}
|
|
42256
|
-
const actionMap = {
|
|
42257
|
-
pending: "pending",
|
|
42258
|
-
in_progress: "started",
|
|
42259
|
-
failed: "failed",
|
|
42260
|
-
interrupted: "interrupted",
|
|
42261
|
-
completed: "completed",
|
|
42262
|
-
cancelled: "cancelled"
|
|
42263
|
-
};
|
|
42264
|
-
const workItemAction = persistedStatus ? actionMap[persistedStatus] || "updated" : "updated";
|
|
42265
|
-
const workItemSummary = input.summary || (persistedStatus ? `Status changed to ${persistedStatus}` : void 0);
|
|
42266
|
-
let activityWarnings;
|
|
42791
|
+
markMutation();
|
|
42267
42792
|
try {
|
|
42268
|
-
|
|
42269
|
-
try {
|
|
42270
|
-
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
42271
|
-
} catch (error) {
|
|
42272
|
-
return projectPolicyError(error);
|
|
42273
|
-
}
|
|
42274
|
-
}
|
|
42275
|
-
await workItemStore.create({
|
|
42793
|
+
await statusWorkItemStore.create({
|
|
42276
42794
|
taskId: input.id,
|
|
42277
42795
|
tenantId: tenantId2,
|
|
42278
|
-
action:
|
|
42796
|
+
action: input.status,
|
|
42279
42797
|
actor,
|
|
42280
|
-
threadId:
|
|
42281
|
-
summary:
|
|
42282
|
-
|
|
42283
|
-
|
|
42284
|
-
...input.failureReason !== void 0 && { failureReason: input.failureReason }
|
|
42285
|
-
},
|
|
42286
|
-
workspaceId: updated.workspaceId,
|
|
42287
|
-
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
|
|
42288
42802
|
});
|
|
42289
|
-
} catch
|
|
42290
|
-
activityWarnings = [{
|
|
42291
|
-
code: "TASK_UPDATE_ACTIVITY_WRITE_FAILED",
|
|
42292
|
-
taskId: input.id,
|
|
42293
|
-
error: error instanceof Error ? error.message : String(error)
|
|
42294
|
-
}];
|
|
42803
|
+
} catch {
|
|
42295
42804
|
}
|
|
42296
|
-
|
|
42297
|
-
return successfulTaskResponse(input.id, updated, true, {
|
|
42298
|
-
...reconciliationMetadata,
|
|
42299
|
-
warnings: mergeTaskUpdateWarnings(lifecycleWarnings, activityWarnings)
|
|
42300
|
-
});
|
|
42805
|
+
return successfulTaskResponse(input.id, updatedStatus, true);
|
|
42301
42806
|
}
|
|
42302
42807
|
case "delete": {
|
|
42303
42808
|
if (!input.id) {
|
|
@@ -42314,8 +42819,9 @@ function createTaskMiddleware(options = {}) {
|
|
|
42314
42819
|
if (!existing) {
|
|
42315
42820
|
return JSON.stringify({
|
|
42316
42821
|
success: false,
|
|
42317
|
-
|
|
42318
|
-
|
|
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."
|
|
42319
42825
|
});
|
|
42320
42826
|
}
|
|
42321
42827
|
if (!taskMatchesRuntimeScope3(existing, workspaceId, projectId)) {
|
|
@@ -42341,8 +42847,9 @@ function createTaskMiddleware(options = {}) {
|
|
|
42341
42847
|
if (!deleted) {
|
|
42342
42848
|
return JSON.stringify({
|
|
42343
42849
|
success: false,
|
|
42344
|
-
|
|
42345
|
-
|
|
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."
|
|
42346
42853
|
});
|
|
42347
42854
|
}
|
|
42348
42855
|
return JSON.stringify({ success: true, message: `Task '${input.id}' deleted` });
|
|
@@ -42357,7 +42864,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
42357
42864
|
}
|
|
42358
42865
|
};
|
|
42359
42866
|
const reconcileExplicitExecutionResult = async (input, config, response, validationError, didMutate) => {
|
|
42360
|
-
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;
|
|
42361
42868
|
const authority = classifyTaskAuthority(getRunConfig2(config));
|
|
42362
42869
|
if (authority.kind === "projectRoom" || authority.kind === "projectTask" || authority.kind === "invalid") {
|
|
42363
42870
|
return response;
|
|
@@ -42551,14 +43058,18 @@ ${TASK_CONVERGENCE_GUIDANCE}
|
|
|
42551
43058
|
- Explicit ownerId: assign to a specific agent (cross-agent delegation)
|
|
42552
43059
|
|
|
42553
43060
|
## Actions
|
|
42554
|
-
- create: Create a task (title required
|
|
43061
|
+
- create: Create a task (title required)
|
|
42555
43062
|
- get: Get one task and its newest 100 activities (id required)
|
|
42556
43063
|
- list: List tasks, filterable by ownerType/status/priority/parentId
|
|
42557
|
-
- update: Update a task
|
|
42558
|
-
|
|
42559
|
-
|
|
42560
|
-
|
|
42561
|
-
|
|
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.
|
|
42562
43073
|
- add_activity: Add a Markdown activity without changing task fields or status (id and content required)
|
|
42563
43074
|
- delete: Delete a task (id required)
|
|
42564
43075
|
|
|
@@ -42738,7 +43249,12 @@ manage_eval calls in this skill and in [[eval-verify]]'s Setup step 0 \u2014
|
|
|
42738
43249
|
[[eval-verify]] loads this skill and inherits its confirmation requirement.
|
|
42739
43250
|
|
|
42740
43251
|
## Project Structure
|
|
42741
|
-
1. Project: one per agent-under-test.
|
|
43252
|
+
1. Project: one per agent-under-test. A NEW project is created through [[eval-verify]]
|
|
43253
|
+
Setup, which owns project organization: it resolves the exact subject agent-id,
|
|
43254
|
+
checks whether \`eval-{agent-id}\` already exists (read_eval list_projects), reuses it
|
|
43255
|
+
when it does, and confirms with the user before \`manage_eval create_project\`
|
|
43256
|
+
(which requires \`evalVerifyLoaded: true\`). Do NOT call create_project directly from
|
|
43257
|
+
this skill \u2014 load [[eval-verify]] to create a project.
|
|
42742
43258
|
2. Suite: one per capability/domain. Create with manage_eval create_suite.
|
|
42743
43259
|
3. Case: user input \u2192 agent steps \u2192 expected output \u2192 rubrics. Create with manage_eval create_case.
|
|
42744
43260
|
|
|
@@ -43031,6 +43547,15 @@ ACTIONS:
|
|
|
43031
43547
|
}
|
|
43032
43548
|
);
|
|
43033
43549
|
}
|
|
43550
|
+
function requireEvalVerifyDeclaration(evalVerifyLoaded) {
|
|
43551
|
+
if (evalVerifyLoaded !== true) {
|
|
43552
|
+
return JSON.stringify({
|
|
43553
|
+
success: false,
|
|
43554
|
+
error: "Load the 'eval-verify' skill via the skill tool (skill_name 'eval-verify'), then retry this exact call with evalVerifyLoaded: true. eval-verify owns eval project organization: it resolves the exact subject agent-id, checks whether eval-{agent-id} already exists, reuses it when it does, and confirms with the user before creating. Never create an eval project without following it."
|
|
43555
|
+
});
|
|
43556
|
+
}
|
|
43557
|
+
return void 0;
|
|
43558
|
+
}
|
|
43034
43559
|
function createManageEvalTool() {
|
|
43035
43560
|
const schema6 = import_zod69.z.object({
|
|
43036
43561
|
action: import_zod69.z.enum([
|
|
@@ -43049,6 +43574,7 @@ function createManageEvalTool() {
|
|
|
43049
43574
|
description: import_zod69.z.string().optional(),
|
|
43050
43575
|
judgeModelKey: import_zod69.z.string().optional(),
|
|
43051
43576
|
concurrency: import_zod69.z.number().optional(),
|
|
43577
|
+
evalVerifyLoaded: import_zod69.z.boolean().optional().describe("Required on create_project: load the 'eval-verify' skill first via the skill tool (skill_name 'eval-verify'), then pass evalVerifyLoaded: true. Calls without evalVerifyLoaded: true fail. Never omit or pass false."),
|
|
43052
43578
|
targetAgentId: import_zod69.z.string().optional().describe("Optional for create_project \u2014 the agent this eval project verifies. Recorded in targetServerConfig so the agent's detail page can find its eval data without relying on project naming."),
|
|
43053
43579
|
suiteId: import_zod69.z.string().optional(),
|
|
43054
43580
|
caseId: import_zod69.z.string().optional(),
|
|
@@ -43074,6 +43600,8 @@ function createManageEvalTool() {
|
|
|
43074
43600
|
let data;
|
|
43075
43601
|
switch (input.action) {
|
|
43076
43602
|
case "create_project": {
|
|
43603
|
+
const skillError = requireEvalVerifyDeclaration(input.evalVerifyLoaded);
|
|
43604
|
+
if (skillError) return skillError;
|
|
43077
43605
|
const ctx = workspaceContext(exeConfig);
|
|
43078
43606
|
data = await store.createProject(tid, (0, import_uuid12.v4)(), {
|
|
43079
43607
|
name: input.name,
|
|
@@ -43154,7 +43682,12 @@ function createManageEvalTool() {
|
|
|
43154
43682
|
name: "manage_eval",
|
|
43155
43683
|
description: `Create, update, delete evaluation projects, suites, and test cases.
|
|
43156
43684
|
|
|
43157
|
-
Project: create_project(name, description?, judgeModelKey?, concurrency?, targetAgentId?) | update_project | delete_project
|
|
43685
|
+
Project: create_project(name, description?, judgeModelKey?, concurrency?, targetAgentId?, evalVerifyLoaded?) | update_project | delete_project
|
|
43686
|
+
create_project REQUIRES evalVerifyLoaded: true \u2014 load the 'eval-verify' skill first
|
|
43687
|
+
(skill tool, skill_name 'eval-verify'). eval-verify owns project organization:
|
|
43688
|
+
resolve the exact subject agent-id, check whether eval-{agent-id} already exists via
|
|
43689
|
+
read_eval list_projects, reuse it when it does, confirm with the user when it does not,
|
|
43690
|
+
and always pass targetAgentId. Calls without evalVerifyLoaded: true fail.
|
|
43158
43691
|
judgeModelKey defaults to the "default" model. concurrency defaults to 3.
|
|
43159
43692
|
delete_project rejected if active runs exist.
|
|
43160
43693
|
**When creating a project from within a workspace, the workspace/project context is
|
|
@@ -43509,6 +44042,10 @@ Selected target eval subjects:
|
|
|
43509
44042
|
- Orchestra: component evals first, then integration eval
|
|
43510
44043
|
- Workflow: validate_workflow first, then workflow eval covering branch paths, intermediate contracts, ask points, recovery
|
|
43511
44044
|
- In Bounded mode: subject is always the exact bound target ID
|
|
44045
|
+
The eval project belongs to the TARGET agent, not to this round. The subject identity is
|
|
44046
|
+
fixed per target; across rounds and fix passes of the same target, [[eval-verify]] Setup
|
|
44047
|
+
resolves the canonical eval-{target-id} project and REUSES it \u2014 never create a new eval
|
|
44048
|
+
project for a new round of the same agent.
|
|
43512
44049
|
|
|
43513
44050
|
### 7. Deliver
|
|
43514
44051
|
|