Skip to content

Make canonical tools provider-agnostic and keep their identity - #14

Merged
rokoss21 merged 1 commit into
masterfrom
fix/canonical-tool-identity
Aug 21, 2026
Merged

Make canonical tools provider-agnostic and keep their identity#14
rokoss21 merged 1 commit into
masterfrom
fix/canonical-tool-identity

Conversation

@rokoss21

Copy link
Copy Markdown
Owner

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:

@interface WeatherAPI
  fn get(city: string) -> string (effect="read")

@interface StockAPI
  fn get(ticker: string) -> string (effect="read")

produced two entries in canonical.tools both named get. Policy matches on the canonical Interface.fn form (§16.2.6), so with WeatherAPI.get allowed and StockAPI.get denied, an incoming get call has no honest mapping — and the allow rule would answer for the call the deny rule was written for.

Change

canonical.tools entries 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 in scripts/spec_matrix_examples.sh and the renderer tests.

Verification

  • new regression test builds the colliding-interfaces contract and asserts both WeatherAPI.get and StockAPI.get appear, in Resolved Source Form order, with no vendor wrapper
  • 490 tests, smoke, matrix, doc-examples all green; coverage 57 → 60

🤖 Generated with Claude Code

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>
@rokoss21
rokoss21 merged commit 17fa15f into master Aug 21, 2026
14 checks passed
@rokoss21
rokoss21 deleted the fix/canonical-tool-identity branch August 21, 2026 22:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant