LLM Client
The MCL LLM client provides a provider-agnostic interface for calling language models. It supports 6 providers, 3 API shapes, grammar-constrained decoding, streaming, and a 4-tier model router.
The MCL LLM client provides a provider-agnostic interface for calling language models. It supports 6 providers, 3 API shapes, grammar-constrained decoding, streaming, and a 4-tier model router with step-kind sub-routing.
Source files: llm/llm.go, llm/messages_api.go, llm/responses_api.go, llm/model.go, llm/identity.go.
Providers
| Provider | Env var | Endpoint | Models |
|---|---|---|---|
| Together AI | TOGETHER_API_KEY | api.together.xyz | DeepSeek, GPT-OSS |
| Fireworks AI | FIREWORKS_API_KEY | api.fireworks.ai | DeepSeek, Fireworks models |
| OpenCode | OPENCODE_API_KEY | opencode.ai/zen | Claude, GPT-5+ (proxy) |
| Baseten | BASETEN_API_KEY | inference.baseten.co | Kimi, open models |
| xAI | XAI_API_KEY | api.x.ai | Grok models |
| Xiaomi | XIAOMI_API_KEY | api.xiaomimimo.com | MiMo models |
Provider auto-detection is based on the model string. Callers can override with Config.Provider.
API shapes
The client supports three wire formats, auto-detected from the endpoint URL suffix:
| Shape | URL suffix | Request schema | Response schema |
|---|---|---|---|
| Chat Completions | /v1/chat/completions | OpenAI chat format | choices[0].message.content |
| Messages | /v1/messages | Anthropic Messages format | content[].text |
| Responses | /v1/responses | OpenAI Responses format | output[].content[].text |
func DetectAPIShape(endpoint string) APIShape {
// /v1/messages -> ShapeMessages
// /v1/responses -> ShapeResponses
// /v1/chat/completions -> ShapeChatCompletions
}
All three shapes implement interpreter.LLM and interpreter.StreamingLLM.
Config
type Config struct {
Model string // provider-specific model ID
Provider Provider // override auto-detection
APIKey string // override env var lookup
Endpoint string // override provider default
Temperature float64 // 0 = deterministic (compiler default)
Seed int64 // D11 seed; 0 = no seed param
MaxTokens int // default 8192
EnableThinking bool // extended reasoning toggle
Timeout time.Duration // default 90s
GrammarMode GrammarMode // None, JSONSchema, or EBNF
Grammars map[string]*GrammarDef // grammar ID -> schema/EBNF
InjectIdentity bool // prepend IdentityPreamble (Forge)
Shape APIShape // force API shape (auto-detect if zero)
// Gateway routing fields (sess#32)
GatewayURL string
ActorDID string
IntentID string
SlotLabel string
KindRoute string
OnResponseHeaders func(http.Header)
}
Grammar-constrained decoding
| Mode | Description | Providers |
|---|---|---|
GrammarNone | Free-form generation | All |
GrammarJSONSchema | response_format with JSON schema | Together, Fireworks, all chat-completions |
GrammarEBNF | EBNF grammar constraint | Fireworks only |
The compiler slot uses GrammarJSONSchema with the intent_frame@1 grammar so the model can only emit valid Frame JSON.
Model router (Session 31a)
The model router is a 4-tier system with step-kind sub-routing for the executor tier:
Tiers
| Slot | Purpose | Default model |
|---|---|---|
SlotCompiler | Verb classify + frame extract. Small, grammar-constrained, seeded. Sub-second target. | MiMo-v2.5-Pro |
SlotPlanner | PlanTree synthesis. Medium, grammar-aware, recursive $defs. | MiMo-v2.5-Pro |
SlotExecutor | Step decode + gate generation. Agentic, kind-routed. | MiMo-v2.5-Pro |
SlotLiaison | User-facing conversational narrator. Side-channel, never replayed. | MiMo-v2.5-Pro |
Executor step kinds
| Kind | Purpose | Default model |
|---|---|---|
reason | Default agentic step (long-horizon loops) | MiMo-v2.5-Pro |
code | Code generation specialist | MiMo-v2.5-Pro |
summarize | Long-context summarization | MiMo-v2.5-Pro |
write | Free-form prose / creative copy | MiMo-v2.5-Pro |
transform | Structured in -> structured out, deterministic | MiMo-v2.5-Pro |
classify | Pick-from-list with grammar | MiMo-v2.5-Pro |
hard_reason | Opt-in frontier reasoning (expensive) | MiMo-v2.5-Pro |
ModelRegistry
type ModelRegistry struct { ... }
func NewModelRegistry(fallback Config) *ModelRegistry
func (r *ModelRegistry) Register(k RouteKey, cfg Config) *ModelRegistry
func (r *ModelRegistry) Resolve(k RouteKey) Config
The registry resolves (Slot, Kind, LongCtx) to a Config. LongCtx variants are preferred when LongCtx=true is set; unknown executor kinds fall back to KindReason.
RouteKey
type RouteKey struct {
Slot ModelSlot
Kind StepKind
LongCtx bool
}
Kind is only meaningful when Slot == SlotExecutor. For other slots, it is ignored.
Identity injection (Forge Phase 1)
When Config.InjectIdentity is true, the IdentityPreamble is prepended as the first system message at every Decode and Stream call:
You are Matrix -- an agent framework for LLM execution.
Your codebase lives at /root/matrix. This conversation is part of your
ongoing self-maintenance. Every action you take should serve improving
Matrix itself.
The IdentityVersion constant ("matrix-identity-v1") is mixed into model digest computation so the compile-cache invalidates cleanly across preamble migrations.
Streaming
All three API shapes implement interpreter.StreamingLLM:
type StreamingLLM interface {
Stream(ctx context.Context, messages []Message, grammar string,
onDelta func(delta string)) (string, error)
}
Each shape parses its provider's SSE event format:
| Shape | Text delta event | End event |
|---|---|---|
| Chat Completions | choices[0].delta.content | data: [DONE] |
| Messages | content_block_delta with delta.type=text_delta | message_stop |
| Responses | response.output_text.delta with top-level delta string | response.completed |
Gateway routing (sess#32)
When GatewayURL is set, all requests are routed through the Matrix Gateway. The client stamps X-Matrix-Actor-DID, X-Matrix-Intent-ID, X-Matrix-Slot, and X-Matrix-Kind-Route headers so the gateway can authenticate the actor, route against per-slot whitelists, and track costs. Cost telemetry flows back via X-Matrix-Cost-Pax / Daily-Spent / Daily-Remaining response trailers captured by OnResponseHeaders.
