provider/openai: - Fix doubled tool call args (argsComplete flag): Ollama sends complete args in the first streaming chunk then repeats them as delta, causing doubled JSON and 400 errors in elfs - Handle fs: prefix (gemma4 uses fs:grep instead of fs.grep) - Add Reasoning field support for Ollama thinking output cmd/gnoma: - Early TTY detection so logger is created with correct destination before any component gets a reference to it (fixes slog WARN bleed into TUI textarea) permission: - Exempt spawn_elfs and agent tools from safety scanner: elf prompt text may legitimately mention .env/.ssh/credentials patterns and should not be blocked tui/app: - /init retry chain: no-tool-calls → spawn_elfs nudge → write nudge (ask for plain text output) → TUI fallback write from streamBuf - looksLikeAgentsMD + extractMarkdownDoc: validate and clean fallback content before writing (reject refusals, strip narrative preambles) - Collapse thinking output to 3 lines; ctrl+o to expand (live stream and committed messages) - Stream-level filter for model pseudo-tool-call blocks: suppresses <<tool_code>>...</tool_code>> and <<function_call>>...<tool_call|> from entering streamBuf across chunk boundaries - sanitizeAssistantText regex covers both block formats - Reset streamFilterClose at every turn start
106 lines
3.0 KiB
Go
106 lines
3.0 KiB
Go
package provider
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
|
|
"somegit.dev/Owlibou/gnoma/internal/message"
|
|
"somegit.dev/Owlibou/gnoma/internal/stream"
|
|
)
|
|
|
|
// ToolChoiceMode controls how the model selects tools.
|
|
type ToolChoiceMode string
|
|
|
|
const (
|
|
ToolChoiceAuto ToolChoiceMode = "auto"
|
|
ToolChoiceRequired ToolChoiceMode = "required"
|
|
ToolChoiceNone ToolChoiceMode = "none"
|
|
)
|
|
|
|
// Request encapsulates everything needed for a single LLM API call.
|
|
type Request struct {
|
|
Model string
|
|
SystemPrompt string
|
|
Messages []message.Message
|
|
Tools []ToolDefinition
|
|
MaxTokens int64
|
|
Temperature *float64
|
|
TopP *float64
|
|
TopK *int64
|
|
StopSequences []string
|
|
Thinking *ThinkingConfig
|
|
ResponseFormat *ResponseFormat
|
|
ToolChoice ToolChoiceMode // "" = provider default (auto)
|
|
}
|
|
|
|
// ToolDefinition is the provider-agnostic tool schema.
|
|
type ToolDefinition struct {
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
Parameters json.RawMessage `json:"parameters"` // JSON Schema passthrough
|
|
}
|
|
|
|
// ThinkingConfig controls extended thinking / reasoning.
|
|
type ThinkingConfig struct {
|
|
BudgetTokens int64
|
|
}
|
|
|
|
// ResponseFormat controls the output format.
|
|
type ResponseFormat struct {
|
|
Type ResponseFormatType
|
|
JSONSchema *JSONSchema // only used when Type == ResponseJSON
|
|
}
|
|
|
|
type ResponseFormatType string
|
|
|
|
const (
|
|
ResponseText ResponseFormatType = "text"
|
|
ResponseJSON ResponseFormatType = "json_object"
|
|
)
|
|
|
|
// JSONSchema defines a schema for structured JSON output.
|
|
type JSONSchema struct {
|
|
Name string `json:"name"`
|
|
Description string `json:"description,omitempty"`
|
|
Schema json.RawMessage `json:"schema"`
|
|
Strict bool `json:"strict,omitempty"`
|
|
}
|
|
|
|
// Capabilities describes what a model can do.
|
|
type Capabilities struct {
|
|
ToolUse bool `json:"tool_use"`
|
|
JSONOutput bool `json:"json_output"`
|
|
Thinking bool `json:"thinking"`
|
|
Vision bool `json:"vision"`
|
|
ContextWindow int `json:"context_window"`
|
|
MaxOutput int `json:"max_output"`
|
|
}
|
|
|
|
// ModelInfo describes a model available from a provider.
|
|
type ModelInfo struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Provider string `json:"provider"`
|
|
Capabilities Capabilities `json:"capabilities"`
|
|
}
|
|
|
|
// SupportsTools returns true if the model supports tool/function calling.
|
|
func (m ModelInfo) SupportsTools() bool {
|
|
return m.Capabilities.ToolUse
|
|
}
|
|
|
|
// Provider is the core abstraction over all LLM backends.
|
|
type Provider interface {
|
|
// Stream initiates a streaming request and returns an event stream.
|
|
Stream(ctx context.Context, req Request) (stream.Stream, error)
|
|
|
|
// Name returns the provider identifier (e.g., "mistral", "anthropic").
|
|
Name() string
|
|
|
|
// Models returns available models with their capabilities.
|
|
Models(ctx context.Context) ([]ModelInfo, error)
|
|
|
|
// DefaultModel returns the default model ID for this provider.
|
|
DefaultModel() string
|
|
}
|