You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(actions): dispatch on the declared action type over REST (#3915) (#3919)
The REST `/actions/:object/:action` route had no action-type branching — every
action went to the script-handler registry, while the MCP `run_action` bridge
implemented the `flow` branch. A spec-faithful caller invoking a `type: 'flow'`
action got `Action '' on object '*' not found`.
Both headless surfaces now share one dispatch: `flow` runs on the automation
service (via the extracted `dispatchFlowAction`, with the caller's identity
forwarded so `runAs: 'user'` enforces RLS as the invoker), `script` keeps the
registry path, and `url`/`modal`/`form`/`api` return a 400 naming the type and
what to call instead. The route also resolves standalone `defineAction`
artifacts and Studio-authored `action` rows, which additionally closes a
declared-but-unenforced ADR-0066 D4 gate on that path.
Copy file name to clipboardExpand all lines: content/docs/ui/actions.mdx
+11Lines changed: 11 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -233,6 +233,16 @@ curl -b cookies.txt -X POST \
233
233
Global (object-less) actions post to `/api/v1/actions/global/:action`. For
234
234
credentials, see [API Authentication](/docs/api#authentication).
235
235
236
+
The endpoint dispatches on the **declared `type`**, exactly like the MCP
237
+
`run_action` tool — so the same URL invokes a script handler or a flow:
238
+
239
+
|`type`| Over REST |
240
+
|:---|:---|
241
+
|`script`| Runs the registered handler / inline body. |
242
+
|`flow`| Runs `target` on the automation engine, with your identity forwarded (a `runAs: 'user'` flow enforces RLS as you). Equivalent to `POST /api/v1/automation/:target/trigger`, without having to know the flow name. |
243
+
|`api`|**400** — it dispatches on `target`; call that endpoint directly. |
244
+
|`url` / `modal` / `form`|**400** — client-side navigation; there is nothing for the server to run. |
245
+
236
246
## Expose it to AI (MCP)
237
247
238
248
Actions are **not** AI-visible by default. Opting in takes two fields — and
@@ -256,6 +266,7 @@ and [Connect an MCP Client](/docs/ai/connect-mcp).
256
266
|:---|:---|
257
267
| Button doesn't appear |`locations` doesn't include the surface; or the `visible` CEL throws (e.g. a bare, unprefixed field name) and fail-closed hides it; or the user fails `requiredPermissions`|
258
268
| Click → `Action 'x' … not found`|`target`-style script with no registered handler — add the `registerAction` call in `onEnable` (Path B above) |
269
+
| REST → 400 naming the action's `type`| The type has no server dispatch (`url`/`modal`/`form`/`api`) — open its `target` in the client, or call that endpoint directly |
259
270
| Appears in UI, missing from `list_actions` (MCP) |`ai.exposed` not `true`, `ai.description` under 40 characters, or the type isn't headless-callable |
260
271
| Runs but the list looks stale | Add `refreshAfter: true`|
0 commit comments