# Twilight AI API Reference

This file is the detailed API companion for `skill/SKILL.md`.

Use it when the task needs exact package names, exported types, function signatures, provider options, or stream/event shapes.

## Package Map

- `github.com/memohai/twilight-ai/sdk`
- `github.com/memohai/twilight-ai/provider/openai/completions`
- `github.com/memohai/twilight-ai/provider/openai/responses`
- `github.com/memohai/twilight-ai/provider/anthropic/messages`
- `github.com/memohai/twilight-ai/provider/google/generativeai`
- `github.com/memohai/twilight-ai/provider/openai/embedding`
- `github.com/memohai/twilight-ai/provider/google/embedding`

## Package `sdk`

### Client And Top-Level Helpers

```go
type Client struct{}

func NewClient() *Client

func (c *Client) GenerateText(ctx context.Context, options ...GenerateOption) (string, error)
func (c *Client) GenerateTextResult(ctx context.Context, options ...GenerateOption) (*GenerateResult, error)
func (c *Client) StreamText(ctx context.Context, options ...GenerateOption) (*StreamResult, error)
func (c *Client) Embed(ctx context.Context, value string, options ...EmbedOption) ([]float64, error)
func (c *Client) EmbedMany(ctx context.Context, values []string, options ...EmbedOption) (*EmbedResult, error)

func GenerateText(ctx context.Context, options ...GenerateOption) (string, error)
func GenerateTextResult(ctx context.Context, options ...GenerateOption) (*GenerateResult, error)
func StreamText(ctx context.Context, options ...GenerateOption) (*StreamResult, error)
func Embed(ctx context.Context, value string, options ...EmbedOption) ([]float64, error)
func EmbedMany(ctx context.Context, values []string, options ...EmbedOption) (*EmbedResult, error)
```

### Provider Contracts

```go
type Provider interface {
    Name() string
    ListModels(ctx context.Context) ([]Model, error)
    Test(ctx context.Context) *ProviderTestResult
    TestModel(ctx context.Context, modelID string) (*ModelTestResult, error)
    DoGenerate(ctx context.Context, params GenerateParams) (*GenerateResult, error)
    DoStream(ctx context.Context, params GenerateParams) (*StreamResult, error)
}

type ProviderStatus string

const (
    ProviderStatusOK          ProviderStatus = "ok"
    ProviderStatusUnhealthy   ProviderStatus = "unhealthy"
    ProviderStatusUnreachable ProviderStatus = "unreachable"
)

type ProviderTestResult struct {
    Status  ProviderStatus
    Message string
    Error   error
}

type ModelTestResult struct {
    Supported bool
    Message   string
}
```

### Models

```go
type ModelType string

const ModelTypeChat ModelType = "chat"

type Model struct {
    ID          string
    DisplayName string
    Provider    Provider
    Type        ModelType
    MaxTokens   int
}

func (m *Model) Test(ctx context.Context) (*ModelTestResult, error)
```

### Messages

```go
type MessageRole string

const (
    MessageRoleUser      MessageRole = "user"
    MessageRoleAssistant MessageRole = "assistant"
    MessageRoleSystem    MessageRole = "system"
    MessageRoleTool      MessageRole = "tool"
)

type MessagePartType string

const (
    MessagePartTypeText       MessagePartType = "text"
    MessagePartTypeReasoning  MessagePartType = "reasoning"
    MessagePartTypeImage      MessagePartType = "image"
    MessagePartTypeFile       MessagePartType = "file"
    MessagePartTypeToolCall   MessagePartType = "tool-call"
    MessagePartTypeToolResult MessagePartType = "tool-result"
)

type MessagePart interface {
    PartType() MessagePartType
}

type TextPart struct {
    Text string
}

type ReasoningPart struct {
    Text      string
    Signature string
}

type ImagePart struct {
    Image     string
    MediaType string
}

type FilePart struct {
    Data      string
    MediaType string
    Filename  string
}

type ToolCallPart struct {
    ToolCallID string
    ToolName   string
    Input      any
}

type ToolResultPart struct {
    ToolCallID string
    ToolName   string
    Result     any
    IsError    bool
}

type Message struct {
    Role    MessageRole
    Content []MessagePart
}

func UserMessage(text string, extra ...MessagePart) Message
func SystemMessage(text string) Message
func AssistantMessage(text string) Message
func ToolMessage(results ...ToolResultPart) Message
```

Notes:

- `UserMessage` accepts a text string plus optional extra parts such as `ImagePart`.
- `Message` supports JSON marshal and unmarshal with type discrimination.

### Generation

```go
type FinishReason string

const (
    FinishReasonStop          FinishReason = "stop"
    FinishReasonLength        FinishReason = "length"
    FinishReasonContentFilter FinishReason = "content-filter"
    FinishReasonToolCalls     FinishReason = "tool-calls"
    FinishReasonError         FinishReason = "error"
    FinishReasonOther         FinishReason = "other"
    FinishReasonUnknown       FinishReason = "unknown"
)

type ResponseFormatType string

const (
    ResponseFormatText       ResponseFormatType = "text"
    ResponseFormatJSONObject ResponseFormatType = "json_object"
    ResponseFormatJSONSchema ResponseFormatType = "json_schema"
)

type ResponseFormat struct {
    Type       ResponseFormatType
    JSONSchema any
}

type GenerateParams struct {
    Model            *Model
    System           string
    Messages         []Message
    Tools            []Tool
    ToolChoice       any
    ResponseFormat   *ResponseFormat
    Temperature      *float64
    TopP             *float64
    MaxTokens        *int
    StopSequences    []string
    FrequencyPenalty *float64
    PresencePenalty  *float64
    Seed             *int
    ReasoningEffort  *string
}

type StepResult struct {
    Text            string
    Reasoning       string
    FinishReason    FinishReason
    RawFinishReason string
    Usage           Usage
    ToolCalls       []ToolCall
    ToolResults     []ToolResult
    Response        ResponseMetadata
    Messages        []Message
}

type GenerateResult struct {
    Text            string
    Reasoning       string
    FinishReason    FinishReason
    RawFinishReason string
    Usage           Usage
    Sources         []Source
    Files           []GeneratedFile
    ToolCalls       []ToolCall
    ToolResults     []ToolResult
    Response        ResponseMetadata
    Steps           []StepResult
    Messages        []Message
}
```

### Generate Options

```go
type GenerateOption func(*generateConfig)

func WithModel(model *Model) GenerateOption
func WithMessages(messages []Message) GenerateOption
func WithSystem(text string) GenerateOption
func WithTools(tools []Tool) GenerateOption
func WithToolChoice(choice any) GenerateOption
func WithResponseFormat(rf ResponseFormat) GenerateOption
func WithTemperature(t float64) GenerateOption
func WithTopP(topP float64) GenerateOption
func WithMaxTokens(n int) GenerateOption
func WithStopSequences(s []string) GenerateOption
func WithFrequencyPenalty(penalty float64) GenerateOption
func WithPresencePenalty(penalty float64) GenerateOption
func WithSeed(s int) GenerateOption
func WithReasoningEffort(effort string) GenerateOption

func WithMaxSteps(n int) GenerateOption
func WithOnFinish(fn func(*GenerateResult)) GenerateOption
func WithOnStep(fn func(*StepResult) *GenerateParams) GenerateOption
func WithPrepareStep(fn func(*GenerateParams) *GenerateParams) GenerateOption
func WithApprovalHandler(fn func(ctx context.Context, call ToolCall) (bool, error)) GenerateOption
```

Behavior notes:

- `WithMaxSteps(0)` is the default single-call mode.
- `WithMaxSteps(N)` enables automatic tool execution for up to `N` LLM calls.
- `WithMaxSteps(-1)` means unlimited loop until the model stops requesting tools.
- `WithToolChoice` accepts `"auto"`, `"none"`, or `"required"`.

### Tools

```go
type ToolExecuteFunc func(ctx *ToolExecContext, input any) (any, error)

type ToolExecContext struct {
    context.Context
    ToolCallID   string
    ToolName     string
    SendProgress func(content any)
}

type Tool struct {
    Name            string
    Description     string
    Parameters      any
    Execute         ToolExecuteFunc
    RequireApproval bool
}

func NewTool[T any](
    name, description string,
    execute func(ctx *ToolExecContext, input T) (any, error),
) Tool

type ToolCall struct {
    ToolCallID string
    ToolName   string
    Input      any
}

type ToolResult struct {
    ToolCallID string
    ToolName   string
    Input      any
    Output     any
    IsError    bool
}
```

### MCP

```go
type MCPTransportType string

const (
    MCPTransportHTTP MCPTransportType = "http"
    MCPTransportSSE  MCPTransportType = "sse"
)

type MCPClientConfig struct {
    Type       MCPTransportType
    URL        string
    Headers    map[string]string
    Transport  mcp.Transport
    HTTPClient *http.Client
    Name       string
    Version    string
}

type MCPClient struct { /* unexported fields */ }

func CreateMCPClient(ctx context.Context, config *MCPClientConfig) (*MCPClient, error)
func (c *MCPClient) Tools(ctx context.Context) ([]Tool, error)
func (c *MCPClient) Close() error
```

Usage notes:

- `MCPTransportHTTP` is the default built-in transport and uses the official MCP Go SDK's streamable HTTP client transport.
- `MCPTransportSSE` uses the official MCP Go SDK's SSE client transport.
- For stdio or other custom transports, create the transport with `github.com/modelcontextprotocol/go-sdk/mcp` and pass it through `Transport`.
- `Tools(ctx)` converts remote MCP tools into ordinary `sdk.Tool` values suitable for `WithTools(...)`.
- MCP tool schemas are converted from MCP `InputSchema` into `*jsonschema.Schema`.
- MCP execution wrappers call `tools/call` and return concatenated text content to the model.

### Streaming

```go
type StreamPartType string

const (
    StreamPartTypeTextStart           StreamPartType = "text-start"
    StreamPartTypeTextDelta           StreamPartType = "text-delta"
    StreamPartTypeTextEnd             StreamPartType = "text-end"
    StreamPartTypeReasoningStart      StreamPartType = "reasoning-start"
    StreamPartTypeReasoningDelta      StreamPartType = "reasoning-delta"
    StreamPartTypeReasoningEnd        StreamPartType = "reasoning-end"
    StreamPartTypeToolInputStart      StreamPartType = "tool-input-start"
    StreamPartTypeToolInputDelta      StreamPartType = "tool-input-delta"
    StreamPartTypeToolInputEnd        StreamPartType = "tool-input-end"
    StreamPartTypeToolCall            StreamPartType = "tool-call"
    StreamPartTypeToolResult          StreamPartType = "tool-result"
    StreamPartTypeToolError           StreamPartType = "tool-error"
    StreamPartTypeToolOutputDenied    StreamPartType = "tool-output-denied"
    StreamPartTypeToolApprovalRequest StreamPartType = "tool-approval-request"
    StreamPartTypeToolProgress        StreamPartType = "tool-progress"
    StreamPartTypeSource              StreamPartType = "source"
    StreamPartTypeFile                StreamPartType = "file"
    StreamPartTypeStart               StreamPartType = "start"
    StreamPartTypeFinish              StreamPartType = "finish"
    StreamPartTypeStartStep           StreamPartType = "start-step"
    StreamPartTypeFinishStep          StreamPartType = "finish-step"
    StreamPartTypeError               StreamPartType = "error"
    StreamPartTypeAbort               StreamPartType = "abort"
    StreamPartTypeRaw                 StreamPartType = "raw"
)

type StreamPart interface {
    Type() StreamPartType
}

type TextStartPart struct {
    ID               string
    ProviderMetadata map[string]any
}

type TextDeltaPart struct {
    ID               string
    Text             string
    ProviderMetadata map[string]any
}

type TextEndPart struct {
    ID               string
    ProviderMetadata map[string]any
}

type ReasoningStartPart struct {
    ID               string
    ProviderMetadata map[string]any
}

type ReasoningDeltaPart struct {
    ID               string
    Text             string
    ProviderMetadata map[string]any
}

type ReasoningEndPart struct {
    ID               string
    ProviderMetadata map[string]any
}

type ToolInputStartPart struct {
    ID               string
    ToolName         string
    ProviderMetadata map[string]any
}

type ToolInputDeltaPart struct {
    ID               string
    Delta            string
    ProviderMetadata map[string]any
}

type ToolInputEndPart struct {
    ID               string
    ProviderMetadata map[string]any
}

type StreamToolCallPart struct {
    ToolCallID string
    ToolName   string
    Input      any
}

type StreamToolResultPart struct {
    ToolCallID string
    ToolName   string
    Input      any
    Output     any
}

type StreamToolErrorPart struct {
    ToolCallID string
    ToolName   string
    Error      error
}

type ToolOutputDeniedPart struct {
    ToolCallID string
    ToolName   string
}

type ToolApprovalRequestPart struct {
    ApprovalID string
    ToolCallID string
    ToolName   string
    Input      any
}

type ToolProgressPart struct {
    ToolCallID string
    ToolName   string
    Content    any
}

type StreamSourcePart struct {
    Source Source
}

type StreamFilePart struct {
    File GeneratedFile
}

type StartPart struct{}

type FinishPart struct {
    FinishReason    FinishReason
    RawFinishReason string
    TotalUsage      Usage
}

type StartStepPart struct{}

type FinishStepPart struct {
    FinishReason     FinishReason
    RawFinishReason  string
    Usage            Usage
    Response         ResponseMetadata
    ProviderMetadata map[string]any
}

type ErrorPart struct {
    Error error
}

type AbortPart struct {
    Reason string
}

type RawPart struct {
    RawValue any
}

type StreamResult struct {
    Stream   <-chan StreamPart
    Steps    []StepResult
    Messages []Message
}

func (sr *StreamResult) Text() (string, error)
func (sr *StreamResult) ToResult() (*GenerateResult, error)
```

### Usage, Sources, Files, Response Metadata

```go
type Usage struct {
    InputTokens        int
    OutputTokens       int
    TotalTokens        int
    ReasoningTokens    int
    CachedInputTokens  int
    InputTokenDetails  InputTokenDetail
    OutputTokenDetails OutputTokenDetail
}

type InputTokenDetail struct {
    CacheReadTokens     int
    CacheCreationTokens int
}

type OutputTokenDetail struct {
    TextTokens      int
    ReasoningTokens int
    AudioTokens     int
}

type Source struct {
    SourceType       string
    ID               string
    URL              string
    Title            string
    ProviderMetadata map[string]any
}

type GeneratedFile struct {
    Data      string
    MediaType string
}

type ResponseMetadata struct {
    ID        string
    ModelID   string
    Timestamp time.Time
    Headers   map[string]string
}
```

### Embeddings

```go
type EmbeddingProvider interface {
    DoEmbed(ctx context.Context, params EmbedParams) (*EmbedResult, error)
}

type EmbeddingModel struct {
    ID                   string
    Provider             EmbeddingProvider
    MaxEmbeddingsPerCall int
}

type EmbedParams struct {
    Model      *EmbeddingModel
    Values     []string
    Dimensions *int
}

type EmbedResult struct {
    Embeddings [][]float64
    Usage      EmbeddingUsage
}

type EmbeddingUsage struct {
    Tokens int
}

type EmbedOption func(*embedConfig)

func WithEmbeddingModel(model *EmbeddingModel) EmbedOption
func WithDimensions(d int) EmbedOption
```

## Package `provider/openai/completions`

Implements the OpenAI Chat Completions API and OpenAI-compatible `/chat/completions` backends.

```go
type Provider struct { /* unexported fields */ }

type Option func(*Provider)

func WithAPIKey(apiKey string) Option
func WithBaseURL(baseURL string) Option
func WithHTTPClient(client *http.Client) Option
func New(options ...Option) *Provider

func (p *Provider) Name() string
func (p *Provider) ListModels(ctx context.Context) ([]sdk.Model, error)
func (p *Provider) Test(ctx context.Context) *sdk.ProviderTestResult
func (p *Provider) TestModel(ctx context.Context, modelID string) (*sdk.ModelTestResult, error)
func (p *Provider) ChatModel(id string) *sdk.Model
func (p *Provider) DoGenerate(ctx context.Context, params sdk.GenerateParams) (*sdk.GenerateResult, error)
func (p *Provider) DoStream(ctx context.Context, params sdk.GenerateParams) (*sdk.StreamResult, error)
```

Default option values:

- `WithBaseURL`: `https://api.openai.com/v1`
- `WithHTTPClient`: `&http.Client{}`

Discovery endpoints:

- `ListModels`: `GET /models`
- `Test`: `GET /models?limit=1`
- `TestModel`: `GET /models/{id}`

## Package `provider/openai/responses`

Implements the OpenAI Responses API with reasoning summaries, annotations, and flat input mapping.

```go
type Provider struct { /* unexported fields */ }

type Option func(*Provider)

func WithAPIKey(apiKey string) Option
func WithBaseURL(baseURL string) Option
func WithHTTPClient(client *http.Client) Option
func New(options ...Option) *Provider

func (p *Provider) Name() string
func (p *Provider) ListModels(ctx context.Context) ([]sdk.Model, error)
func (p *Provider) Test(ctx context.Context) *sdk.ProviderTestResult
func (p *Provider) TestModel(ctx context.Context, modelID string) (*sdk.ModelTestResult, error)
func (p *Provider) ChatModel(id string) *sdk.Model
func (p *Provider) DoGenerate(ctx context.Context, params sdk.GenerateParams) (*sdk.GenerateResult, error)
func (p *Provider) DoStream(ctx context.Context, params sdk.GenerateParams) (*sdk.StreamResult, error)
```

Default option values:

- `WithBaseURL`: `https://api.openai.com/v1`
- `WithHTTPClient`: `&http.Client{}`

Discovery endpoints:

- `ListModels`: `GET /models`
- `Test`: `GET /models?limit=1`
- `TestModel`: `GET /models/{id}`

Responses-specific behavior:

- assistant reasoning maps to `GenerateResult.Reasoning`
- URL citation annotations map to `GenerateResult.Sources`
- function-call outputs map to tool-call and tool-result structures

## Package `provider/anthropic/messages`

Implements the Anthropic Messages API.

```go
type ThinkingConfig struct {
    Type         string
    BudgetTokens int
}

type Provider struct { /* unexported fields */ }

type Option func(*Provider)

func WithAPIKey(apiKey string) Option
func WithAuthToken(token string) Option
func WithBaseURL(baseURL string) Option
func WithHTTPClient(client *http.Client) Option
func WithHeaders(headers map[string]string) Option
func WithThinking(cfg ThinkingConfig) Option
func New(options ...Option) *Provider

func (p *Provider) Name() string
func (p *Provider) ListModels(ctx context.Context) ([]sdk.Model, error)
func (p *Provider) Test(ctx context.Context) *sdk.ProviderTestResult
func (p *Provider) TestModel(ctx context.Context, modelID string) (*sdk.ModelTestResult, error)
func (p *Provider) ChatModel(id string) *sdk.Model
func (p *Provider) DoGenerate(ctx context.Context, params sdk.GenerateParams) (*sdk.GenerateResult, error)
func (p *Provider) DoStream(ctx context.Context, params sdk.GenerateParams) (*sdk.StreamResult, error)
```

Default option values:

- `WithBaseURL`: `https://api.anthropic.com/v1`
- default API version header: `2023-06-01`
- `WithHTTPClient`: `&http.Client{}`

Thinking config notes:

- `Type` supports `"enabled"`, `"adaptive"`, or `"disabled"`
- `BudgetTokens` is required when `Type == "enabled"`

Discovery endpoints:

- `ListModels`: `GET /v1/models`
- `Test`: `GET /v1/models?limit=1`
- `TestModel`: `GET /v1/models/{id}`

## Package `provider/google/generativeai`

Implements the Google Generative AI API for Gemini chat models.

```go
type Provider struct { /* unexported fields */ }

type Option func(*Provider)

func WithAPIKey(apiKey string) Option
func WithBaseURL(baseURL string) Option
func WithHTTPClient(client *http.Client) Option
func New(options ...Option) *Provider

func (p *Provider) Name() string
func (p *Provider) ListModels(ctx context.Context) ([]sdk.Model, error)
func (p *Provider) Test(ctx context.Context) *sdk.ProviderTestResult
func (p *Provider) TestModel(ctx context.Context, modelID string) (*sdk.ModelTestResult, error)
func (p *Provider) ChatModel(id string) *sdk.Model
func (p *Provider) DoGenerate(ctx context.Context, params sdk.GenerateParams) (*sdk.GenerateResult, error)
func (p *Provider) DoStream(ctx context.Context, params sdk.GenerateParams) (*sdk.StreamResult, error)
```

Default option values:

- `WithBaseURL`: `https://generativelanguage.googleapis.com/v1beta`
- `WithHTTPClient`: `&http.Client{}`

Model ID rules:

- plain names like `gemini-2.5-flash` are accepted
- full paths like `publishers/google/models/gemini-2.5-flash` are also accepted

Discovery endpoints:

- `ListModels`: `GET /v1beta/models`
- `Test`: `GET /v1beta/models?pageSize=1`
- `TestModel`: `GET /v1beta/models/{id}`

## Package `provider/openai/embedding`

Implements the OpenAI Embeddings API.

```go
type Provider struct { /* unexported fields */ }

type Option func(*Provider)

func WithAPIKey(apiKey string) Option
func WithBaseURL(baseURL string) Option
func WithHTTPClient(client *http.Client) Option
func New(options ...Option) *Provider

func (p *Provider) EmbeddingModel(id string) *sdk.EmbeddingModel
func (p *Provider) DoEmbed(ctx context.Context, params sdk.EmbedParams) (*sdk.EmbedResult, error)
```

Default option values:

- `WithBaseURL`: `https://api.openai.com/v1`
- `WithHTTPClient`: `&http.Client{}`

Behavior notes:

- `EmbeddingModel(id)` returns a model with `MaxEmbeddingsPerCall: 2048`
- `DoEmbed` calls `POST /embeddings` with `encoding_format: "float"`

## Package `provider/google/embedding`

Implements the Google embedding API.

```go
type Provider struct { /* unexported fields */ }

type Option func(*Provider)

func WithAPIKey(apiKey string) Option
func WithBaseURL(baseURL string) Option
func WithHTTPClient(client *http.Client) Option
func WithTaskType(taskType string) Option
func New(options ...Option) *Provider

func (p *Provider) EmbeddingModel(id string) *sdk.EmbeddingModel
func (p *Provider) DoEmbed(ctx context.Context, params sdk.EmbedParams) (*sdk.EmbedResult, error)
```

Default option values:

- `WithBaseURL`: `https://generativelanguage.googleapis.com/v1beta`
- `WithHTTPClient`: `&http.Client{}`

Task type values:

- `RETRIEVAL_QUERY`
- `RETRIEVAL_DOCUMENT`
- `SEMANTIC_SIMILARITY`
- `CLASSIFICATION`
- `CLUSTERING`
- `QUESTION_ANSWERING`
- `FACT_VERIFICATION`
- `CODE_RETRIEVAL_QUERY`

Behavior notes:

- `EmbeddingModel(id)` returns a model with `MaxEmbeddingsPerCall: 2048`
- single-value embedding uses `embedContent`
- multi-value embedding uses `batchEmbedContents`

## Selection Cheatsheet

- Broad OpenAI-compatible chat API: `provider/openai/completions`
- OpenAI Responses features such as reasoning summaries or citation annotations: `provider/openai/responses`
- Claude and extended thinking: `provider/anthropic/messages`
- Gemini chat and tool calling: `provider/google/generativeai`
- OpenAI-compatible embeddings: `provider/openai/embedding`
- Gemini embeddings with task-type tuning: `provider/google/embedding`
