feat: Add workbench actions - #3910
Conversation
Soffi AI SummaryThis PR adds workbench actions — a new approval/supervision workflow for AI workbench tool invocations that require human review before execution. It addresses PROD-5073. The core change introduces an "Actions" tab in the workbench UI that surfaces pending tool calls waiting for human approval or denial. Key motivations and changes include:
Commits
Updated: 2026-07-28 18:08 UTC |
Preserve upstream rejected activity status and MCP subagent selection, keep deny user attribution and k8s modes GraphQL. Co-authored-by: Cursor <cursoragent@cursor.com>
Greptile SummaryThe PR adds supervised workbench actions and their review workflow.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| lib/console/deployments/workbenches.ex | Adds transactional approval and rejection execution with row locking to serialize concurrent decisions. |
| lib/console/graphql/resolvers/deployments/workbench.ex | Adds action mutations and server-side redaction and retrieval logic for Kubernetes request diffs. |
| assets/src/graph/workbench.graphql | Adds workbench action mutations and a focused query for Kubernetes request diff data. |
| assets/src/components/workbenches/workbench/job/WorkbenchJobActionDetail.tsx | Implements the action-review UI and approval or denial interactions. |
| assets/src/components/workbenches/workbench/job/WorkbenchJobKubeUpdateDiff.tsx | Renders Kubernetes action diffs while suppressing Secret details in the UI. |
| test/console/deployments/workbenches_test.exs | Covers workbench action execution, including serialized concurrent approvals. |
| test/console/graphql/queries/deployments/workbench_queries_test.exs | Covers GraphQL retrieval and server-side redaction of Kubernetes Secret request bodies. |
Reviews (2): Last reviewed commit: "fix build" | Re-trigger Greptile
|
plural review this |
There was a problem hiding this comment.
Nice feature set overall, and the prior Secret-body exposure issue looks addressed. I found two remaining issues before this is ready:
reject_job_activity/3still allows an approve/reject race that can mark an already-executed action as rejected.- Kubernetes update action titles drop the object name, which makes the new action UIs ambiguous when multiple resources of the same kind are present.
Requesting changes for those.
|
|
||
| export function formatKubeKindLabel( | ||
| resource: string | undefined | ||
| ): string | undefined { |
There was a problem hiding this comment.
getKubeActionTitle() only includes the resource name for delete actions. For update actions this collapses every item in a collection to the same title (e.g. every Deployment shows as just Deployments), which makes the new inline/action-list UI much harder to scan once there are multiple pending updates in the same namespace. Please include parsed.name for update actions too, similar to the delete case.
| get_workbench_job_activity!(activity_id) | ||
| |> allow(user, :approve) | ||
| |> when_ok(fn activity -> | ||
| start_transaction() |
There was a problem hiding this comment.
There’s still a race on rejection. reject_job_activity/3 now locks the row, but unlike approve_job_activity/2 it never verifies that the activity is still in :needs_approval before updating it. After one reviewer approves and releases the lock, a concurrent reject can acquire the lock and overwrite the now-successful activity to :rejected, leaving state inconsistent with the already-executed external action. Please guard reject the same way approval is effectively guarded, so only activities currently awaiting approval can transition to rejected.
| |> paginate(args) | ||
| end | ||
|
|
||
| def function_call_tool(%{tool_id: id}, _, _) when is_binary(id), |
There was a problem hiding this comment.
the changes in this module are pretty clunky i'll try to make a few style improvements.
| @@ -0,0 +1,42 @@ | |||
| import createIcon from './createIcon' | |||
|
|
|||
| const icon = | |||
There was a problem hiding this comment.
embedding a png seems like the wrong approach here. You can either generate an svg from it with a tool or ask the ai to do that for you.
There was a problem hiding this comment.
I've done a ton of these, I usually just prompt the ai to search for brand icons online, and generate the appropriate svg from them. It can normally figure it out, and often find one that's already availale online with web search.
Fixes PROD-5073 too.
Test Plan
Test environment: https://console.plrl-dev-aws.onplural.sh/
Checklist
Plural Flow: console