Skip to content

feat(agent-bff): expose the action execute endpoint with result normalization#1752

Open
nbouliol wants to merge 3 commits into
feature/prd-673-expose-the-action-form-endpointfrom
feature/prd-674-expose-the-action-execute-endpoint-with-result-normalization
Open

feat(agent-bff): expose the action execute endpoint with result normalization#1752
nbouliol wants to merge 3 commits into
feature/prd-673-expose-the-action-form-endpointfrom
feature/prd-674-expose-the-action-execute-endpoint-with-result-normalization

Conversation

@nbouliol

@nbouliol nbouliol commented Jul 10, 2026

Copy link
Copy Markdown
Member

What

Exposes POST /v1/:collection/actions/:action/execute on the BFF, stacked on the action-form PR (#1748). It rejects unknown submitted fields, runs the Smart Action, and normalizes the agent result into one flat wrapper — success / error / webhook / redirect — returning a structured 501 for File results, which are unimplemented in v1.

Fixes PRD-674

Base branch is feature/prd-673-expose-the-action-form-endpoint (stacked). Review after #1748 merges; rebase onto main at that point.

How

agent-client (2 additive, backward-compatible changes — a version bump ships with this, so rollback is no longer "redeploy agent-bff alone"):

  • ActionFormValidationError now carries html; toActionError forwards it from the native action Error payload ({ error, html }). Without this the html is dropped before reaching the BFF.
  • setFields throws a typed UnknownActionFieldError (same message as before) so callers route an unknown field to a client error instead of a generic 500. Existing consumers (mcp-server, workflow-executor) catch generically and are unaffected.

agent-bff:

  • action-execute-mapper.ts — pure mapper: the agent 200 payload is discriminated positively (webhook / redirect / success); any unrecognized body (a streamed File) falls through to a 501 unsupported_action_result. HttpRequester does not expose response headers, so Content-Disposition cannot be read — the fall-through is the only viable File detection.
  • agent-action-client.ts — a single loadAction method (form and execute load the same agent-client Action object); Action extends ActionForm.
  • action-routes-middleware.ts — one middleware matching both /form and /execute with shared body parsing and action resolution. execute() gets its own try/catch (it cannot use the generic callAgent, which would mislabel the action-Error 400 as a transport 502): UnknownActionFieldError → 400 invalid_request, ActionFormValidationError → 400 { type: "error", ..., html }, ActionRequiresApprovalError → 403 action_requires_approval, transport 5xx → agent_unavailable.
  • bff-local-errors.ts — new actionRequiresApproval (403).

Result shapes

Agent result HTTP BFF body
Success 200 { type: "success", message, invalidated: [...], html }
Error (native) 400 { type: "error", status: 400, message, html }
Webhook 200 { type: "webhook", url, method, headers, body }
Redirect 200 { type: "redirect", path }
File 501 { error: { type: "unsupported_action_result", status: 501 } }

Out of scope / follow-ups

  • Approval-gated actions are not wired (no createApprovalRequest); they surface as 403 action_requires_approval (with roleIdsAllowedToApprove). Full wiring depends on the auth foundation (PRD-637) providing a per-mode Forest-server token + rendering context, and would add an approvalRequested wrapper shape. To confirm with the spec author.
  • action_not_allowed (403) still has no local trigger — every non-exposed action maps to 404, mirroring the collection/relation routes (existing TODO).

Tests

  • agent-client: html carry on the error path, typed UnknownActionFieldError from setFields.
  • agent-bff: pure execute mapper (all shapes + 501), the /execute route (missing recordIds, unknown field, action Error + html, approval, File, unknown action, transport 5xx vs action-Error 400, success/webhook/redirect), and the shared loadAction.
  • No regression in setFields consumers: mcp-server (24) and workflow-executor adapter (63) green.

🤖 Generated with Claude Code

Note

Expose action execute endpoint in agent-bff with result normalization

  • Adds a POST /agent/v1/:collection/actions/:action/execute route in action-routes-middleware.ts, dispatching alongside the existing /form route via a unified regex.
  • Introduces mapActionExecuteResult in action-execute-mapper.ts to normalize raw execute payloads into typed BFF responses: 200 success, 200 webhook, 200 redirect, or 501 unsupported_action_result.
  • Adds actionRequiresApproval (403) and maps ActionFormValidationError (400 with optional html) and UnknownActionFieldError (400 invalid_request) in the execute handler.
  • Widens AgentActionClient from loadActionForm to loadAction, returning a new Action interface with setFields and execute methods.
  • Extends ActionFormValidationError to carry an html property and introduces UnknownActionFieldError with a fieldName in agent-client errors.

Macroscope summarized 911b16e.

nbouliol and others added 2 commits July 10, 2026 15:36
…eld error

Carry the native action Error result's html on ActionFormValidationError and
throw a typed UnknownActionFieldError from the strict setFields, so consumers
can render error markup and route unknown fields to a client error.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lization

Serve POST /v1/:collection/actions/:action/execute: reject unknown submitted
fields via setFields, run the action, and normalize the agent result into a
flat wrapper (success/error/webhook/redirect), returning 501 for File results.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@linear-code

linear-code Bot commented Jul 10, 2026

Copy link
Copy Markdown

PRD-674

@qltysh

qltysh Bot commented Jul 10, 2026

Copy link
Copy Markdown

6 new issues

Tool Category Rule Count
qlty Structure Function with many returns (count = 4): mapActionExecuteResult 2
qlty Structure Function with high complexity (count = 13): mapActionExecuteResult 2
qlty Structure Function with many parameters (count = 7): handleForm 2

Comment thread packages/agent-bff/src/action/action-execute-mapper.ts Outdated
Comment thread packages/agent-bff/src/action/action-routes-middleware.ts Outdated
Validate value shapes (not just key presence) when normalizing the execute
result so malformed payloads fall through to 501 instead of a null-field 200,
and keep an empty roleIdsAllowedToApprove array in the approval 403 details.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant