Make canonical tools provider-agnostic and keep their identity - #14
Merged
Conversation
Writing the first provider adapter surfaced two problems in the object
the adapter is supposed to translate.
The canonical payload carried OpenAI's tool envelope. The struct in the
renderer was documented as "following OpenAI function calling format",
inside the object §18.1 defines as provider-agnostic and §18 positions
as the boundary between FACET and any vendor. An adapter written against
that is not translating a neutral form, it is reshaping one vendor's
form into another's.
Worse, the tool name was the bare function name. Two interfaces each
declaring `get` produced two entries both called `get`: indistinguishable
in the payload, and unattributable when the model calls one. Policy
matches on the canonical `Interface.fn` form (§16.2.6), so with
`WeatherAPI.get` allowed and `StockAPI.get` denied, an incoming `get`
has no honest mapping — and the allow rule would answer for the call the
deny rule was written for.
`canonical.tools` is now `{ name, description, parameters }` with the
name in canonical identifier form. Providers that restrict tool names to
`[A-Za-z0-9_-]` — which is most of them — must mangle it and map back
before the guard sees the call; that is an adapter obligation, and it is
only expressible because the canonical name survives to the boundary.
This is a breaking change to `canonical.tools` for anything parsing the
payload, recorded as such in the changelog.
Coverage rises to 60 of 206.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Prerequisite for ROADMAP item 3, found while starting the first adapter.
Two problems in the object the adapter translates
The canonical payload carried OpenAI's envelope. The struct in the renderer was literally documented as "Tool definition following OpenAI function calling format" — inside the object §18.1 defines as provider-agnostic and §18 positions as the boundary between FACET and any vendor. An adapter written against that isn't translating a neutral form; it's reshaping one vendor's form into another's.
The tool name was the bare function name. Two interfaces each declaring
get:produced two entries in
canonical.toolsboth namedget. Policy matches on the canonicalInterface.fnform (§16.2.6), so withWeatherAPI.getallowed andStockAPI.getdenied, an incominggetcall has no honest mapping — and the allow rule would answer for the call the deny rule was written for.Change
canonical.toolsentries are now:{ "name": "WeatherAPI.get", "description": "...", "parameters": { "type": "object", ... } }Providers that restrict tool names to
[A-Za-z0-9_-]— which is most of them — must mangle this and map back before the guard sees the call. That is an adapter obligation, and it is only expressible because the canonical name now survives to the boundary.Breaking for anything parsing
canonical.tools; recorded as such in the changelog. Updated inscripts/spec_matrix_examples.shand the renderer tests.Verification
WeatherAPI.getandStockAPI.getappear, in Resolved Source Form order, with no vendor wrapper🤖 Generated with Claude Code