Documentation
¶
Overview ¶
OpenAI-compatible API-key GET /models discovery: a redirect-refusing, credential-safe request returning sanitized model ids plus whitelisted reasoning-effort capability metadata.
Per-model tool-call support, read from whatever capability metadata a provider publishes about its own models.
Selectable-provider catalog: merges configured provider.<name> entries with built-in providers that declare selectable models outside the provider: map (the OpenAI ChatGPT provider). It is the single source model validation, resume recovery, and no-selectable diagnostics cross-reference instead of the composed provider: map alone.
Internal provider contract over the OpenAI chat-completions shape: the shared openai-go-backed Client plus the built-in adapter registry.
Pre-request credential failure a provider.Client raises when the selected provider has no usable credential.
Extracts a one-line human-readable message from a provider HTTP-error body for the TUI notice.
Typed surfacing of provider non-2xx chat-completions responses: HTTPError carries the status, the raw response body text, and a one-line human-readable surface string used as the Go error text. Provider adapters do not retry: each non-2xx response is surfaced as an HTTPError, and the turn layer owns any classification-driven retry policy (e.g. honoring RetryAfter). The TUI no longer renders Surface directly: the on-screen line-1 message is the friendly text from FriendlyHTTPMessage, while the provider package stays independent of internal/events and the turn layer persists the body text as provider_request_failed{http, http_error} (superseding the earlier rule that an HTTP error emits no event).
Built-in OpenAI launch-provider connection defaults and Platform discovery projection.
Built-in OpenAI ChatGPT selectable-provider catalog metadata: provider id, display name, ChatGPT/Codex model origin, and model list. This file owns catalog metadata only; the ChatGPT/Codex Responses API request/response adapter and client live in openai_chatgpt_client.go.
OpenAI ChatGPT (Codex) Responses API adapter: maps codemeld's provider.Request/ Response turn contract onto the ChatGPT/Codex Responses API at the pinned, non-overridable origin, bridging Responses SSE events into the openai.ChatCompletionChunk stream the turn loop already consumes, with two-header auth and credential-safe HTTP errors. This adapter exception is scoped to the built-in openai-chatgpt provider only; Platform/OpenRouter/custom providers keep the chat-completions NewClient path unchanged.
Sanitized parse+adapt shape for ChatGPT/Codex discovered models: the codemeld-owned struct that keeps only selection/capability metadata (never the discovery response's prompt-bearing instructions/messages or raw bodies) and adapts it into the shared discovered-model store's neutral entry shape the connect-path writer persists.
Built-in OpenRouter launch-provider connection defaults.
Parses the composed config provider block into typed entries and resolves auth headers.
Provider-agnostic tool definitions advertised on a chat-completion request, the product-authored `bash` definition that lives outside the tool registry, and the strict checker that turns raw `ask_user` arguments into an accepted request.
Classifies wrapped provider transport/TLS/decode/stream-drop/empty-response failures into the provider_request_failed (phase, reason) closed set. Pure classification only: it never emits an event and stays independent of internal/events, so the turn layer hands the result to events.EmitProviderRequestFailed and tui.RenderProviderRequestFailedNotice.
Built-in Venice.ai OpenAI-compatible provider connection defaults.
Index ¶
- Constants
- func AskUserDecodesUnchanged(raw json.RawMessage) bool
- func AskUserTextRenderable(s string) bool
- func FriendlyHTTPMessage(name string, status int, body string) string
- func FriendlyRoutingExhaustionMessage(name string, e *RoutingExhaustionError) string
- func ParseProviders(composed map[string]any) (map[string]ProviderEntry, error)
- func RefreshChatGPTModelCache(ctx context.Context, cfg ChatGPTClientConfig, ...) error
- func ResolvePlatformAPIKey(configuredKey string) string
- func Retryable(c Classification) bool
- func SupportedEffort(provider, modelID string) []string
- func SupportsTools(providerID string, caps map[string]any) bool
- func UnavailableUpstreamProvider(providerID string, err error) (string, bool)
- type APIKeyDiscoveryConfig
- type Adapter
- type AskUserQuestion
- type AskUserRequest
- type AuthHeader
- type AuthKind
- type Catalog
- type CatalogEntry
- type ChatGPTClientConfig
- type ChatGPTStoreModel
- type Classification
- func ClassifyEmptyCompletion(c *openai.ChatCompletion) (Classification, bool)
- func ClassifyRequestError(err error) (Classification, bool)
- func ClassifyStreamDrop(err error, partialResponseChars int64) Classification
- func EmptyStreamClassification() Classification
- func NoBodyHTTPFailure(status int64) Classification
- func TruncatedHTTPFailure(status *int64) Classification
- type Client
- type ClientConfig
- type ContentPart
- type CredentialUnavailableError
- type DiscoveredConfiguredModel
- type HTTPBodyError
- type HTTPError
- type MaxPrice
- type Message
- type ModelOrigin
- type OpenRouterEndpointStore
- type OpenRouterEstimate
- type ProviderEntry
- type Request
- type Response
- type Routing
- type RoutingExhaustionError
- type ToolCall
- type ToolDefinition
Constants ¶
const ( EffortNone = "none" EffortMinimal = "minimal" EffortLow = "low" EffortMedium = "medium" EffortHigh = "high" EffortXHigh = "xhigh" EffortDefault = "default" )
Only an empty Request.Effort omits the reasoning parameter; non-empty values are sent unchanged.
const ( MaxAskUserQuestions = 5 MaxAskUserOptions = 8 MaxAskUserTextRunes = 200 // Context is a scrollable paragraph rather than a row the form has to fit, so it carries // its own bound: raising the shared one would let a single option label fill the terminal. MaxAskUserContextRunes = 2000 )
const AskUserTextPattern = "^[^" + askUserTextBlocked + "]*[^" + askUserTextBlocked + " ][^" + askUserTextBlocked + "]*$"
AskUserTextPattern is anchored so a blocked character is refused wherever it sits, not only in a value with nothing else to show: a tab or newline beside visible text is still text the terminal cannot draw at the width the form measured it at.
const AskUserToolName = "ask_user"
const ChatGPTProviderID = "openai-chatgpt"
ChatGPTProviderID is the stable, reserved provider id of the built-in OpenAI ChatGPT (subscription) provider, persisted in model.active / model.last_used and matched at resume recovery. It is distinct from the OpenAI Platform provider id (PlatformProviderID); a user-defined provider.openai-chatgpt entry is rejected at load, so this provider is never read from the configured provider: map.
const EffortNoReasoning = "no-reasoning"
EffortNoReasoning means no reasoning-effort parameter is sent.
const PlatformProviderID = "openai"
PlatformProviderID is the stable provider id of the built-in OpenAI Platform (API-key) provider, persisted in model.active / model.last_used and matched at resume recovery. It is distinct from the OpenAI ChatGPT provider id (ChatGPTProviderID); there is no cross-provider precedence.
const RetryConfigKey = "retry"
RetryConfigKey is the reserved key under the settings `provider` object that holds the auto-retry block (provider.retry) rather than a provider entry. ParseProviders skips it so it is never parsed as — or selectable as — a provider; config.NewCache reads it separately for the retry policy.
const SuggestFollowupToolName = "suggest_followup"
SuggestFollowupToolName is the pinned name of the product-authored `suggest_followup` tool. The turn loop matches a model tool call against this exact literal to intercept it (it is never dispatched, never persisted), so the advertised definition and the interception point share this single constant.
Variables ¶
This section is empty.
Functions ¶
func AskUserDecodesUnchanged ¶
func AskUserDecodesUnchanged(raw json.RawMessage) bool
AskUserDecodesUnchanged reports whether encoding/json will decode the raw token without substituting anything: it repairs a lone surrogate escape or an invalid UTF-8 byte into U+FFFD and returns no error, and a value repaired that way is neither the id the model correlates its answer by nor the label the user was shown. U+FFFD sent as itself is ordinary printable text and stays accepted; only text that would be rewritten into it is refused. The renderability rule cannot stand in for this, because the substitute passes it.
func AskUserTextRenderable ¶
AskUserTextRenderable reports whether the question form can show s in full. It is the authoritative rule for every displayed field and stays at least as strict as AskUserTextPattern, which cannot require that any grapheme occupy a cell (text made only of combining marks mounts as an empty prompt or an unreadable row) and cannot name the code points askUserTextBlocked leaves out. Every rune must be printable — unicode.IsPrint admits the ASCII space but no other whitespace, so a tab or newline beside visible text is refused here for the same reason the pattern refuses it.
func FriendlyHTTPMessage ¶
FriendlyHTTPMessage returns the one-line notice text for a provider non-2xx response. It leads with the synthetic prefix "provider <name> returned HTTP <status>" and, when the body carries a usable human sentence, appends it after ": " — preferring error.metadata.raw (the provider-specific sentence) over the often-generic error.message. A non-JSON body, an empty body, or one with no usable field yields the bare prefix with no JSON shown. The extracted text has its newlines/tabs collapsed to single spaces so the body's own control characters cannot break the one-line notice.
This extractor copies a sentence out of body verbatim and never redacts: for a credentialed provider (the OpenAI ChatGPT adapter) the caller must pass a body already scrubbed via redactCredentials, since the *HTTPError.Body it reads is stored pre-redacted. Keep new extraction logic body-derived so it cannot reintroduce a token or account-derived value the body no longer contains.
func FriendlyRoutingExhaustionMessage ¶
func FriendlyRoutingExhaustionMessage(name string, e *RoutingExhaustionError) string
func ParseProviders ¶
func ParseProviders(composed map[string]any) (map[string]ProviderEntry, error)
ParseProviders converts the composed config's provider block into typed entries keyed by provider name, filling the Bearer default for entries without an explicit auth_header. An absent or empty provider block yields an empty map. Schema-level shape rules (required fields, unknown keys, auth_header shape) are enforced upstream by config.Validate; this returns an error only on a value whose runtime type does not match the validated schema.
func RefreshChatGPTModelCache ¶
func RefreshChatGPTModelCache(ctx context.Context, cfg ChatGPTClientConfig, write func([]ChatGPTStoreModel) error) error
RefreshChatGPTModelCache runs ChatGPT model discovery with the given session credentials, adapts the sanitized result into the shared discovered-model store's neutral records, and hands them to write for persistence. It runs only on explicit login and on a forced picker refresh — never automatically on picker open, highlight, or `codemeld auth status`. The store writer is injected so this package need not import internal/config. The returned error carries only a status/path, never a credential or a raw or prompt-bearing response body (discoverModels drops those by construction).
func ResolvePlatformAPIKey ¶
ResolvePlatformAPIKey returns the OpenAI Platform provider's effective API key, preferring a non-empty OPENAI_API_KEY environment variable over configuredKey (the key read from provider.openai.api_key in the global settings file). This precedence applies only to the Platform provider (auth kind AuthKindPlatform): the OpenAI ChatGPT provider uses its stored session and ignores OPENAI_API_KEY, and custom OpenAI-compatible providers resolve their key through provider.<name>.api_key unchanged.
func Retryable ¶
func Retryable(c Classification) bool
Retryable reports whether a classified provider failure is transient and should be auto-retried. The retryable population is a dropped TCP/TLS connection (stream_drop, including a partial drop), a dial failure (dns/timeout/refused/other), a recoverable TLS handshake/other failure, an empty response (no_choices/null_content/zero_delta_stream), and an http response with a 429/500/502/503/504 status. Deterministic, user-actionable failures are never retried: a 4xx http response, an invalid/expired TLS certificate, a decode error, and the 2xx-with-bad-body http_no_body/http_truncated cases (their status is the 2xx that was received, so they fall outside the retry-status set). A CredentialUnavailableError and a context cancellation never become a Classification, so the turn layer handles them and they are never seen here.
func SupportedEffort ¶
func SupportsTools ¶
A further provider is one more case; the default must stay true so a provider that publishes nothing about tool calling keeps its tools.
Types ¶
type APIKeyDiscoveryConfig ¶
type APIKeyDiscoveryConfig struct {
ProviderName string
Entry ProviderEntry
HTTPClient *http.Client
}
APIKeyDiscoveryConfig is the input to DiscoverAPIKeyModels. ProviderName is used only in error surface text; Entry supplies the base URL and the resolved auth header (ProviderEntry.ResolveAuthHeader); HTTPClient is an optional injection point for tests (nil uses http.DefaultClient). Timeout and cancellation are the caller's responsibility via ctx — no client-level timeout is set here.
type Adapter ¶
type Adapter struct {
Name string
DefaultBaseURL string
DefaultAuthHeader AuthHeader
}
type AskUserQuestion ¶
type AskUserQuestion struct {
ID string
Prompt string
Options []string
MultiSelect bool
AllowCustom bool
}
AskUserQuestion and AskUserRequest are one accepted `ask_user` call. They are the single definition of what a valid call is: production dispatch maps an accepted request onto the TUI form, and /resume replay runs a saved call's raw arguments back through the same checker, so a call the live form would refuse can never render on replay.
type AskUserRequest ¶
type AskUserRequest struct {
Context string
Questions []AskUserQuestion
}
func DecodeAskUserRequest ¶
func DecodeAskUserRequest(arguments string) (AskUserRequest, error)
type AuthHeader ¶
AuthHeader is the runtime form of a provider's optional auth_header object: the header name and its value template, where any {api_key} literal is substituted at resolve time.
type AuthKind ¶
type AuthKind string
AuthKind classifies how a selectable provider resolves its request credentials, so turn dispatch can pick the credential source from the provider id without re-deriving it and never attaches ChatGPT session state to a custom provider.
const ( // AuthKindConfigured resolves credentials from provider.<name>.api_key and the // configured auth_header (custom OpenAI-compatible providers and OpenRouter). AuthKindConfigured AuthKind = "configured" // AuthKindPlatform is the OpenAI Platform provider: the key resolves from // OPENAI_API_KEY when set and non-empty, otherwise from provider.openai.api_key // (see [ResolvePlatformAPIKey]). AuthKindPlatform AuthKind = "platform" // AuthKindChatGPTSession is the built-in OpenAI ChatGPT provider: credentials // come from the stored auth.openai-chatgpt session and OPENAI_API_KEY is ignored. AuthKindChatGPTSession AuthKind = "chatgpt_session" )
type Catalog ¶
type Catalog struct {
// contains filtered or unexported fields
}
Catalog is the merged, ordered set of selectable providers: configured providers first (in sorted provider-id order) followed by built-in selectable providers. It is read-only after BuildCatalog; its accessors return defensive copies so a caller cannot mutate the cached session view.
func BuildCatalog ¶
func BuildCatalog(configured map[string]ProviderEntry, chatGPTDiscovered []ChatGPTStoreModel, discoveredConfigured map[string][]DiscoveredConfiguredModel) Catalog
func (Catalog) Entries ¶
func (c Catalog) Entries() []CatalogEntry
Entries returns copies of every catalog entry in catalog order (configured providers sorted by id, then built-ins); mutating the result does not change the catalog.
func (Catalog) Entry ¶
func (c Catalog) Entry(id string) (CatalogEntry, bool)
Entry returns a copy of the catalog entry for id and whether it is present. The boolean distinguishes an unknown provider from one present with an empty model list, which model validation relies on.
func (Catalog) SupportedEffort ¶
func (Catalog) SupportsTools ¶
type CatalogEntry ¶
type CatalogEntry struct {
ID string
DisplayName string
Models []string
AuthKind AuthKind
Origin ModelOrigin
Builtin bool
}
CatalogEntry is one selectable provider in the merged catalog: its stable provider id (persisted in model.active / model.last_used and matched at resume recovery), its human-facing display name, the selectable model id allowlist, the auth kind, the model origin, and whether it is a built-in row not read from settings. Models is in configured declaration order for configured providers and in built-in list order for built-ins. Stable provider ids — not display names — are persisted, emitted in events, and validated; display names are metadata for the picker.
type ChatGPTClientConfig ¶
type ChatGPTClientConfig struct {
AccessToken string
AccountID string
// HTTPClient is optional and lets tests point the adapter at a stub server. It
// changes only the transport, never the pinned origin: the request
// URL stays chatgpt.com so a test redirects with a RoundTripper, not a base-URL
// override. Production leaves it nil; either way the adapter wraps it in a
// redirect-pinned copy (see pinRedirects) so credentials never follow a 3xx off
// the approved origin.
HTTPClient *http.Client
}
ChatGPTClientConfig carries the per-turn ChatGPT credentials the adapter needs. The production wiring loads and, where needed, refreshes the stored auth.openai-chatgpt session and supplies the already-resolved access token and account id here; the adapter never reads global settings, chooses providers, or refreshes tokens itself.
type ChatGPTStoreModel ¶
type ChatGPTStoreModel struct {
ID string
DisplayName string
ContextWindow int64
InputModalities []string
Capabilities map[string]any
}
ChatGPTStoreModel is one discovered ChatGPT model adapted to the shared discovered-model store's neutral shape: selection/capability metadata only. It is the boundary type the connect-path writer consumes so the provider package need not import internal/config (which would cycle); the CLI maps it onto the store's own record type. Capabilities carries the remaining whitelisted ChatGPT fields (reasoning levels, verbosity, …) as a generic map, so no prompt-bearing or raw-response data can ride along — chatGPTModel has no field for those.
type Classification ¶
type Classification struct {
Phase string
Reason string
HTTPStatus *int64
PartialResponseChars int64
ErrorDetail string
}
Classification is the provider_request_failed tuple a transport, TLS decode, stream-drop, or empty-response failure maps to. Its fields line up one-to-one with events.EmitProviderRequestFailed's arguments: HTTPStatus is non-nil only for the http phase (required for http_no_body, optional for http_truncated, forbidden elsewhere); PartialResponseChars is meaningful only for stream_drop; ErrorDetail is always the diagnostic message and is never empty so the event validator accepts it.
func ClassifyEmptyCompletion ¶
func ClassifyEmptyCompletion(c *openai.ChatCompletion) (Classification, bool)
ClassifyEmptyCompletion inspects a 2xx non-streamed completion the SDK decoded successfully and reports an empty_response classification when it carries no usable assistant output: no_choices for an absent/empty choices list, null_content for a present first choice whose message has no content, refusal, or tool calls. It reports false when the completion does carry usable output, so a legitimate refusal or tool-call turn is never mistaken for a failure.
func ClassifyRequestError ¶
func ClassifyRequestError(err error) (Classification, bool)
ClassifyRequestError maps the error returned by a non-streaming ChatCompletion call (or the initial Stream open) to a dial, tls, or decode classification. It reports false — leaving the caller to handle it elsewhere — when err is nil, a context cancellation/deadline (user interrupt or the turn deadline, never a provider_request_failed), or an *HTTPError (a real non-2xx response the turn layer handles directly, emitting provider_request_failed{http, http_error} rather than routing it through this transport classifier). TLS is checked before the generic connection buckets so a handshake failure wrapped in a *url.Error/*net.OpError is not mislabeled as a dial failure.
func ClassifyStreamDrop ¶
func ClassifyStreamDrop(err error, partialResponseChars int64) Classification
ClassifyStreamDrop maps a mid-stream failure — the stream's final error after the turn layer has counted partialResponseChars assistant-content characters — to a stream_drop classification. A clean or unexpected EOF maps to stream_eof; any other read error maps to stream_read_error. The helper does not count characters or infer transcript state itself; partialResponseChars is supplied by the caller and must be >= 0. err must be non-nil (a clean close with no content is EmptyStreamClassification, not a drop).
func EmptyStreamClassification ¶
func EmptyStreamClassification() Classification
EmptyStreamClassification returns the empty_response/zero_delta_stream classification for a stream that closed cleanly (no error) without ever emitting an assistant-content delta.
func NoBodyHTTPFailure ¶
func NoBodyHTTPFailure(status int64) Classification
NoBodyHTTPFailure returns the http/http_no_body classification for a provider response whose status line arrived but whose body was absent. The status is required by for this reason (it is what the hint table keys on), so it is taken as a plain int and always recorded.
func TruncatedHTTPFailure ¶
func TruncatedHTTPFailure(status *int64) Classification
TruncatedHTTPFailure returns the http/http_truncated classification for a response body cut off mid-transfer. The status is optional per — present when a status line was received before the truncation, nil otherwise.
type Client ¶
Client is codemeld's internal provider interface over chat completions, covering both the non-streaming and streaming response forms.
func NewChatGPTClient ¶
func NewChatGPTClient(cfg ChatGPTClientConfig) Client
NewChatGPTClient builds the ChatGPT/Codex Responses API adapter as a provider.Client. It pins the non-overridable approved origin and the caller supplies an already-loaded/refreshed access token and account id. The returned client speaks the Responses API and is used only for the built-in openai-chatgpt provider.
func NewClient ¶
func NewClient(cfg ClientConfig) Client
NewClient builds the shared openai-go-backed Client for any OpenAI-compatible provider, whether a built-in adapter or a custom configured one. It constructs the chat-completions service directly rather than openai.NewClient so no OPENAI_* environment variable can inject a base URL, API key, or header; the only auth sent is the resolved AuthHeader/AuthValue.
type ClientConfig ¶
type ClientConfig struct {
Name string
BaseURL string
AuthHeader string
AuthValue string
Attribution bool
Routing Routing
HTTPClient *http.Client
MinThroughput func(ctx context.Context, model string) (float64, bool)
}
ClientConfig holds the resolved per-provider values a Client needs. AuthHeader and AuthValue are the name/value returned by ProviderEntry.ResolveAuthHeader. Name is the provider's display name, woven into the HTTP-error surface prefix. HTTPClient is optional and lets tests point the client at a stub server.
type ContentPart ¶
ContentPart is one part of a multi-part user message in the provider contract. Type is "text" or "image_url": a text part carries its text in Text, and an image_url part carries its image reference (a data: URI or a URL) in ImageURL. codemeld only synthesizes these two shapes.
type CredentialUnavailableError ¶
type CredentialUnavailableError struct {
}
CredentialUnavailableError is returned by a provider.Client when the selected provider has no usable credential for the turn and the turn must fail without falling back to another provider. It is a pre-request failure — no HTTP request reached the network — so it is distinct from *HTTPError and *HTTPBodyError and is never routed through the transport classifier. Surface is a safe, provider-named, credential-free remediation message the turn layer renders verbatim as the failure notice. No provider_request_failed event is emitted for it: the reason set has no auth phase and there is no transport outcome to record (the OpenAI ChatGPT wiring raises it for a missing/invalid/expired session or a failed token refresh).
func (*CredentialUnavailableError) Error ¶
func (e *CredentialUnavailableError) Error() string
type DiscoveredConfiguredModel ¶
type DiscoveredConfiguredModel struct {
ID string
InputModalities []string
Capabilities map[string]any
}
DiscoveredConfiguredModel is one model surfaced by OpenAI-compatible /models discovery: its sanitized id plus, when the provider advertises reasoning-effort capability metadata in one of the shapes [effortShapes] declares, a whitelisted capabilities map (nil otherwise). It is what DiscoverAPIKeyModels returns and the shape BuildCatalog consumes for a configured provider's discovered models.
func DiscoverAPIKeyModels ¶
func DiscoverAPIKeyModels(ctx context.Context, cfg APIKeyDiscoveryConfig) ([]DiscoveredConfiguredModel, error)
DiscoverAPIKeyModels performs an OpenAI-compatible GET <base_url>/models request bearing the provider's configured api key and returns the sanitized, de-duplicated models in response order — each carrying its id and, when the provider advertises reasoning-effort capabilities in a declared shape, a whitelisted capabilities map. It is a narrow, opt-in discovery entry point: the caller passes an explicit provider id, base URL, and resolved auth header, so it never overclaims compatibility for a provider that was not asked for.
It is credential-safe: the HTTP client is redirect-pinned, so a 3xx is handed back unfollowed and the api key is never re-sent to a redirect Location; a redirect and every other non-2xx surface as a body-free *HTTPError; a malformed or empty body surfaces as a validation error carrying no api key, auth header, or raw/provider error body. Only whitelisted fields survive the projection, so no prompt-, secret-, or raw-body content reaches the returned capabilities. It writes nothing — the caller persists the result.
func FilterPlatformDiscoveredModels ¶
func FilterPlatformDiscoveredModels(models []DiscoveredConfiguredModel) []DiscoveredConfiguredModel
type HTTPBodyError ¶
HTTPBodyError reports a 2xx provider response whose body could not be consumed as a usable completion: Truncated is false when a status line arrived but the body was absent (http_no_body) and true when the body was cut off mid-transfer (http_truncated). Status is the received HTTP status line. It is the seam between the provider client (which detects the condition at the transport, the only place the status survives the SDK's body read) and the turn layer (which maps it to NoBodyHTTPFailure/TruncatedHTTPFailure and emits the event). It is distinct from *HTTPError: a non-2xx response stays on the verbatim path and never becomes an HTTPBodyError.
Err is the underlying transport read error on the streaming path, where the failure surfaces from the SSE body reader rather than a buffered read; it is exposed via Unwrap so a truncation that followed partial assistant content can still be classified as a stream_drop with its original io.EOF/ErrUnexpectedEOF fidelity. It is nil on the non-streaming path, where the status is enough.
func (*HTTPBodyError) Error ¶
func (e *HTTPBodyError) Error() string
func (*HTTPBodyError) Unwrap ¶
func (e *HTTPBodyError) Unwrap() error
Unwrap exposes the underlying streaming transport error (nil on the non-streaming path) so errors.Is against io.EOF/io.ErrUnexpectedEOF still works.
type HTTPError ¶
type HTTPError struct {
Status int
Body string
Surface string
// RetryAfter is the verbatim Retry-After response-header value when the
// provider sent one (a delta-seconds count or an HTTP-date), or "" when
// absent. It is carried — unlike the rest of the response headers, which the
// typed error drops — so the auto-retry engine can honor a 429/503's requested
// backoff. It is never persisted: only Body becomes the durable
// provider_request_failed error_detail.
RetryAfter string
}
HTTPError is a provider chat-completions response with a non-2xx HTTP status. Body holds the response body as received from the HTTP client: it is a Go string so arbitrary bytes, including invalid UTF-8 and binary payloads, can be carried to the notice path. Surface is a one-line human-readable prefix naming the provider and status followed by Body; it is the Go error text, no longer the direct on-screen TUI line — the notice path renders the friendly FriendlyHTTPMessage instead. Body is the source the friendly extractor parses. Every non-2xx status — including 429/503 quota/rate-limit responses — flows through this single path; no retry or throttle branching occurs. The turn layer persists Body through provider_request_failed{http, http_error}, where the event append layer applies UTF-8 normalization before storage, but still sends no rate-limit signal to the scheduler.
type Message ¶
type Message struct {
Role string
Content string
// Parts carries a user message's content as an ordered list of content parts
// (text and image_url) instead of a plain string. When non-empty on a
// Role=="user" message it takes precedence over Content, and the message is
// sent as a `content` array rather than a string. It is
// ignored for every other role. The provider package stays free of a sessions
// import: the turn package translates sessions.ContentPart into this shape.
Parts []ContentPart
// ToolCalls is the assistant message's tool calls. It is set only on
// Role=="assistant" messages that requested tools; an empty list sends a plain
// assistant message.
ToolCalls []ToolCall
// ToolCallID correlates a Role=="tool" result message to the assistant
// tool-call entry it answers. It is empty for every other role.
ToolCallID string
}
Message is one chat-completion message in codemeld's internal provider contract. Role is "system", "user", "assistant", or "tool". An assistant message that invoked tools carries them in ToolCalls; a tool-result message (Role "tool") carries the id of the assistant tool-call entry it answers in ToolCallID, so the OpenAI-compatible tool-call continuation round-trips back to the provider.
type ModelOrigin ¶
type ModelOrigin string
ModelOrigin records non-overridable provenance for a built-in provider's models. It is catalog metadata only and is empty for configured providers.
const ( // OriginNone is the origin of a configured provider's models (no built-in // provenance). OriginNone ModelOrigin = "" // OriginChatGPTCodex marks the OpenAI ChatGPT provider's models as served by the // ChatGPT/Codex flow, not the OpenAI Platform chat-completions surface. OriginChatGPTCodex ModelOrigin = "chatgpt-codex" )
type OpenRouterEndpointStore ¶
type OpenRouterEndpointStore struct {
HTTPClient *http.Client
Now func() time.Time
// contains filtered or unexported fields
}
func (*OpenRouterEndpointStore) Estimate ¶
func (s *OpenRouterEndpointStore) Estimate(entry ProviderEntry, authName, authValue, model, sortMode string, fetched func()) (OpenRouterEstimate, bool)
func (*OpenRouterEndpointStore) SpeedBar ¶
func (s *OpenRouterEndpointStore) SpeedBar(ctx context.Context, entry ProviderEntry, authName, authValue, model string) (float64, bool)
type OpenRouterEstimate ¶
type ProviderEntry ¶
type ProviderEntry struct {
BaseURL string
APIKey string
AuthHeader *AuthHeader
Routing Routing
}
ProviderEntry is the runtime form of one provider.<name> config entry. APIKey is held in plaintext at runtime. AuthHeader is non-nil after ParseProviders, carrying the configured header or the Bearer default.
func (ProviderEntry) ResolveAuthHeader ¶
func (p ProviderEntry) ResolveAuthHeader() (name, value string)
ResolveAuthHeader returns the auth header name and value with every {api_key} literal in the value replaced by the entry's api key; other {name} tokens pass through unchanged. An empty api key yields an empty substitution, and the Bearer default is used when AuthHeader is unset.
type Request ¶
type Request struct {
Model string
Messages []Message
Effort string
Stream bool
Tools []ToolDefinition
PromptCacheKey string
IgnoredProviders []string
}
Request is one chat-completion call. Effort is sent unchanged when non-empty; an empty value omits the reasoning parameter. Stream selects the streaming response form. Tools is the turn's mode-filtered advertised tool set: when non-empty ChatCompletion sends it as `tools` with automatic tool choice; when empty it sends neither field. The request builder owns assembling and mode-filtering this set — ChatCompletion never inspects the registry or mode state.
type Response ¶
type Response struct {
Completion *openai.ChatCompletion
Stream *ssestream.Stream[openai.ChatCompletionChunk]
}
Response carries the result of a ChatCompletion call in exactly one form: for a non-streaming request Completion is set and Stream is nil; for a streaming request Stream is set and Completion is nil. The OpenAI chat-completions shape is codemeld's internal provider contract, so the openai-go result types are surfaced directly.
type RoutingExhaustionError ¶
type RoutingExhaustionError struct {
Model string
MaxPrice MaxPrice
DataCollectionDeny bool
RequireParameters bool
Ignore []string
HTTP *HTTPError
}
func (*RoutingExhaustionError) Error ¶
func (e *RoutingExhaustionError) Error() string
func (*RoutingExhaustionError) Unwrap ¶
func (e *RoutingExhaustionError) Unwrap() error
type ToolCall ¶
ToolCall is one OpenAI-compatible function tool call carried on an assistant provider message. Arguments is the raw JSON-encoded arguments string as the model produced it (phase 1 supports only the "function" tool-call type).
type ToolDefinition ¶
ToolDefinition is one advertised tool in codemeld's internal provider contract: a stable Name (a registry name such as `vcs_commit`, or the pinned `bash`), a one-line Description the model reads to choose when to call it, and Parameters — a JSON-Schema object in the OpenAI function-tool shape describing the call's arguments. It is provider-agnostic so request builders assemble it without importing any provider SDK; ChatCompletion maps it onto the openai-go function tool. A nil Parameters advertises a function with no parameters.
func AskUserToolDefinition ¶
func AskUserToolDefinition() ToolDefinition
func BashToolDefinition ¶
func BashToolDefinition() ToolDefinition
BashToolDefinition returns the product-authored advertising definition for the `bash` shell tool. `bash` has no registry Tool — dispatch special-cases the pinned name and runs the raw command through the shell path — so its definition is authored here rather than enumerated from the registry, and it is advertised in every mode (Plan's read-only restriction is enforced per-invocation by posture, not at advertise time). The schema requires a single string `command` property and forbids any other key, mirroring the dispatch decoder (decodeBashCommand). A fresh Parameters map is returned on each call so a caller cannot mutate shared advertising state.
func SuggestFollowupToolDefinition ¶
func SuggestFollowupToolDefinition() ToolDefinition
SuggestFollowupToolDefinition returns the product-authored advertising definition for the `suggest_followup` tool — the model→UI side-channel for a single end-of-turn follow-up suggestion. Like `bash` it has no registry Tool: the turn loop special-cases the pinned name, routing {label, prompt} to a TUI ghost-text surface rather than executing or persisting anything. The Description carries the usage contract so a weak model is steered away from firing it on trivial turns; the schema requires the two string properties and forbids any other key, and a fresh Parameters map is returned on each call so a caller cannot mutate shared advertising state.
Source Files
¶
- apikey_model_discovery.go
- capabilities.go
- catalog.go
- client.go
- credential_error.go
- effort_shapes.go
- friendly_error.go
- http_errors.go
- openai_adapter.go
- openai_chatgpt_catalog.go
- openai_chatgpt_client.go
- openai_chatgpt_modelcache.go
- openrouter_adapter.go
- openrouter_endpoints.go
- schema.go
- tooldefs.go
- transport_errors.go
- venice_adapter.go