@sanity/workflow-mcp 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -49,13 +49,26 @@ export declare interface ProjectedActionVerdict {
49
49
  disabledReason?: string;
50
50
  }
51
51
 
52
+ export declare interface ProjectedActivity {
53
+ /** Activity name — what to pass to `fire_action` as `activity`. */
54
+ activity: string;
55
+ /** Human label, if provided. */
56
+ title?: string;
57
+ /** Longer prose description, if provided. */
58
+ description?: string;
59
+ /** Current activity status. */
60
+ status: "pending" | "active" | "done" | "skipped" | "failed";
61
+ /** Available actions on this activity, each with its allowed/disabled verdict. */
62
+ actions: ProjectedActionVerdict[];
63
+ }
64
+
52
65
  /**
53
66
  * The diagnosis projection — why an instance is or isn't progressing.
54
67
  *
55
68
  * The engine's {@link SuggestedRemediation} is already small and
56
69
  * LLM-friendly, so `remediations` passes through verbatim rather than
57
70
  * being re-projected. The verbose `WorkflowEvaluation` the engine returns
58
- * alongside the diagnosis is dropped — per-task action detail belongs to
71
+ * alongside the diagnosis is dropped — per-activity action detail belongs to
59
72
  * {@link ProjectedInstanceState} (get_workflow_state), not here.
60
73
  */
61
74
  export declare interface ProjectedDiagnosis {
@@ -95,8 +108,8 @@ export declare interface ProjectedInstanceState {
95
108
  done: boolean;
96
109
  /** What this workflow is about. See {@link ProjectedSubject}. */
97
110
  subject?: ProjectedSubject;
98
- /** Tasks on the current stage, with available actions. */
99
- tasks: ProjectedTask[];
111
+ /** Activities on the current stage, with available actions. */
112
+ activities: ProjectedActivity[];
100
113
  /** Most recent history entries (newest first), capped to keep payload tight. */
101
114
  recentHistory: ProjectedHistoryEntry[];
102
115
  }
@@ -148,19 +161,6 @@ export declare interface ProjectedSubject {
148
161
  title?: string;
149
162
  }
150
163
 
151
- export declare interface ProjectedTask {
152
- /** Task name — what to pass to `fire_action` as `task`. */
153
- task: string;
154
- /** Human label, if provided. */
155
- title?: string;
156
- /** Longer prose description, if provided. */
157
- description?: string;
158
- /** Current task status. */
159
- status: "pending" | "active" | "done" | "skipped" | "failed";
160
- /** Available actions on this task, each with its allowed/disabled verdict. */
161
- actions: ProjectedActionVerdict[];
162
- }
163
-
164
164
  /**
165
165
  * The MCP tool surface for workflow operations — the static descriptors an
166
166
  * agent reads to decide what to call. The implementations live in `tools.ts`;
@@ -178,7 +178,7 @@ export declare interface ProjectedTask {
178
178
  * raw `WorkflowInstance` documents.
179
179
  * - `diagnose_workflow` answers "*why* isn't this moving?" — it
180
180
  * classifies an instance as healthy (waiting/progressing) or genuinely
181
- * stuck (a failed effect/task, a dead-end transition) and names the
181
+ * stuck (a failed effect/activity, a dead-end transition) and names the
182
182
  * remediations that would unstick it. A pure read; the remediations are
183
183
  * advisory (none execute through this server).
184
184
  * - `fire_action` is the only write. Mirrors the engine's universal
@@ -201,7 +201,7 @@ export declare interface ProjectedTask {
201
201
  * - Parameter names use snake_case, matching MCP convention.
202
202
  * - The write tool's description spells out that this is the way
203
203
  * to advance workflow state — not a side door. Without that line,
204
- * an LLM tends to look for a `complete_task` or `set_stage` tool.
204
+ * an LLM tends to look for a `complete_activity` or `set_stage` tool.
205
205
  * - Read tools cap their output. A 50-page `recent_history` would
206
206
  * burn context and is rarely informative; 8 is enough to spot
207
207
  * loops or stuck-in-stage patterns.
package/dist/index.d.ts CHANGED
@@ -49,13 +49,26 @@ export declare interface ProjectedActionVerdict {
49
49
  disabledReason?: string;
50
50
  }
51
51
 
52
+ export declare interface ProjectedActivity {
53
+ /** Activity name — what to pass to `fire_action` as `activity`. */
54
+ activity: string;
55
+ /** Human label, if provided. */
56
+ title?: string;
57
+ /** Longer prose description, if provided. */
58
+ description?: string;
59
+ /** Current activity status. */
60
+ status: "pending" | "active" | "done" | "skipped" | "failed";
61
+ /** Available actions on this activity, each with its allowed/disabled verdict. */
62
+ actions: ProjectedActionVerdict[];
63
+ }
64
+
52
65
  /**
53
66
  * The diagnosis projection — why an instance is or isn't progressing.
54
67
  *
55
68
  * The engine's {@link SuggestedRemediation} is already small and
56
69
  * LLM-friendly, so `remediations` passes through verbatim rather than
57
70
  * being re-projected. The verbose `WorkflowEvaluation` the engine returns
58
- * alongside the diagnosis is dropped — per-task action detail belongs to
71
+ * alongside the diagnosis is dropped — per-activity action detail belongs to
59
72
  * {@link ProjectedInstanceState} (get_workflow_state), not here.
60
73
  */
61
74
  export declare interface ProjectedDiagnosis {
@@ -95,8 +108,8 @@ export declare interface ProjectedInstanceState {
95
108
  done: boolean;
96
109
  /** What this workflow is about. See {@link ProjectedSubject}. */
97
110
  subject?: ProjectedSubject;
98
- /** Tasks on the current stage, with available actions. */
99
- tasks: ProjectedTask[];
111
+ /** Activities on the current stage, with available actions. */
112
+ activities: ProjectedActivity[];
100
113
  /** Most recent history entries (newest first), capped to keep payload tight. */
101
114
  recentHistory: ProjectedHistoryEntry[];
102
115
  }
@@ -148,19 +161,6 @@ export declare interface ProjectedSubject {
148
161
  title?: string;
149
162
  }
150
163
 
151
- export declare interface ProjectedTask {
152
- /** Task name — what to pass to `fire_action` as `task`. */
153
- task: string;
154
- /** Human label, if provided. */
155
- title?: string;
156
- /** Longer prose description, if provided. */
157
- description?: string;
158
- /** Current task status. */
159
- status: "pending" | "active" | "done" | "skipped" | "failed";
160
- /** Available actions on this task, each with its allowed/disabled verdict. */
161
- actions: ProjectedActionVerdict[];
162
- }
163
-
164
164
  /**
165
165
  * The MCP tool surface for workflow operations — the static descriptors an
166
166
  * agent reads to decide what to call. The implementations live in `tools.ts`;
@@ -178,7 +178,7 @@ export declare interface ProjectedTask {
178
178
  * raw `WorkflowInstance` documents.
179
179
  * - `diagnose_workflow` answers "*why* isn't this moving?" — it
180
180
  * classifies an instance as healthy (waiting/progressing) or genuinely
181
- * stuck (a failed effect/task, a dead-end transition) and names the
181
+ * stuck (a failed effect/activity, a dead-end transition) and names the
182
182
  * remediations that would unstick it. A pure read; the remediations are
183
183
  * advisory (none execute through this server).
184
184
  * - `fire_action` is the only write. Mirrors the engine's universal
@@ -201,7 +201,7 @@ export declare interface ProjectedTask {
201
201
  * - Parameter names use snake_case, matching MCP convention.
202
202
  * - The write tool's description spells out that this is the way
203
203
  * to advance workflow state — not a side door. Without that line,
204
- * an LLM tends to look for a `complete_task` or `set_stage` tool.
204
+ * an LLM tends to look for a `complete_activity` or `set_stage` tool.
205
205
  * - Read tools cap their output. A 50-page `recent_history` would
206
206
  * burn context and is rarely informative; 8 is enough to spot
207
207
  * loops or stuck-in-stage patterns.
package/dist/index.js CHANGED
@@ -2,16 +2,15 @@ import { extractDocumentId, actionVerdict, isTerminalStage, validateDefinition,
2
2
  import { defineWorkflow } from "@sanity/workflow-engine/define";
3
3
  const minimalExample = {
4
4
  name: "quick-approval",
5
- version: 1,
6
5
  title: "Quick approval",
7
6
  description: "One review stage with a single approve action, then a terminal stage.",
8
7
  initialStage: "review",
9
- fields: [{ type: "doc.ref", name: "subject", title: "Document", source: { type: "init" } }],
8
+ fields: [{ type: "doc.ref", name: "subject", title: "Document", initialValue: { type: "input" } }],
10
9
  stages: [
11
10
  {
12
11
  name: "review",
13
12
  title: "Review",
14
- tasks: [
13
+ activities: [
15
14
  {
16
15
  name: "decide",
17
16
  title: "Decide",
@@ -25,16 +24,15 @@ const minimalExample = {
25
24
  ]
26
25
  }, reviewLoopExample = {
27
26
  name: "doc-review",
28
- version: 1,
29
27
  title: "Document review",
30
28
  description: "Draft, then editorial review that approves or rejects back to drafting.",
31
29
  initialStage: "drafting",
32
- fields: [{ type: "doc.ref", name: "subject", title: "Document", source: { type: "init" } }],
30
+ fields: [{ type: "doc.ref", name: "subject", title: "Document", initialValue: { type: "input" } }],
33
31
  stages: [
34
32
  {
35
33
  name: "drafting",
36
34
  title: "Drafting",
37
- tasks: [
35
+ activities: [
38
36
  {
39
37
  name: "write",
40
38
  title: "Write the draft",
@@ -47,7 +45,7 @@ const minimalExample = {
47
45
  {
48
46
  name: "review",
49
47
  title: "Editorial review",
50
- tasks: [
48
+ activities: [
51
49
  {
52
50
  name: "review",
53
51
  title: "Review the draft",
@@ -60,18 +58,18 @@ const minimalExample = {
60
58
  ],
61
59
  transitions: [
62
60
  { name: "to-approved", title: "Approve and finish", to: "approved" },
63
- // Reject flips the task to `failed`; this routes the instance back.
61
+ // Reject flips the activity to `failed`; this routes the instance back.
64
62
  {
65
63
  name: "to-drafting",
66
64
  title: "Send back to drafting",
67
65
  to: "drafting",
68
- filter: "$anyTaskFailed"
66
+ filter: "$anyActivityFailed"
69
67
  }
70
68
  ]
71
69
  },
72
70
  { name: "approved", title: "Approved", description: "Terminal \u2014 no transitions out." }
73
71
  ]
74
- }, ORIENTATION = "# Authoring a workflow definition\n\nA workflow definition is a plain JSON object. There is no code in it \u2014 every\ncondition (filters, predicates, guards) is a GROQ *string*. Generate the JSON,\nthen call `validate_workflow_definition` to check it; fix the reported errors\nand re-validate until it returns `valid: true`. The validator returns the\n*desugared* definition under `definition` \u2014 that is exactly what would deploy.\n\n## Shape\n\n- **Workflow**: `{ name, version (positive int), title, description?, initialStage, fields?, stages[], predicates? }`.\n `initialStage` must be the `name` of a declared stage.\n- **Stage**: `{ name, title?, description?, tasks?, transitions? }`. A stage with\n no transitions is terminal. Reaching a terminal stage ends the workflow.\n- **Task**: `{ name, title?, activation?, actions? }`. `activation` is `'auto'`\n (starts when the stage is entered) or `'manual'` (default \u2014 a human starts it).\n- **Action**: `{ name, title?, status?, params?, ops? }`.\n `status: 'done' | 'skipped' | 'failed'` is sugar that flips the *firing task* to\n that status when the action fires. `ops` are mutations applied when the action\n fires (e.g. `{type:'field.set', target:{field:'x'}, value:{type:'param', param:'p'}}`).\n `params` are values the action collects from the caller (referenced by\n `{type:'param', param:'<name>'}` sources).\n- **Transition**: `{ name, title?, to, filter? }`. `to` must name a declared\n stage. `filter` is a GROQ condition gating the exit; omit it and it defaults\n to `$allTasksDone`.\n- **Field** (workflow- or stage-scoped persistent state): `{ type, name, title?, source }`.\n Common `type`s: `doc.ref`, `doc.refs`, `value.string`, `value.url`,\n `value.number`, `value.boolean`. `source` is where the value comes from:\n `{type:'init'}` (supplied when the instance starts), `{type:'write'}` (a user\n edits it), `{type:'param', param:'<actionParamName>'}`, `{type:'now'}`, `{type:'actor'}`.\n By convention a workflow has an `init`-sourced `doc.ref` named `subject` \u2014 the\n headline document it is about.\n\n## GROQ in conditions\n\nBuilt-in variables available in filters/predicates: `$allTasksDone`,\n`$anyTaskFailed` (booleans over the current stage's tasks), `$tasks` (the task\nlist), `$fields` (field values), `$now`, and the caller-scoped vars `$actor`\n(the acting user), `$assigned` (whether the caller is the task's assignee \u2014 the\nidiomatic permission gate, used as `filter: '$assigned'`), and `$can`. Define\nreusable named conditions under top-level `predicates: { name: '<groq>' }` and\nreference them as `$name` (e.g.\n`predicates: { ready: \"count($tasks[status != 'done']) == 0\" }` \u2192 `$ready`).\n\nConditions evaluate against an in-memory snapshot (the instance + its subject +\nfield-declared docs) \u2014 **never** scan by `_type` (e.g. `*[_type==\"article\"]`);\nthat is a discovery query and the validator rejects it. To bring a document into\nscope, declare a `doc.ref` field for it.\n\n## Sugars worth knowing\n\n- Action `status: 'done' | 'skipped' | 'failed'` \u2014 flips the firing task (shown above).\n- Omitted transition `filter` \u2014 defaults to `$allTasksDone`.\n- Omitted task `activation` \u2014 defaults to `'manual'`.\n\n## Modeling defaults\n\nValid is not the same as good. Prefer these unless the request says otherwise:\n\n- **A decline/reject loops back.** Route a rejected / changes-requested\n transition to an *earlier* stage for revision (e.g. `review \u2192 drafting` gated\n on `$anyTaskFailed`), not to a terminal stage. Reserve terminal stages for\n completion and for explicit cancellation/abandonment \u2014 a workflow should not\n dead-end just because something was declined.\n- **Prefer draft \u2192 review.** Model an author working in a drafting stage who\n submits, then a review stage that gates. Don't add more review stages unless\n the request asks for multiple approvers or rounds.\n- **When the shape is ambiguous, pick the conventional one and confirm** with the\n user rather than inventing extra stages.\n\n## Rules the validator enforces\n\n- Stage names, task names (per stage) and transition names are unique.\n- Every transition `to` and `initialStage` names a declared stage.\n- Custom `predicates` must not shadow a built-in (e.g. `allTasksDone`).\n- Every GROQ string must parse and must not be a `_type` discovery scan.", AUTHORING_GUIDE = `${ORIENTATION}
72
+ }, ORIENTATION = "# Authoring a workflow definition\n\nA workflow definition is a plain JSON object. There is no code in it \u2014 every\ncondition (filters, predicates, guards) is a GROQ *string*. Generate the JSON,\nthen call `validate_workflow_definition` to check it; fix the reported errors\nand re-validate until it returns `valid: true`. The validator returns the\n*desugared* definition under `definition` \u2014 that is exactly what would deploy.\n\n## Shape\n\n- **Workflow**: `{ name, title, description?, initialStage, fields?, stages[], predicates? }`.\n `initialStage` must be the `name` of a declared stage. Do NOT include a\n `version` \u2014 definitions are immutable and content-addressed; deploy assigns\n the version from the content, the author never writes one.\n- **Stage**: `{ name, title?, description?, activities?, transitions? }`. A stage with\n no transitions is terminal. Reaching a terminal stage ends the workflow.\n- **Activity**: `{ name, title?, activation?, actions? }`. `activation` is `'auto'`\n (starts when the stage is entered) or `'manual'` (default \u2014 a human starts it).\n- **Action**: `{ name, title?, status?, params?, ops? }`.\n `status: 'done' | 'skipped' | 'failed'` is sugar that flips the *firing activity* to\n that status when the action fires. `ops` are mutations applied when the action\n fires (e.g. `{type:'field.set', target:{field:'x'}, value:{type:'param', param:'p'}}`).\n `params` are values the action collects from the caller (referenced by\n `{type:'param', param:'<name>'}` sources).\n- **Transition**: `{ name, title?, to, filter? }`. `to` must name a declared\n stage. `filter` is a GROQ condition gating the exit; omit it and it defaults\n to `$allActivitiesDone`.\n- **Field** (workflow- or stage-scoped persistent state): `{ type, name, title?, initialValue? }`.\n Scalar `type`s mirror Sanity: `string`, `text` (multiline), `number`,\n `boolean`, `date` (YYYY-MM-DD), `datetime` (ISO), `url`. Plus references\n (`doc.ref`, `doc.refs`, `release.ref`), identities (`actor` \u2014 one concrete\n principal; `assignee` / `assignees` \u2014 one or many user-or-role assignees), and\n the compositional kinds `object` (`{ type:'object', name, fields: [...] }`) and\n `array` (`{ type:'array', name, of: [...] }`) \u2014 `fields`/`of` are themselves\n field shapes, so any structure composes. `initialValue` seeds the slot once at\n materialisation and is **optional** \u2014 omit it for op-filled working memory\n (the common default). Arms: `{type:'input'}` (the caller supplies it when the\n instance starts), `{type:'query', query:'<groq>'}` (computed from the lake),\n `{type:'literal', value:<json>}`, or `{type:'fieldRead', field:'<name>'}`.\n By convention a workflow has an `input`-sourced `doc.ref` named `subject` \u2014 the\n headline document it is about.\n Two list sugars desugar to `array`: `{type:'todoList', name}` (ad-hoc\n status-tracked work \u2014 rows `{ label, status, assignee?, dueDate? }`) and\n `{type:'notes', name}` (an append-only audit/comment log \u2014 rows\n `{ body, actor, at }`; pairs with the `audit` op, which stamps `actor`/`at`).\n\n## GROQ in conditions\n\nBuilt-in variables available in filters/predicates: `$allActivitiesDone`,\n`$anyActivityFailed` (booleans over the current stage's activities), `$activities` (the activity\nlist), `$fields` (field values), `$now`, and the caller-scoped vars `$actor`\n(the acting user), `$assigned` (whether the caller is the activity's assignee \u2014 the\nidiomatic permission gate, used as `filter: '$assigned'`), and `$can`. Define\nreusable named conditions under top-level `predicates: { name: '<groq>' }` and\nreference them as `$name` (e.g.\n`predicates: { ready: \"count($activities[status != 'done']) == 0\" }` \u2192 `$ready`).\n\nConditions evaluate against an in-memory snapshot (the instance + its subject +\nfield-declared docs) \u2014 **never** scan by `_type` (e.g. `*[_type==\"article\"]`);\nthat is a discovery query and the validator rejects it. To bring a document into\nscope, declare a `doc.ref` field for it.\n\n## Sugars worth knowing\n\n- Action `status: 'done' | 'skipped' | 'failed'` \u2014 flips the firing activity (shown above).\n- Omitted transition `filter` \u2014 defaults to `$allActivitiesDone`.\n- Omitted activity `activation` \u2014 defaults to `'manual'`.\n\n## Modeling defaults\n\nValid is not the same as good. Prefer these unless the request says otherwise:\n\n- **A decline/reject loops back.** Route a rejected / changes-requested\n transition to an *earlier* stage for revision (e.g. `review \u2192 drafting` gated\n on `$anyActivityFailed`), not to a terminal stage. Reserve terminal stages for\n completion and for explicit cancellation/abandonment \u2014 a workflow should not\n dead-end just because something was declined.\n- **Prefer draft \u2192 review.** Model an author working in a drafting stage who\n submits, then a review stage that gates. Don't add more review stages unless\n the request asks for multiple approvers or rounds.\n- **When the shape is ambiguous, pick the conventional one and confirm** with the\n user rather than inventing extra stages.\n\n## Rules the validator enforces\n\n- Stage names, activity names (per stage) and transition names are unique.\n- Every transition `to` and `initialStage` names a declared stage.\n- Custom `predicates` must not shadow a built-in (e.g. `allActivitiesDone`).\n- Every GROQ string must parse and must not be a `_type` discovery scan.", AUTHORING_GUIDE = `${ORIENTATION}
75
73
 
76
74
  ## Examples
77
75
 
@@ -106,7 +104,7 @@ ${JSON.stringify(reviewLoopExample, null, 2)}
106
104
  },
107
105
  {
108
106
  name: "get_workflow_state",
109
- description: "Get the current state of a single workflow instance, projected for action. Returns the workflow's id and human-readable `workflowTitle`, the current stage, the subject document the workflow is about (when the workflow has a conventional subject \u2014 its ref and title), every task on the current stage with its available actions (and whether each action is currently allowed), and the most recent history entries. Use this whenever you need to understand what's possible on an instance before deciding to act. This is a pure read \u2014 it does not change anything. If you only need to discover what instances exist, use list_workflow_instances instead; this tool requires you to know the instance id. list_workflow_instances also returns the same `workflowTitle` and `subject` fields, so prefer it for fan-out discovery rather than polling get_workflow_state per instance.",
107
+ description: "Get the current state of a single workflow instance, projected for action. Returns the workflow's id and human-readable `workflowTitle`, the current stage, the subject document the workflow is about (when the workflow has a conventional subject \u2014 its ref and title), every activity on the current stage with its available actions (and whether each action is currently allowed), and the most recent history entries. Use this whenever you need to understand what's possible on an instance before deciding to act. This is a pure read \u2014 it does not change anything. If you only need to discover what instances exist, use list_workflow_instances instead; this tool requires you to know the instance id. list_workflow_instances also returns the same `workflowTitle` and `subject` fields, so prefer it for fan-out discovery rather than polling get_workflow_state per instance.",
110
108
  input_schema: {
111
109
  type: "object",
112
110
  properties: {
@@ -121,7 +119,7 @@ ${JSON.stringify(reviewLoopExample, null, 2)}
121
119
  },
122
120
  {
123
121
  name: "diagnose_workflow",
124
- description: "Explain why a single workflow instance is or isn't progressing. Returns a verdict (`state`: progressing, waiting, blocked, completed, aborted, or stuck), a one-line `summary`, and \u2014 when stuck \u2014 a structured `cause` plus the `remediations` that would unstick it. Use this when an instance seems stalled or the user asks \"why isn't this moving?\": it distinguishes a healthy instance (waiting on a human, or will advance on its own) from a genuinely stuck one (a failed effect or task, a dead-end transition). This is a pure read \u2014 it changes nothing, and the remediations it names are advisory: none can be executed through this server. To actually advance a healthy waiting instance use fire_action; for per-task action detail use get_workflow_state.",
122
+ description: "Explain why a single workflow instance is or isn't progressing. Returns a verdict (`state`: progressing, waiting, blocked, completed, aborted, or stuck), a one-line `summary`, and \u2014 when stuck \u2014 a structured `cause` plus the `remediations` that would unstick it. Use this when an instance seems stalled or the user asks \"why isn't this moving?\": it distinguishes a healthy instance (waiting on a human, or will advance on its own) from a genuinely stuck one (a failed effect or activity, a dead-end transition). This is a pure read \u2014 it changes nothing, and the remediations it names are advisory: none can be executed through this server. To actually advance a healthy waiting instance use fire_action; for per-activity action detail use get_workflow_state.",
125
123
  input_schema: {
126
124
  type: "object",
127
125
  properties: {
@@ -136,7 +134,7 @@ ${JSON.stringify(reviewLoopExample, null, 2)}
136
134
  },
137
135
  {
138
136
  name: "fire_action",
139
- description: "Advance a workflow instance by firing an action on one of its tasks. This is the only way to advance workflow state from the outside \u2014 there is no separate 'complete task' or 'transition stage' tool. To find the right (task, action) pair, call get_workflow_state first and pick from the allowed actions listed on the current stage's tasks. After firing, the engine cascades any auto-transitions that become eligible (so an 'approve' action on a review task may transition the workflow to a terminal stage in one shot). Returns the resulting state, same shape as get_workflow_state. If the action is not currently allowed (e.g. the task is already done, or a guard fails), this returns an error describing why.",
137
+ description: "Advance a workflow instance by firing an action on one of its activities. This is the only way to advance workflow state from the outside \u2014 there is no separate 'complete activity' or 'transition stage' tool. To find the right (activity, action) pair, call get_workflow_state first and pick from the allowed actions listed on the current stage's activities. After firing, the engine cascades any auto-transitions that become eligible (so an 'approve' action on a review activity may transition the workflow to a terminal stage in one shot). Returns the resulting state, same shape as get_workflow_state. If the action is not currently allowed (e.g. the activity is already done, or a guard fails), this returns an error describing why.",
140
138
  input_schema: {
141
139
  type: "object",
142
140
  properties: {
@@ -144,16 +142,16 @@ ${JSON.stringify(reviewLoopExample, null, 2)}
144
142
  type: "string",
145
143
  description: "The workflow instance id."
146
144
  },
147
- task: {
145
+ activity: {
148
146
  type: "string",
149
- description: "The id of the task on the current stage. Must be one of the tasks returned by get_workflow_state."
147
+ description: "The id of the activity on the current stage. Must be one of the activities returned by get_workflow_state."
150
148
  },
151
149
  action: {
152
150
  type: "string",
153
- description: "The id of the action on that task. Must be one of the actions listed as allowed=true on the task."
151
+ description: "The id of the action on that activity. Must be one of the actions listed as allowed=true on the activity."
154
152
  }
155
153
  },
156
- required: ["instance_id", "task", "action"],
154
+ required: ["instance_id", "activity", "action"],
157
155
  additionalProperties: !1
158
156
  }
159
157
  },
@@ -237,7 +235,7 @@ function projectSummary(doc, subjectTitles) {
237
235
  };
238
236
  }
239
237
  function projectState(instance, evaluation, subjectTitles) {
240
- const workflowTitle = JSON.parse(instance.definitionSnapshot).title, stageTitle = evaluation.currentStage.stage.title, tasks = evaluation.currentStage.tasks.map((te) => {
238
+ const workflowTitle = JSON.parse(instance.definitionSnapshot).title, stageTitle = evaluation.currentStage.stage.title, activities = evaluation.currentStage.activities.map((te) => {
241
239
  const actions = te.actions.map((ae) => {
242
240
  const verdict = actionVerdict(te, ae);
243
241
  return {
@@ -248,9 +246,9 @@ function projectState(instance, evaluation, subjectTitles) {
248
246
  };
249
247
  });
250
248
  return {
251
- task: te.task.name,
252
- ...te.task.title !== void 0 ? { title: te.task.title } : {},
253
- ...te.task.description !== void 0 ? { description: te.task.description } : {},
249
+ activity: te.activity.name,
250
+ ...te.activity.title !== void 0 ? { title: te.activity.title } : {},
251
+ ...te.activity.description !== void 0 ? { description: te.activity.description } : {},
254
252
  status: te.status,
255
253
  actions
256
254
  };
@@ -267,7 +265,7 @@ function projectState(instance, evaluation, subjectTitles) {
267
265
  ...stageTitle !== void 0 ? { currentStageTitle: stageTitle } : {},
268
266
  done: isInstanceDone(instance),
269
267
  ...subject !== void 0 ? { subject } : {},
270
- tasks,
268
+ activities,
271
269
  recentHistory
272
270
  };
273
271
  }
@@ -282,10 +280,10 @@ function isInstanceDone(instance) {
282
280
  }
283
281
  const DISABLED_REASON_TEXT = {
284
282
  "filter-failed": "action's filter condition did not hold for this actor",
285
- "task-not-active": "task is not currently active",
283
+ "activity-not-active": "activity is not currently active",
286
284
  "stage-terminal": "stage is terminal \u2014 no further actions possible",
287
285
  "instance-completed": "instance has already completed",
288
- "requirements-unmet": "task's declared requirements are not yet satisfied"
286
+ "requirements-unmet": "activity's declared requirements are not yet satisfied"
289
287
  };
290
288
  function formatDisabledReason(reason) {
291
289
  return DISABLED_REASON_TEXT[reason.kind] ?? reason.kind.replace(/-/g, " ");
@@ -296,12 +294,12 @@ function summariseHistoryEntry(entry) {
296
294
  return `entered stage "${String(entry.stage)}"`;
297
295
  case "stageExited":
298
296
  return `exited stage "${String(entry.stage)}" \u2192 "${String(entry.toStage)}"`;
299
- case "taskActivated":
300
- return `task "${String(entry.task)}" activated`;
301
- case "taskStatusChanged":
302
- return `task "${String(entry.task)}" status: ${String(entry.from)} \u2192 ${String(entry.to)}`;
297
+ case "activityActivated":
298
+ return `activity "${String(entry.activity)}" activated`;
299
+ case "activityStatusChanged":
300
+ return `activity "${String(entry.activity)}" status: ${String(entry.from)} \u2192 ${String(entry.to)}`;
303
301
  case "actionFired":
304
- return `action "${String(entry.action)}" fired on task "${String(entry.task)}"`;
302
+ return `action "${String(entry.action)}" fired on activity "${String(entry.activity)}"`;
305
303
  case "transitionFired":
306
304
  return `transition fired: "${String(entry.fromStage)}" \u2192 "${String(entry.toStage)}"`;
307
305
  case "effectQueued":
@@ -309,7 +307,7 @@ function summariseHistoryEntry(entry) {
309
307
  case "effectCompleted":
310
308
  return `effect "${String(entry.effect)}" completed (${String(entry.status)})`;
311
309
  case "spawned":
312
- return `spawned child workflow from task "${String(entry.task)}"`;
310
+ return `spawned child workflow from activity "${String(entry.activity)}"`;
313
311
  default:
314
312
  return entry._type;
315
313
  }
@@ -319,9 +317,9 @@ function diagnosisSummary(diagnosis) {
319
317
  case "progressing":
320
318
  return "This instance will advance on its own.";
321
319
  case "waiting":
322
- return `Waiting for action on task "${diagnosis.task}": ${diagnosis.actions.join(" or ")}. This is the normal in-flight state \u2014 it advances when someone acts.`;
320
+ return `Waiting for action on activity "${diagnosis.activity}": ${diagnosis.actions.join(" or ")}. This is the normal in-flight state \u2014 it advances when someone acts.`;
323
321
  case "blocked":
324
- return `Task "${diagnosis.task}" is visible but not yet executable \u2014 unmet requirement(s): ${diagnosis.requirements.join(", ")}. It will not advance until those are satisfied.`;
322
+ return `Activity "${diagnosis.activity}" is visible but not yet executable \u2014 unmet requirement(s): ${diagnosis.requirements.join(", ")}. It will not advance until those are satisfied.`;
325
323
  case "completed":
326
324
  return `Completed at ${diagnosis.at}.`;
327
325
  case "aborted":
@@ -333,13 +331,13 @@ function diagnosisSummary(diagnosis) {
333
331
  function stuckSummary(cause) {
334
332
  switch (cause.kind) {
335
333
  case "failed-effect":
336
- return `Stuck: a failed effect "${cause.effect.name}" is blocking task "${cause.effect.origin.name}", which can't complete until the effect succeeds.`;
334
+ return `Stuck: a failed effect "${cause.effect.name}" is blocking activity "${cause.effect.origin.name}", which can't complete until the effect succeeds.`;
337
335
  case "hung-effect":
338
336
  return `Stuck: effect "${cause.effect.name}" was claimed but never completed \u2014 the drainer likely died mid-dispatch, so it won't drain on its own.`;
339
- case "failed-task":
340
- return `Stuck: task "${cause.task}" is in a terminal failed state, so any exit transition gated on it can never fire.`;
337
+ case "failed-activity":
338
+ return `Stuck: activity "${cause.activity}" is in a terminal failed state, so any exit transition gated on it can never fire.`;
341
339
  case "no-transition-fires":
342
- return "Stuck: every task is resolved but no exit transition's filter is satisfied \u2014 likely a routing state value a filter reads was never written.";
340
+ return "Stuck: every activity is resolved but no exit transition's filter is satisfied \u2014 likely a routing state value a filter reads was never written.";
343
341
  case "transition-unevaluable":
344
342
  return `Stuck (recoverable): exit transition(s) ${cause.transitions.join(", ")} read an operand that is missing or unreadable (GROQ null). It advances on its own once that data becomes readable \u2014 no manual fix needed.`;
345
343
  }
@@ -363,7 +361,7 @@ function buildTools(engine, options = {}) {
363
361
  const input = parseFireActionInput(rawInput);
364
362
  return await engine.fireAction({
365
363
  instanceId: input.instance_id,
366
- task: input.task,
364
+ activity: input.activity,
367
365
  action: input.action,
368
366
  ...accessOverride !== void 0 ? { access: accessOverride } : {}
369
367
  }), getInstanceState(engine, input.instance_id, accessOverride);
@@ -408,12 +406,12 @@ function parseFireActionInput(raw) {
408
406
  if (raw === null || typeof raw != "object")
409
407
  throw new Error("fire_action: input must be an object");
410
408
  const obj = raw;
411
- for (const key of ["instance_id", "task", "action"])
409
+ for (const key of ["instance_id", "activity", "action"])
412
410
  if (typeof obj[key] != "string" || obj[key] === "")
413
411
  throw new Error(`fire_action: ${key} is required`);
414
412
  return {
415
413
  instance_id: obj.instance_id,
416
- task: obj.task,
414
+ activity: obj.activity,
417
415
  action: obj.action
418
416
  };
419
417
  }