cloudflare / cloudflare/agents

codemode: support argument-aware approval decisions before durable pause

Open
#2,134 1 comment 0 reactions 1 assignee Claimed by @mattzcarey View on GitHub
enhancement
Dominant language
TypeScript
Stars
5.6k
Forks
711
Avg merge
1d 20h
Merged PRs (30d)
53

Description

## Summary

Code Mode durable approvals currently support only a static `requiresApproval: boolean` annotation. Connectors need a way to validate and classify a call from its actual arguments **before** `runtime.decide(...)` records or pauses it.

This remains the behavior in `@cloudflare/codemode` 0.5.1. `buildConnectorBindings` reads `annotation?.requiresApproval`, calls `runtime.decide(...)`, and only then calls `connector.executeTool(...)`. `ToolSetConnector` also documents that a function-valued AI SDK `needsApproval` cannot be evaluated and is therefore conservatively always approval-gated.

## Use case

A connector exposes one GraphQL operation tool:

```ts
graphql({ document, variables })
```

The payload may contain:

- a query, which should execute immediately;
- a mutation, which should pause for approval;
- an invalid, multi-operation, ambiguous, or subscription document, which should be rejected before any approval is created.

With the current API, marking the tool `requiresApproval: true` unnecessarily gates every query. Leaving it untagged lets mutations run. Validating in `executeTool` is too late: the durable runtime has already made and persisted its approval decision.

The same problem applies to tools whose sensitivity depends on a target, action, or argument value.

## Suggested API shape

One option is a connector hook:

```ts
async preflightTool(method, args, ctx) {
// May validate and throw. Must not perform a side effect.
return { requiresApproval: classify(method, args) };
}
```

The durable binding would invoke it before `runtime.decide(...)` and use its result as an override of the static annotation. If preflight throws, the call should fail without creating a pending approval record.

Alternatively, `requiresApproval` could accept an async predicate over the arguments, provided it runs at that same pre-decision boundary.

## Required semantics

- Runs before a pending approval is durably recorded.
- Can reject invalid input without producing an approval request.
- Cannot execute the underlying action or other side effects.
- Has documented replay behavior so an approved action cannot change classification or arguments on resume.
- Preserves the current static boolean behavior by default.

## Related issue

#1148 covers the broader Code Mode approval design and is closed. Durable per-action pause/replay now exists; this issue is specifically about the remaining argument-aware decision boundary.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.