Documentation
¶
Overview ¶
Schema and loader for the _experts.yml manifest.
The ExpertsManifest struct owns the `experts:` block. Consumers that need additional top-level keys (jumalu's `graphs:`) embed this struct and add their own fields; yaml.v3 inlines anonymous embedded structs, so a single YAML file is decoded into the merged schema without a custom unmarshaler.
Shared JSON POST transport for every non-streaming LLM provider call. Marshal, POST, status classification, body read, unmarshal — one place.
Providers supply URL, headers, body, client, and codec. They do not repeat the boilerplate. Streaming stays in sse.go and the provider Stream methods; this helper is for the request/response cycle only.
ai/llm/observe.go
Ollama does not use SSE. Its /api/chat stream is newline-delimited JSON, terminated by a `done:true` field inside the last line. Its streaming reader therefore stays local to this file and is not routed through StreamSSE.
SSE parsing skeleton. The four streaming providers (OpenAI-compatible, DeepSeek-via-OpenAI, Anthropic, Gemini) differ only in the JSON shape of a single `data:` frame. The reader loop, the [DONE] terminator, the context check, and the close-on-exit all live here.
Ollama does not use this file — it streams newline-delimited JSON, not SSE. Its reader stays local to ollama.go.
Index ¶
- Constants
- Variables
- func BuildMoEAdminActions(cfg MoEAdminConfig) []action.AnyAction
- func BuildMoEExperts(manifest *ExpertsManifest) (map[string]Provider, error)
- func CalculateCost(model string, promptTokens, cachedTokens, compTokens int, at time.Time) (cost.Micro, cost.Currency, bool)
- func DecodeAnthropicChunk(data []byte) (text string, done bool, err error)
- func DecodeGeminiChunk(data []byte) (text string, done bool, err error)
- func DecodeOpenAIChunk(data []byte) (text string, done bool, err error)
- func DoJSON[Res any](ctx context.Context, r HTTPRequest) (Res, error)
- func FetchModels(ctx context.Context, providerType, apiKey, baseURL string) ([]string, error)
- func FromHTTPStatus(status int, body []byte, providerName string) error
- func InitPricingFile(filePath string, force bool) (string, error)
- func IsKnownProvider(name string) bool
- func IsLoaded(ctx context.Context, p Provider, model string) bool
- func KnownProviders() []string
- func NewNode(id, _ string, p Provider, systemPrompt, userPromptTmpl string) action.AnyAction
- func NewStructuredNode[T any](id, _ string, p Provider, systemPrompt, userPromptTmpl string) action.AnyAction
- func NewTypedNode[Res any](name string, provider Provider, defaultSystem string) action.AnyAction
- func ParseOpenAISSEStream(ctx context.Context, body io.ReadCloser) iter.Seq2[string, error]
- func Preload(ctx context.Context, p Provider, model string) error
- func ProviderAction(name string, p Provider) *action.Builder[Request, Response]
- func ResolveConfigPath(flag, envKey string, defaults ...string) (string, error)
- func StreamSSE(ctx context.Context, body io.ReadCloser, decode SSEChunkDecoder) iter.Seq2[string, error]
- func Unload(ctx context.Context, p Provider, model string) error
- type AnthropicProvider
- type Config
- type DeepSeekProvider
- type Embedder
- type ExpertProviderConfig
- type ExpertSpec
- type ExpertsManifest
- type FallbackConfig
- type FallbackError
- type FallbackInfo
- type FallbackProvider
- type FunctionCall
- type FunctionSpec
- type GeminiProvider
- type HTTPRequest
- type Message
- type MoEAdminConfig
- type MoEModelsReq
- type MoEModelsRes
- type MoEProvider
- func (m *MoEProvider) Complete(ctx context.Context, req Request) (Response, error)
- func (m *MoEProvider) IsLoaded(ctx context.Context, _ string) bool
- func (m *MoEProvider) Name() string
- func (m *MoEProvider) Preload(ctx context.Context, _ string) error
- func (m *MoEProvider) RegisterExpert(expertName string, p Provider) *MoEProvider
- func (m *MoEProvider) Stream(ctx context.Context, req Request) (iter.Seq2[string, error], error)
- func (m *MoEProvider) Unload(ctx context.Context, _ string) error
- type MoEReloadRes
- type MoEStatsRes
- type ModelManager
- type ObservableProvider
- type OffPeakWindow
- type OllamaProvider
- func (p *OllamaProvider) Complete(ctx context.Context, req Request) (Response, error)
- func (p *OllamaProvider) IsLoaded(ctx context.Context, model string) bool
- func (p *OllamaProvider) Name() string
- func (p *OllamaProvider) Preload(ctx context.Context, model string) error
- func (p *OllamaProvider) Stream(ctx context.Context, req Request) (iter.Seq2[string, error], error)
- func (p *OllamaProvider) Unload(ctx context.Context, model string) error
- type OpenAIProvider
- type Price
- type PriceCard
- type PriceCatalog
- func (c *PriceCatalog) Get(model string) (PriceCard, bool)
- func (c *PriceCatalog) IsOffPeak(t time.Time) bool
- func (c *PriceCatalog) LoadFromFile(filePath string) error
- func (c *PriceCatalog) LoadFromURL(ctx context.Context, url string) error
- func (c *PriceCatalog) LoadFromYAML(data []byte) error
- func (c *PriceCatalog) Models() []string
- func (c *PriceCatalog) Register(model string, card PriceCard)
- type Provider
- type ProviderChain
- type ProviderPreset
- type ProviderTrace
- type Request
- type Response
- type Role
- type RouterSink
- type SSEChunkDecoder
- type SinkStats
- type StreamEvent
- type StreamEventKind
- type StreamSink
- type TieredModelRouter
- type TokenEstimator
- type ToolCall
- type ToolSpec
- type TypedReq
- type Usage
Constants ¶
const DefaultPricingTemplate = `` /* 1638-byte string literal not displayed */
DefaultPricingTemplate is loaded by NewPriceCatalog at process start.
⚠️ The numbers below are placeholders for any field you have not verified against the provider's published rate card. Only the fields that were already present in this repository before M1.5 have been preserved verbatim; every new field (prompt_cache_hit_per_1k, off_peak, currency) is a zero or a commented hint.
To make cost reporting trustworthy:
- Edit the YAML below, or ship a pricing.yml and call GlobalCatalog.LoadFromFile("pricing.yml") at startup.
- Model names must match exactly what the provider returns in the `model` field of its response. `deepseek-flash` is not a real DeepSeek model name — verify what you actually receive and align.
- Every new model you support must appear here, or CalculateCost returns ok=false and the runner shows `-` in the cost column.
Variables ¶
var GlobalCatalog = NewPriceCatalog()
GlobalCatalog is the default catalog used by CalculateCost and by every provider that builds a Response.
var Presets = map[string]ProviderPreset{ "groq": { Name: "groq", DefaultURL: "https://api.groq.com/openai/v1", DefaultModel: "llama-3.1-8b-instant", EnvKeyNames: []string{"GROQ_API_KEY"}, }, "nim": { Name: "nim", DefaultURL: "http://localhost:8000/v1", DefaultModel: "meta/llama-3.3-70b-instruct", EnvKeyNames: []string{"NVIDIA_API_KEY", "NVIDIA_NIM_API_KEY"}, }, "vllm": { Name: "vllm", DefaultURL: "http://localhost:8000/v1", DefaultModel: "default", EnvKeyNames: []string{"VLLM_API_KEY"}, }, // contains filtered or unexported fields }
Functions ¶
func BuildMoEAdminActions ¶
func BuildMoEAdminActions(cfg MoEAdminConfig) []action.AnyAction
func BuildMoEExperts ¶
func BuildMoEExperts(manifest *ExpertsManifest) (map[string]Provider, error)
BuildMoEExperts constructs the named Provider map from a manifest.
Side effect: registers per-model pricing into GlobalCatalog so the cost accounting layer has rates available before the first call. A model with zero rates is registered with zeros — callers that require pricing should populate prompt_price_1k and completion_price_1k in the manifest.
When an expert declares more than one provider, the returned provider is a ProviderChain composed in declaration order. The chain inherits the default fallback policy (xerr.IsTransient) and no observer.
The graph compilation layer (jumalu) is expected to walk its own `graphs:` block after this call returns. This function does not compile or execute anything.
func CalculateCost ¶
func CalculateCost( model string, promptTokens, cachedTokens, compTokens int, at time.Time, ) (cost.Micro, cost.Currency, bool)
CalculateCost returns the cost of one LLM turn.
model the model identifier as reported by the provider
promptTokens total input tokens (cached + miss)
cachedTokens the portion of promptTokens that hit the prompt cache.
Pass 0 when the provider does not report cache hits.
compTokens output tokens
at the time of the call, used to select peak vs off-peak
Returns (micros, currency, ok). When ok is false the model has no rate card — the caller should treat cost as unknown, not zero.
func DecodeAnthropicChunk ¶
DecodeAnthropicChunk handles content_block_delta and message_stop.
func DecodeGeminiChunk ¶
DecodeGeminiChunk handles the candidates/parts/text shape. Multiple parts in a single frame are concatenated; the caller sees one fragment per frame.
func DecodeOpenAIChunk ¶
DecodeOpenAIChunk handles the OpenAI / DeepSeek / Groq / most OpenAI-compatible SSE delta shape.
func DoJSON ¶
func DoJSON[Res any](ctx context.Context, r HTTPRequest) (Res, error)
DoJSON performs a JSON POST, decodes the JSON response into Res, and maps non-2xx status codes through FromHTTPStatus. The function is the single HTTP entry point for every OpenAI-compatible, Anthropic, and Ollama non-streaming request.
func FetchModels ¶
FetchModels queries an upstream provider for its active model catalog.
func FromHTTPStatus ¶
FromHTTPStatus maps an upstream HTTP response into the kernel error taxonomy. Body markers are inspected before falling through to the status-based default, because OpenAI-compatible providers wrap transient conditions inside 400 responses.
func InitPricingFile ¶
InitPricingFile writes the default template to disk.
func IsKnownProvider ¶
IsKnownProvider reports whether a provider name is present in the preset catalog. It is used by the @llm directive to reject misspelled provider names at compile time.
func KnownProviders ¶
func KnownProviders() []string
KnownProviders returns every provider name accepted by IsKnownProvider, sorted for stable error messages.
func NewStructuredNode ¶
func NewTypedNode ¶
func NewTypedNode[Res any]( name string, provider Provider, defaultSystem string, ) action.AnyAction
NewTypedNode returns an action that:
- Sends {system, user} to the provider with JSONMode enabled.
- Decodes the model's reply into Res.
- Returns Res as the action output.
This is the single primitive that lets every ai/* subsystem drop its own hand-rolled "prompt → call → unmarshal" boilerplate and keep only the DTO. The heavy lifting (structured output enforcement, JSON decoding, error normalisation) lives in exactly one place.
The name is required and becomes the action's registry identity (e.g. "ai.structured.review_report"). Callers typically pass a fully qualified name so the .nflow file can reference it directly.
func ParseOpenAISSEStream ¶
ParseOpenAISSEStream parses an OpenAI-compatible SSE body into a standard iter.Seq2 iterator.
func ProviderAction ¶
func ResolveConfigPath ¶
ResolveConfigPath applies the standard fail-fast resolution chain: flag wins, then env, then the first existing default. An explicit override that points to a missing file is a hard error.
func StreamSSE ¶
func StreamSSE(ctx context.Context, body io.ReadCloser, decode SSEChunkDecoder) iter.Seq2[string, error]
StreamSSE reads an SSE body line by line and calls decode on every `data:` payload. The function owns the reader lifecycle: it closes body on exit, checks ctx on every iteration, and stops on [DONE] or on the first decoder that returns done=true.
Types ¶
type AnthropicProvider ¶
type AnthropicProvider struct {
// contains filtered or unexported fields
}
func NewAnthropic ¶
func NewAnthropic(cfg Config) *AnthropicProvider
func (*AnthropicProvider) Name ¶
func (p *AnthropicProvider) Name() string
type Config ¶
type Config struct {
Name string `json:"name,omitempty" yaml:"name,omitempty"`
BaseURL string `json:"base_url,omitempty" yaml:"base_url,omitempty"`
APIKey string `json:"api_key,omitempty" yaml:"api_key,omitempty"`
DefaultModel string `json:"default_model,omitempty" yaml:"default_model,omitempty"`
Timeout time.Duration `json:"timeout,omitempty" yaml:"timeout,omitempty"`
MaxRetries int `json:"max_retries,omitempty" yaml:"max_retries,omitempty"`
}
type DeepSeekProvider ¶
type DeepSeekProvider struct {
// contains filtered or unexported fields
}
func NewDeepSeek ¶
func NewDeepSeek(cfg Config) *DeepSeekProvider
func (*DeepSeekProvider) Name ¶
func (p *DeepSeekProvider) Name() string
type Embedder ¶
func NewEmbedder ¶
NewEmbedder creates an embedding generator compatible with OpenAI, OpenRouter, and Ollama.
type ExpertProviderConfig ¶
type ExpertProviderConfig struct {
Provider string `json:"provider" yaml:"provider"`
Model string `json:"model" yaml:"model"`
Temperature float64 `json:"temperature,omitempty" yaml:"temperature,omitempty"`
MaxTokens int `json:"max_tokens,omitempty" yaml:"max_tokens,omitempty"`
TimeoutMS int64 `json:"timeout_ms,omitempty" yaml:"timeout_ms,omitempty"`
SystemPrefix string `json:"system_prefix,omitempty" yaml:"system_prefix,omitempty"`
PromptPrice1k float64 `json:"prompt_price_1k,omitempty" yaml:"prompt_price_1k,omitempty"`
CompletionPrice1k float64 `json:"completion_price_1k,omitempty" yaml:"completion_price_1k,omitempty"`
}
ExpertProviderConfig is the per-provider entry under an expert.
TimeoutMS accepts both the current `timeout_ms:` YAML key and the historical `timeoutms:` key. The legacy form exists because an earlier loader carried the field with no yaml tag, making the literal lowercased Go field name the effective YAML key. Both forms are decoded; the canonical form wins if both are present.
func (*ExpertProviderConfig) UnmarshalYAML ¶
func (c *ExpertProviderConfig) UnmarshalYAML(value *yaml.Node) error
UnmarshalYAML decodes both `timeout_ms` and the legacy `timeoutms` key. Everything else uses the default yaml.v3 behavior via a shadow struct.
type ExpertSpec ¶
type ExpertSpec struct {
Key string `json:"key" yaml:"key"`
Name string `json:"name" yaml:"name"`
Description string `json:"description" yaml:"description"`
Keywords []string `json:"keywords" yaml:"keywords"`
Providers []ExpertProviderConfig `json:"providers" yaml:"providers"`
}
ExpertSpec is a single named expert entry.
type ExpertsManifest ¶
type ExpertsManifest struct {
Experts map[string]ExpertSpec `json:"experts" yaml:"experts"`
}
ExpertsManifest is the shared top-level shape of an _experts.yml.
Consumers that need additional top-level keys should embed this struct anonymously; yaml.v3 will inline the embedded fields.
func LoadExpertsFile ¶
func LoadExpertsFile(filePath string) (*ExpertsManifest, error)
func LoadExpertsManifest ¶
func LoadExpertsManifest(data []byte) (*ExpertsManifest, error)
func (*ExpertsManifest) MatchExpertByKeywords ¶
func (m *ExpertsManifest) MatchExpertByKeywords(query string) string
MatchExpertByKeywords returns the first expert whose keyword list contains a case-insensitive substring of query. Returns "general" when nothing matches or the manifest is empty.
type FallbackConfig ¶
type FallbackConfig struct {
ShouldFallback func(error) bool
Transform func(Request) Request
OnFallback func(context.Context, FallbackInfo) error
}
FallbackConfig controls provider failover conditions and request transforms.
type FallbackError ¶
FallbackError wraps primary and secondary errors for errors.Is / errors.As matching.
func (*FallbackError) Error ¶
func (e *FallbackError) Error() string
func (*FallbackError) Unwrap ¶
func (e *FallbackError) Unwrap() []error
type FallbackInfo ¶
FallbackInfo captures primary-to-secondary provider transition context.
type FallbackProvider ¶
type FallbackProvider struct {
// contains filtered or unexported fields
}
FallbackProvider executes secondary provider on transient primary failure.
func NewFallbackProvider ¶
func NewFallbackProvider(primary, secondary Provider, cfg FallbackConfig) *FallbackProvider
func (*FallbackProvider) Name ¶
func (p *FallbackProvider) Name() string
type FunctionCall ¶
type FunctionSpec ¶
type GeminiProvider ¶
type GeminiProvider struct {
// contains filtered or unexported fields
}
func NewGemini ¶
func NewGemini(cfg Config) *GeminiProvider
func (*GeminiProvider) Name ¶
func (p *GeminiProvider) Name() string
type HTTPRequest ¶
type HTTPRequest struct {
URL string
Headers map[string]string
Body any
Client *http.Client
Codec codec.Codec
ProviderName string
}
HTTPRequest is the input to DoJSON. ProviderName is used only in error messages produced by FromHTTPStatus; leave empty to omit the prefix.
type MoEAdminConfig ¶
type MoEAdminConfig struct {
Sink *RouterSink
ReloadFunc func(context.Context) (int, error)
KnownProviders []string
}
MoEAdminConfig wires the MoE admin surface to a RouterSink and a manifest reload callback supplied by the caller.
type MoEModelsReq ¶
type MoEModelsRes ¶
type MoEProvider ¶
type MoEProvider struct {
// contains filtered or unexported fields
}
func BuildMoEFromManifest ¶
func BuildMoEFromManifest(manifest *ExpertsManifest, defaultProvider Provider) (*MoEProvider, error)
BuildMoEFromManifest is the legacy entry point. It wraps the expert map into a MoEProvider for callers that want a single routing provider.
New callers should prefer BuildMoEExperts and construct their own router (TieredModelRouter, ProviderChain, or a custom dispatcher).
func NewMoE ¶
func NewMoE(name string, defaultProvider Provider) *MoEProvider
func (*MoEProvider) Name ¶
func (m *MoEProvider) Name() string
func (*MoEProvider) RegisterExpert ¶
func (m *MoEProvider) RegisterExpert(expertName string, p Provider) *MoEProvider
type MoEReloadRes ¶
type MoEReloadRes struct {
Experts int `json:"experts_reloaded"`
}
type MoEStatsRes ¶
type ModelManager ¶
type ObservableProvider ¶
type ObservableProvider struct {
// contains filtered or unexported fields
}
ObservableProvider wraps any Provider and fires a ProviderTrace around every Complete call. Stream is not traced; use the runner's stream events for streaming observability.
func (*ObservableProvider) Name ¶
func (p *ObservableProvider) Name() string
type OffPeakWindow ¶
type OffPeakWindow struct {
StartUTC string `json:"start_utc" yaml:"start_utc"`
EndUTC string `json:"end_utc" yaml:"end_utc"`
}
OffPeakWindow is the daily UTC window during which the OffPeak rate card applies. The window may wrap midnight (e.g. 16:30 → 00:30).
type OllamaProvider ¶
type OllamaProvider struct {
// contains filtered or unexported fields
}
func NewOllama ¶
func NewOllama(cfg Config) *OllamaProvider
func (*OllamaProvider) IsLoaded ¶
func (p *OllamaProvider) IsLoaded(ctx context.Context, model string) bool
func (*OllamaProvider) Name ¶
func (p *OllamaProvider) Name() string
func (*OllamaProvider) Preload ¶
func (p *OllamaProvider) Preload(ctx context.Context, model string) error
type OpenAIProvider ¶
type OpenAIProvider struct {
// contains filtered or unexported fields
}
func NewOpenAI ¶
func NewOpenAI(cfg Config) *OpenAIProvider
func (*OpenAIProvider) Name ¶
func (p *OpenAIProvider) Name() string
type Price ¶
type Price struct {
PromptPer1k float64 `json:"prompt_per_1k" yaml:"prompt_per_1k"`
PromptCacheHit1k float64 `json:"prompt_cache_hit_per_1k" yaml:"prompt_cache_hit_per_1k"`
CompPer1k float64 `json:"comp_per_1k" yaml:"comp_per_1k"`
}
Price is a per-1000-token rate for one billing tier.
PromptPer1k cache-MISS input rate (the "expensive" input path)
PromptCacheHit1k cache-HIT input rate. Providers that do not offer
prompt caching should leave this equal to
PromptPer1k, or zero when the field is unused.
CompPer1k output rate
All values are in the currency declared by the enclosing PriceCard.
type PriceCard ¶
type PriceCard struct {
Currency cost.Currency `json:"currency" yaml:"currency"`
Peak Price `json:"peak" yaml:"peak"`
OffPeak *Price `json:"off_peak,omitempty" yaml:"off_peak,omitempty"`
}
PriceCard is the full rate card for one model in one currency.
Peak applied 24/7 unless OffPeak is set and the call happens
inside the catalog's OffPeakWindow.
OffPeak optional discounted rate card. Leave nil when the
provider does not differentiate by time-of-day.
Currency the currency in which Peak and OffPeak are denominated.
type PriceCatalog ¶
type PriceCatalog struct {
// contains filtered or unexported fields
}
PriceCatalog is the process-wide rate card registry. It is safe for concurrent readers and occasional writers (Register / reload).
func NewPriceCatalog ¶
func NewPriceCatalog() *PriceCatalog
NewPriceCatalog returns a catalog pre-populated from the built-in DefaultPricingTemplate. Callers may overwrite it with LoadFromFile, LoadFromURL, or LoadFromYAML.
func (*PriceCatalog) Get ¶
func (c *PriceCatalog) Get(model string) (PriceCard, bool)
Get returns the rate card for a model.
func (*PriceCatalog) IsOffPeak ¶
func (c *PriceCatalog) IsOffPeak(t time.Time) bool
IsOffPeak reports whether t falls inside the configured window. The window is UTC by contract.
func (*PriceCatalog) LoadFromFile ¶
func (c *PriceCatalog) LoadFromFile(filePath string) error
func (*PriceCatalog) LoadFromURL ¶
func (c *PriceCatalog) LoadFromURL(ctx context.Context, url string) error
func (*PriceCatalog) LoadFromYAML ¶
func (c *PriceCatalog) LoadFromYAML(data []byte) error
LoadFromYAML accepts two formats:
New (preferred):
currency: USD
window: { start_utc: "16:30", end_utc: "00:30" }
models:
deepseek-chat:
peak: { prompt_per_1k: 0.00027, prompt_cache_hit_per_1k: 0.00007, comp_per_1k: 0.00110 }
off_peak: { prompt_per_1k: 0.000135, prompt_cache_hit_per_1k: 0.000035, comp_per_1k: 0.00055 }
Legacy:
gpt-4o: { prompt_per_1k: 0.00250, comp_per_1k: 0.01000 }
The new shape wins when a `models:` key is present.
func (*PriceCatalog) Models ¶
func (c *PriceCatalog) Models() []string
Models returns a sorted list of every model that has a rate card. Useful for introspection and startup banners.
func (*PriceCatalog) Register ¶
func (c *PriceCatalog) Register(model string, card PriceCard)
Register installs or replaces a rate card for a model.
type Provider ¶
type Provider interface {
Name() string
Complete(ctx context.Context, req Request) (Response, error)
Stream(ctx context.Context, req Request) (iter.Seq2[string, error], error)
}
func NewObservableProvider ¶
func NewObservableProvider(inner Provider, emit ProviderTrace) Provider
NewObservableProvider returns inner wrapped with emit. If either inner or emit is nil the function returns inner unchanged, so callers can chain it unconditionally.
type ProviderChain ¶
type ProviderChain struct {
// contains filtered or unexported fields
}
func NewProviderChain ¶
func NewProviderChain(primary Provider, fallbacks ...Provider) *ProviderChain
func (*ProviderChain) Name ¶
func (c *ProviderChain) Name() string
type ProviderPreset ¶
type ProviderTrace ¶
type ProviderTrace func( kind, provider, model string, in, out int, costMicro int64, dur time.Duration, err error, )
ProviderTrace is the callback invoked by ObservableProvider around every completion attempt.
kind one of "start", "finish", "warn", "error"
provider the provider's Name() (e.g. "deepseek")
model the resolved model name; "auto" until known, then the
server-reported name from the response
in, out token counts (0 for "start" and "error")
costMicro cost in the currency's micro units (0 when unknown)
dur wall-clock time of the call (0 for "start")
err non-nil for "error" and "warn"
type Request ¶
type Request struct {
Model string `json:"model,omitempty"`
Messages []Message `json:"messages"`
Temperature float64 `json:"temperature,omitempty"`
MaxTokens int `json:"max_tokens,omitempty"`
JSONMode bool `json:"json_mode,omitempty"`
Tools []ToolSpec `json:"tools,omitempty"`
IncludeThinking bool `json:"include_thinking,omitempty"`
}
type Response ¶
type Response struct {
Content string `json:"content"`
ReasoningContent string `json:"reasoning_content,omitempty"`
Model string `json:"model"`
PromptTokens int `json:"prompt_tokens"`
CachedPromptTokens int `json:"cached_prompt_tokens,omitempty"`
CompTokens int `json:"completion_tokens"`
FinishReason string `json:"finish_reason,omitempty"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
Duration time.Duration `json:"duration,omitempty"`
}
func (Response) CostMicros ¶
CostMicros returns the cost of this turn in microdollars-equivalent units of the currency reported by the rate card. The currency itself is available via Cost() when needed.
type RouterSink ¶
type RouterSink struct {
// contains filtered or unexported fields
}
RouterSink counts MoE router events. It is a plain observe.Sink so it can be attached with .AnyHook(observe.Hook(sink)) to any action set.
func NewRouterSink ¶
func NewRouterSink() *RouterSink
func (*RouterSink) Stats ¶
func (s *RouterSink) Stats() SinkStats
type SSEChunkDecoder ¶
SSEChunkDecoder turns the JSON payload of a single SSE `data:` frame into a text fragment. Providers differ only in this function.
Return values:
- text: fragment to yield. Empty fragments are skipped by the skeleton.
- done: true means the stream is complete and the reader stops.
- err: decoding failed for this frame; the skeleton drops the frame and continues. A single malformed frame does not tear down a healthy stream.
type StreamEvent ¶
type StreamEvent struct {
Sequence uint64 `json:"sequence"`
Time time.Time `json:"time"`
Kind StreamEventKind `json:"kind"`
RunID string `json:"run_id,omitempty"`
SessionID string `json:"session_id,omitempty"`
Turn int `json:"turn,omitempty"`
Action string `json:"action,omitempty"`
ToolCallID string `json:"tool_call_id,omitempty"`
ToolName string `json:"tool_name,omitempty"`
Delta string `json:"delta,omitempty"`
ToolResult string `json:"tool_result,omitempty"`
Response *Response `json:"response,omitempty"`
Error error `json:"error,omitempty"`
}
StreamEvent represents an ephemeral lifecycle or streaming event.
type StreamEventKind ¶
type StreamEventKind uint8
const ( EventRunStarted StreamEventKind = iota EventTurnStarted EventCompletionStarted EventTokenDelta EventCompletionFinished EventToolCallStarted EventToolCallFinished EventTurnFinished EventRunFinished EventError )
func (StreamEventKind) String ¶
func (k StreamEventKind) String() string
type StreamSink ¶
type StreamSink interface {
Emit(context.Context, StreamEvent) error
}
StreamSink receives zero-allocation streaming events across run boundaries.
type TieredModelRouter ¶
type TieredModelRouter struct {
FastSmall Provider // Tier 1: Local / Groq (0$ or sub-cent)
Standard Provider // Tier 2: DeepSeek-V3 / GPT-4o-mini
HeavyDeep Provider // Tier 3: Claude 3.5 Sonnet / o1 (High reasoning)
}
TieredModelRouter dynamically escalates queries to higher-tier models if smaller models fail.
func NewTieredModelRouter ¶
func NewTieredModelRouter(fast, standard, heavy Provider) *TieredModelRouter
func (*TieredModelRouter) CompleteAdaptive ¶
func (r *TieredModelRouter) CompleteAdaptive(ctx context.Context, req Request, minTier int) (Response, int, error)
CompleteAdaptive routes queries through increasing capability tiers.
type TokenEstimator ¶
type ToolCall ¶
type ToolCall struct {
ID string `json:"id"`
Type string `json:"type"`
Function FunctionCall `json:"function"`
}
type ToolSpec ¶
type ToolSpec struct {
Type string `json:"type"`
Function FunctionSpec `json:"function"`
}
type TypedReq ¶
type TypedReq struct {
System string `json:"system,omitempty"`
User string `json:"user" validate:"required"`
}
TypedReq is the input contract for every NewTypedNode-produced action. A caller builds one of these, the action forwards it to the provider in JSON mode, and the model's reply is unmarshalled into Res.
The two fields are free-form strings so the node can be composed without knowing anything about the caller's domain. System carries the reviewer/architect/planner persona; User carries the payload rendered as text by an upstream projection.
type Usage ¶
type Usage struct {
Model string `json:"model,omitempty"`
PromptTokens int `json:"prompt_tokens,omitempty"`
CachedPromptTokens int `json:"cached_prompt_tokens,omitempty"`
CompTokens int `json:"comp_tokens,omitempty"`
FinishReason string `json:"finish_reason,omitempty"`
Duration time.Duration `json:"duration,omitempty"`
}
Usage is the LLM accounting that travels with every agent result.
Any result that embeds Usage automatically satisfies the runner observer's token-cost interface, so the metrics table picks it up without per-result Tokens()/CostUSD() methods.
Usage is intentionally a value type: it is small (40 bytes on 64-bit), copyable, and safe to embed.
func FromResponse ¶
FromResponse extracts Usage from a completed Response.
func (Usage) CostMicros ¶
CostMicros returns the cost in micro-units of the rate-card currency. Zero when the model has no rate card — that is intentional; the observer prints "-" rather than "0.000000" for unknown models.
func (Usage) CostUSD ¶
CostUSD is the compat method expected by the runner observer's tokenCostReporter interface. The value is micro-units of whatever currency the rate card declares; the name is historical. Callers that need the currency should call CalculateCost directly.