Skip to content

feat(provider): add onPermissionRequest callback option#17

Merged
DaniAkash merged 4 commits into
mainfrom
feat/on-permission-request-callback
May 18, 2026
Merged

feat(provider): add onPermissionRequest callback option#17
DaniAkash merged 4 commits into
mainfrom
feat/on-permission-request-callback

Conversation

@DaniAkash
Copy link
Copy Markdown
Owner

@DaniAkash DaniAkash commented May 6, 2026

Summary

Upstream: openclaw/acpx#299 — the runtime PR this provider change consumes.

Forwards onPermissionRequest from AcpxProviderSettings into the underlying AcpRuntimeOptions, so hosts can intercept per-call permission requests with their own UI. Returning undefined from the callback (or omitting it entirely) falls through to the existing permissionMode resolver — zero behavior change for existing consumers.

Driven by downstream BrowserOS chat work that wants inline approve/deny CTA cards instead of an up-front mode gate. The mode gate is too coarse for that flow — approve-reads silently denies writes (codex's apply_patch aborts with no signal), approve-all skips approval entirely. A per-call callback is the right primitive.

const provider = createAcpxProvider({
  agent: 'codex',
  cwd: '/path/to/repo',
  permissionMode: 'approve-reads', // fallback for unhandled cases
  onPermissionRequest: async (req, { signal }) => {
    const decision = await myUi.prompt({
      title: req.raw.toolCall.title,
      kind: req.inferredKind,
    })
    return decision // undefined falls through to the mode resolver
  },
})

What changed

File Change
package.json Version 0.0.40.0.5. acpx peer-dep + dev-dep raised to >=0.8.0 (the upstream version that ships onPermissionRequest on AcpRuntimeOptions via openclaw/acpx#299).
src/types.ts Re-export AcpPermissionRequest + AcpPermissionDecision from acpx/runtime; add onPermissionRequest to AcpxProviderSettings with the documented signature and doc-comment.
src/provider.ts Thread the option through buildRuntimeOptions() (one line).
src/index.ts Re-export the two new types.
README.md Replace the "Permissions are mode-based" limitation bullet with a fall-through explanation; new ## Per-call permissions section with the full callback contract.
test/unit/provider.test.ts NEW — three tests using bun:test mock.module('acpx/runtime') to intercept createAcpRuntime and assert on the options bag: (1) callback forwards into AcpRuntimeOptions, (2) absent when not configured, (3) pre-built runtime: option skips runtime construction entirely.
test/e2e/permission-callback.test.ts NEW — opt-in e2e contract test that spawns a real codex-acp process. Asserts the wire-level permission round-trip end-to-end: callback fires with a correctly-shaped AcpPermissionRequest, and the agent honours reject_once, allow_once, and undefined fall-through outcomes. Gated behind SMOKE_AGENTS=codex so it stays out of CI.

Test plan

  • bun run lint clean.
  • bun run typecheck clean (passes against the now-published acpx@0.8.0).
  • bun run fallow clean.
  • bun test — 266 pass / 24 skip / 0 fail across the monorepo (290 tests, 30 files; the three new unit tests are part of the 266; the new e2e test is in the 24 skipped because SMOKE_AGENTS is unset).
  • SMOKE_AGENTS=codex bun test packages/acpx-ai-provider/test/e2e/permission-callback.test.ts — 3 pass / 0 fail against a real codex 0.130.0 instance, ~42s.
  • bun run build clean (ESM + .d.ts).

Coordination

This PR ships alongside two sibling provider features that all target 0.0.5:

  • #19getModels() helper
  • #23sessionOptions forwarding

Whichever lands first wins 0.0.5; the other two will need a follow-up bump (0.0.50.0.60.0.7) and a one-line package.json rebase to resolve the version conflict. All three are independent on the code side.

Hosts can now intercept the agent's per-call permission requests
with their own UI by passing onPermissionRequest to
createAcpxProvider. Returning undefined falls through to the existing
mode-based resolver, so existing consumers see no behavior change.

Driven by downstream BrowserOS chat work that wants inline
approve/deny CTA cards instead of an up-front mode gate. The mode
gate is too coarse for that flow — approve-reads silently denies
writes (codex's apply_patch aborts with no signal), approve-all
skips approval entirely.

The provider's job is plumbing only: pass the option through to
createAcpRuntime, the runtime owns the wire-level resolution and
decision-to-optionId mapping.

- src/types.ts: re-export AcpPermissionRequest +
  AcpPermissionDecision from acpx/runtime; add onPermissionRequest
  to AcpxProviderSettings with the documented signature
- src/provider.ts: thread the option through buildRuntimeOptions()
- src/index.ts: re-export the two new types
- README.md: replace the mode-only limitation bullet with a
  fall-through explanation; add a new Per-call permissions section
  with the full callback contract
- test/unit/provider.test.ts: three tests covering callback
  forwarding, the omitted case, and the documented pre-built-runtime
  no-op
- package.json: bump to 0.1.0; bump acpx peer-dep + dev-dep to
  >=0.8.0 to require the runtime release that exposes the callback

Blocked on upstream openclaw/acpx#299 + a corresponding acpx release.
Typecheck fails until then because the new types don't exist in
acpx@0.7.0; runtime / lint / fallow / build / tests all green.
Resolves conflicts:
- packages/acpx-ai-provider/package.json: keep this branch's 0.1.0
  bump (was 0.0.4 on main; this PR ships new public API).
- packages/acpx-ai-provider/src/provider.ts: keep both changes —
  main's toRuntimeMcpServers() helper for type-safe mcpServers,
  AND this branch's onPermissionRequest pass-through.

Resyncs bun.lock against acpx@0.8.0 (now published, gates the
onPermissionRequest option this PR forwards).
@DaniAkash DaniAkash marked this pull request as ready for review May 17, 2026 07:09
… real codex

Spawns a real codex-acp process and asserts the wire-level permission
round-trip: the callback fires with a correctly-shaped request, and
the agent honours reject_once, allow_once, and undefined fall-through.

Gated behind SMOKE_AGENTS=codex so it stays out of CI.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds per-call permission callback support to acpx-ai-provider, forwarding onPermissionRequest into the underlying ACP runtime and documenting/testing the new host-interception flow.

Changes:

  • Adds onPermissionRequest to provider settings and exports the related permission request/decision types.
  • Threads the callback into runtime construction and documents per-call permissions.
  • Bumps acpx dependency requirements and adds unit/e2e coverage for callback forwarding and behavior.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/acpx-ai-provider/src/types.ts Adds callback option and permission type exports.
packages/acpx-ai-provider/src/provider.ts Forwards the callback into AcpRuntimeOptions.
packages/acpx-ai-provider/src/index.ts Re-exports new permission-related types.
packages/acpx-ai-provider/README.md Documents per-call permission callback usage and fallback behavior.
packages/acpx-ai-provider/package.json Bumps package and acpx dependency versions.
bun.lock Updates locked acpx dependency metadata.
packages/acpx-ai-provider/test/unit/provider.test.ts Adds unit tests for runtime option forwarding.
packages/acpx-ai-provider/test/e2e/permission-callback.test.ts Adds opt-in Codex e2e permission callback contract tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@DaniAkash DaniAkash merged commit 91ebe46 into main May 18, 2026
6 checks passed
@DaniAkash DaniAkash deleted the feat/on-permission-request-callback branch May 18, 2026 10:42
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