feat: align provider and agent behavior with Pi - #106
Merged
Conversation
Port the constrained-sampling behavior from Pi PR #6341, including strict schemas, native grammar tools, custom tool streaming and replay, and provider capability metadata.
Lock in the capture, versioned text-signature encoding, and replay behavior from Pi commit 87d71380.
Port Pi output_index slot routing and terminal reasoning signature backfill from 8c9dbffa and 1f0dbc00. Preserve Pi terminal item precedence and add interleaving, replay, and abort regression coverage.
Port Pi d9f7f814 and bc41f612 for unique cross-API tool IDs and tool-result cache anchors. Port Pi 351efc82 and daab056a so length-truncated calls are not executed and settled tools ignore late progress updates. Mirror the upstream regression scenarios, including parallel late updates.
Ports the applicable agent-loop portion of Pi commit 2fd3868401f0fe79496f3df731b20348ba57538a, including usage observation and replacement in after_tool_call plus transcript serialization.
Ports Pi commit 9ccfcd7cfcacdf593c0b24929d1d847e6cdf6711 by honoring an explicit null off entry in the model thinking-level map.
Ports Pi commit b9bfa7ed46ef19f48991473eae202be768623702 so explicit OpenRouter-compatible routing is forwarded by custom providers without URL detection.
Ports Pi commit 7d0497fdb752a05a9327864951ae7d6fcc4a9617 by buffering encrypted reasoning details until their matching streamed tool call arrives.
Ports the supported-provider portion of Pi commit 7f29e7a3697dc77416818faea4f4af29a13ce079, including request-scoped PI_CACHE_RETENTION precedence for Responses, Chat Completions, and Anthropic.
Ports Pi commit 2d597f0212145c9e4b8d6f66d85349e5e2cb86a4 by normalizing completed message items with null content to empty text.
Ports Pi commit 64b51efb6ef6f1e42676e866da906a5f900e592d so Z.AI uses thinking.type while Qwen retains enable_thinking.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
ai.rsis the Rust port of Pi's AI/provider layer, but the Rust implementation had fallen behind Pi in several behaviors that matter to tool-using agents and downstream consumers such as aiproxy. The largest gaps were native constrained sampling, OpenAI Responses history fidelity, streamed output routing, deferred tool loading, provider-specific reasoning replay, and agent-loop handling around tool execution.This PR brings the providers and agent loop already supported by
ai.rsback in line with Pi. Pi is treated as the behavioral source of truth: the Rust code follows Pi's wire shapes, control flow, compatibility flags, and regression cases as closely as Rust and the existing public API permit.AGENTS.mdnow records that rule for future ports.Scope
The port covers the provider surfaces and agent loop that already exist in
ai.rs:ai.rsagent loopIt does not add unrelated Pi providers or downstream aiproxy-specific behavior.
Constrained sampling and tool definitions
constrainedSamplingsupport toToolfalse, strict JSON-schema sampling, and native grammar samplingpreferversusrequirebehavior when strict schemas are unavailablecrates/ai/README.mdThis is based on the behavior introduced by Pi PR #6341.
OpenAI Responses
customtool definitions for supported grammar toolscustom_tool_callinput and replays it ascustom_tool_call/custom_tool_call_outputhistoryToolCall.argumentsrepresentation consistent between native grammar tools and function-tool fallbackoutput_index, including interleaved output itemsresponse.output_item.donedata as authoritative and backfills terminal reasoningencrypted_contentwhen necessaryphaseacross turns with versioned text signatures, matching Pi commit87d7138tool_choice,service_tier, prompt-cache controls, and reasoning controls using Pi-compatible wire shapesOpenAI Chat Completions and compatible providers
finish_reasonfailures and reports streams that end without a terminal finish reasonAnthropic Messages
tool_referenceloadingoffentry in the model thinking-level mapmessage_startwhen a latermessage_deltaomits usageAgent loop and shared types
ToolResultMessage, exposes it toafter_tool_call, and allows the hook to replace itaddedToolNameson tool results so tool definitions become available from the correct transcript point onwardProvider-scoped configuration and authentication
PI_CACHE_RETENTIONconsistently across Responses, Chat Completions, and AnthropicAuthorization,x-api-key, orcf-aig-authorizationheaders where the matching Pi provider allows header-only authenticationGitHub Copilot parity
authorization_pending,slow_down, expiry, and cancellation handlingGET /models, stores their IDs with the credentials, and filters the configured model catalog accordinglyUser-Agent: GitHubCopilotChat/0.35.0Editor-Version: vscode/1.107.0Editor-Plugin-Version: copilot-chat/0.35.0Copilot-Integration-Id: vscode-chatX-GitHub-Api-Version: 2026-06-01for model discoveryX-Initiator,Openai-Intent: conversation-edits, andCopilot-Vision-Request: truewhen appropriateCopilot model policy enablement is intentionally not included.
ai.rsdoes not maintain a hard-coded model-ID policy list or callPOST /models/{id}/policy; consumers can add that policy if they need it.Compatibility and public API additions
The main data-model additions are:
ConstrainedSampling,ConstrainedSamplingConfig,ConstrainedSamplingStrict, and grammar variantsProviderEnvToolResultMessage.usageandToolResultMessage.added_tool_namesExisting ordinary function tools continue to work without opting into constrained sampling. Provider-specific features remain capability-gated.
Verification
mise run fmtmise run checkmise run clippymise run test-ai— 517 tests passedBuild and Testpassedsimple-coding-agentexample successfully completed a real coding interaction against this branchai.rscheckout:cargo check --workspacepassedaiproxy-http: 77 tests passedaiproxy-core: 49 tests passedaiproxy-cli: 55 tests passedcodex execthrough aiproxy exercised a native grammar/custom tool, replayed its output into the next Responses request, and continued inference successfullycollaboration.wait_agent, and returned the child result; the namespace/encryption compatibility fix for that final wire boundary is in aiproxy PR #57, not inai.rs