feat: declare the Codex grammar through pi's constrainedSampling API - #43
Merged
code-yeongyu merged 2 commits intoOct 3, 2026
Merged
code-yeongyu merged 2 commits into
code-yeongyu merged 2 commits into
Conversation
zidou-kiyn
added a commit
to zidou-kiyn/pi-preset
that referenced
this pull request
Sep 30, 2026
…r status Explain why the preset ships no mcp.json or defaultTools now that MCP, codemode, and tool_search are built in, and why pi-apply-patch stays required: pi has no built-in apply_patch, and its grammar only reaches the model once code-yeongyu/pi-apply-patch#43 lands.
Owner
|
Thanks @zidou-kiyn, this is correct. I verified it against pi's own resolver at the pinned 0.87.1:
I pushed one maintainer commit (79af773):
I'll merge once CI is green on the new head. |
The freeform property on the tool definition is not read by pi, so apply_patch always went out as a plain JSON function tool, even on providers that support OpenAI grammar tools. Pi's public ToolDefinition.constrainedSampling hook takes grammar variants. Declaring the Codex Lark grammar there sends apply_patch as a native OpenAI custom tool whenever the model's provider sets compat.supportsOpenAIGrammarTools (pi's bundled OpenAI and OpenAI Codex catalogs do), and falls back to the function tool everywhere else. The freeform property is kept for existing consumers.
Replace the assertion that pinned the constrainedSampling object with tests that run pi's public resolver (@earendil-works/pi-ai/api/constrained-sampling): a provider with OpenAI grammar tools gets the Codex Lark grammar bound to the 'input' parameter, and any other provider keeps the plain function tool. Add the CHANGELOG entry.
code-yeongyu
force-pushed
the
feat/constrained-sampling-grammar
branch
from
October 3, 2026 12:35
79af773 to
8f70b80
Compare
Owner
|
Merged as f327003, with you credited as co-author and in the CHANGELOG. Thanks @zidou-kiyn: plain pi now sends apply_patch as a real grammar tool on providers that support it. |
Merged
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.
Problem
createApplyPatchTool()attaches the Codex Lark grammar as afreeformproperty, but pi never reads that property. The provider request therefore always declaresapply_patchas a plain JSON function tool, even for GPT models on providers that support OpenAI grammar tools.Observed with pi 0.99.1,
gpt-6.1-sol, and a Responses provider withcompat.supportsOpenAIGrammarTools: true: the payload inbefore_provider_requestcontains{ "type": "function", "name": "apply_patch" }.Fix
Pi's public
ToolDefinition.constrainedSamplinghook accepts grammar variants (it is in the pinned 0.87.1 devDependency). This PR declares the existing grammar there:compat.supportsOpenAIGrammarTools(pi's bundledopenaiandopenai-codexcatalogs set it for GPT models), pi sendsapply_patchas a native custom tool withformat: { type: "grammar", syntax: "lark" }. pi maps the raw custom-tool input back to the singleinputparameter, soexecuteis unchanged.freeformproperty is kept for existing consumers. The grammar, description, and schema are byte-for-byte unchanged.Verification
bun run checkandbun run testpass (61 tests). The registration test now also assertsconstrainedSampling.pi -p -ne -e ./src/index.tson pi 0.99.1 +gpt-6.1-sol: all three requests declaredcustom:apply_patch (grammar), both patches (add file, then update line) applied, and every response was 200.Note, not changed here
pi 0.99 prints on every start:
Host-provided extension packages must be declared in peerDependencies with a "*" range, not dependencies: typebox. #40 movedtypeboxintodependencieson purpose for hosts that install with peer resolution disabled, so this PR leaves it alone. Flagging it in case you want to revisit that trade-off.