symfonic.kernel.palette¶
palette ¶
Binding a turn's tool palette without recompiling the plan.
Lazy tool routing selects a subset of the palette from the turn's own input, so what the model is offered differs per turn. The plan binds tools once, at compile time, and is immutable by contract (IPL-4) — rebinding requires a new plan and there is no setter.
Both are kept. The projector is built at compile time, holds the unbound chat
model and the full palette, and hands back a model bound to whichever subset a
turn resolved. The plan's identity never moves: equality_key excludes
bindings, which is the same reason event_sink and stage_handlers live
there — a reference frozen at compile time whose behaviour stays live.
Cached by palette identity, not by turn. Two turns that resolve the same subset share one bound model, and a provider that charges for binding pays once. The identity is the sorted tool names, so it is stable under a resolver that returns the same set in a different order — which the procedural layer does, since it ranks.
None means the full palette and returns the binding the plan already
made, byte for byte. That is the no-router case and the disabled case, and it
must stay indistinguishable from the behaviour before this module existed.
PaletteProjector ¶
PaletteProjector(model: Any, tools: Any, bound: Any, *, wrap: Any = None, forcing: Any = None, bind_with: Any = None)
Binds the model to a subset of the compiled palette, on demand.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
Any
|
the unbound chat model, kept so a subset can be bound. |
required |
tools
|
Any
|
the compiled palette, in the order the plan holds it. |
required |
bound
|
Any
|
what the plan already bound and the caller already calls -- the adapter, not the raw model. Returned verbatim for the full palette so the unrouted path is not merely equivalent to the previous behaviour but identical to it. |
required |
wrap
|
Any
|
turns a freshly bound model into the same shape as |
None
|
Source code in src/symfonic/kernel/palette.py
tools
property
¶
The compiled palette, for a caller checking a force against it.
bind ¶
The model to call this turn, for the palette selected and required.
names of None — no router, a router that declined, or a
deployment with the feature off — is the full palette.
forced is bound as the provider's tool_choice. A forced turn
binds the full palette when nothing narrowed it, rather than
narrowing to the forced tool alone: forcing says which call must
happen, not which calls exist, and collapsing the palette would change
what the model is told it can do on the round after the force is spent.
Source code in src/symfonic/kernel/palette.py
model_for ¶
The model to call this turn, narrowed to a resolved palette if there is one.
Reads the snapshot rather than being told, because the resolution is a capability's contribution and the kernel's job is to honour what was contributed, not to know who contributed it.
Source code in src/symfonic/kernel/palette.py
palette_identity ¶
A stable key for one resolved palette.
Sorted, because a resolver that ranks returns the same set in different orders and two orders of one palette must not bind twice.
forced is part of the identity, not a detail beside it: the same tools
bound with and without a required choice are two different bindings, and
sharing a cache entry between them would hand a forced turn the model an
unforced turn had already bound.