Skip to content

Abilities: gate pre-execute with approval decision filter, surface from loop#234

Merged
chubes4 merged 2 commits into
Automattic:mainfrom
ibrahimhajjaj:add/pre-execute-approval-94
May 28, 2026
Merged

Abilities: gate pre-execute with approval decision filter, surface from loop#234
chubes4 merged 2 commits into
Automattic:mainfrom
ibrahimhajjaj:add/pre-execute-approval-94

Conversation

@ibrahimhajjaj
Copy link
Copy Markdown
Contributor

@ibrahimhajjaj ibrahimhajjaj commented May 28, 2026

Summary

Two coupled pieces of #94 in one PR: the wp_pre_execute_ability bridge handler that mints pending actions and returns approval_required envelopes, and the mediate_tool_calls branch that recognizes those envelopes and surfaces status: approval_required from the loop.

Refs #94. Stacks on the lifecycle bridge added in #199.

Bridge handler

Adds gate_pre_execute as a second handler on WP_Agent_Ability_Lifecycle_Bridge. Hosts opt into per-call approval by hooking agents_api_ability_pre_execute_decision and returning either a WP_Agent_Pending_Action or an array shape WP_Agent_Pending_Action::from_array() accepts. The bridge handles the boilerplate: sentinel pass-through so stacked consumers coexist, minting (when needed) through from_array(), best-effort staging through the wp_agent_pending_action_store filter, and returning the canonical approval_required envelope.

Loop recognition

mediate_tool_calls now detects when an ability call returned an approval_required envelope, captures it, appends it to the transcript in place of the tool_result, emits an approval_required event with the action_id, and halts mediation for the turn. The outer run() loop surfaces status: 'approval_required' and completed: false on the final result, mirroring how budget_exceeded and stalled are surfaced today.

Changes

  • src/Abilities/class-wp-agent-ability-lifecycle-bridge.php: new FILTER_PRE_EXECUTE_DECISION and FILTER_PENDING_ACTION_STORE consts, second add_filter in register(), new gate_pre_execute static method.
  • src/Runtime/class-wp-agent-conversation-loop.php: approval detection inside mediate_tool_calls, new approval_required return key, per-turn pickup in run(), status block on the final result.
  • tests/pre-execute-approval-smoke.php: new smoke covering sentinel pass-through, null decision = pass-through, pending-action decision = mint+stage+envelope, the coexistence guarantee (second consumer bails on a non-sentinel $pre), and loop-level recognition.
  • composer.json: registers the new smoke.
  • docs/runtime-and-tools.md: new "Ability lifecycle bridge" section + a paragraph in "Budgets, events, and failure behavior" for the new loop status.

Testing

  • php tests/pre-execute-approval-smoke.php — 14 assertions, all pass.
  • php tests/ability-lifecycle-bridge-smoke.php — 12 assertions, all pass (existing, unchanged behavior).
  • php tests/conversation-loop-tool-execution-smoke.php — all pass (unchanged).
  • composer test — full suite green.
  • git diff --check — clean.
  • php -l on all modified files — clean.

AI assistance

  • AI assistance: Yes
  • Tool(s): OpenCode (GPT-5.5)
  • Used for: Static-analysis cleanup for the approval gate PR; Chris reviewed via local lint/test gates before merge.

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.

2 participants