Skip to content

Conversation

@bendrucker
Copy link
Contributor

@bendrucker bendrucker commented Dec 18, 2025

Adds missing fields to Vercel AI adapter types for full AI SDK compatibility, addressing data part reconciliation and other protocol gaps.

Changes

  • DataChunk: Adds optional id field for data part reconciliation and transient field for non-persistent data
  • FinishChunk: Adds finish_reason field with standard stop reasons (stop, length, content-filter, tool-calls, error, other, unknown)
    • Populated from ModelResponse.finish_reason in handle_run_result
    • Set to error in on_error handler
  • Adds ToolApprovalRequestChunk and ToolOutputDeniedChunk types for human-in-the-loop tool approval workflows

Future Work

Tool approval integration will be addressed in a separate PR. This requires:

  1. Emitting ToolApprovalRequestChunk when agent output is DeferredToolRequests
  2. Exploring how Vercel AI SDK sends back approval/denial responses to map them to DeferredToolResults
  3. Handling ToolOutputDeniedChunk — currently Pydantic AI doesn't distinguish denied tool results from normal results at the event stream level (denied results flow as FunctionToolResultEvent with ToolReturnPart)

Testing

  • Added test for DataChunk with id field to verify reconciliation IDs serialize correctly in the SSE stream
  • Added test for DataChunk with transient: true to verify non-persistent data chunks are encoded properly
  • Updated existing error handling tests to verify finishReason: 'error' is set correctly

tool_call_id: str


class ToolOutputDeniedChunk(BaseChunk):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we ever receive (the part version) of this, and should we handle it? We'll likely need it for https://ai.pydantic.dev/deferred-tools/#human-in-the-loop-tool-approval

@bendrucker bendrucker force-pushed the vercel-ai-data-chunk-fields branch from 0f50321 to 6c6e56f Compare December 18, 2025 21:18
When agent run result contains DeferredToolRequests with approvals,
emit ToolApprovalRequestChunk for each tool call requiring human
approval. Uses tool_call_id as both approval_id and tool_call_id.
@bendrucker bendrucker changed the title Add missing AI SDK data chunk fields for reconciliation Add AI SDK data chunk ID and tool approval types Dec 18, 2025
@bendrucker
Copy link
Contributor Author

Forgot to post this comment, splitting off deferred tool <> approval integration definitely makes sense based on my epxloration. I will slim this down to types + finish reason and then kick off a draft for tool approval logic.

Dug into denials a bit, approvals are closer to being easily supported.

When a user denies a tool execution, Pydantic AI doesn't have a distinct event type for it. Denied tool results flow as regular FunctionToolResultEvent with ToolReturnPart, with the denial message as the content field. There's no way to distinguish a denial from a normal tool result at the event stream level.

So we'd need something like:

  • A new event type like DeniedToolResultEvent
  • A ToolDeniedPart message type (vs ToolReturnPart)

- Use event.result.response instead of all_messages()
- Set finish_reason to error in on_error
- Remove tool approval emission (defer to separate PR)
- Update test snapshots for finishReason field
@DouweM
Copy link
Collaborator

DouweM commented Dec 19, 2025

When a user denies a tool execution, Pydantic AI doesn't have a distinct event type for it.

@bendrucker Hmm, Pydantic AI doesn't have an event for denials because denials never originate in Pydantic AI itself, they come from the user in the form of DeferredToolResults passed into agent.run, so I'm not sure why Vercel AI expects us to yield denial chunks to them, rather than them sending approval/denial parts or metadata to us?

@DouweM DouweM merged commit 64a6fe4 into pydantic:main Dec 19, 2025
30 checks passed
@bendrucker
Copy link
Contributor Author

Yeah you're right, I need to keep reading. The only thing I can think of is that the client is expecting an acknowledgement from the server of the denial. I've opened #3772 with half-working code and some notes for discussion. Really an issue with illustrative code attached right now, not close to reviewable/mergeable. If you want to dig further/comment, I'm certainly interested, but otherwise will spend some more time validating the client-side behavior and getting the PR to a reviewable state.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants