Skip to content
skyl

provider/openai

GPT, native. Ships inside the core module.

The OpenAI adapter reaches the GPT family. It ships inside the core module, so it costs you no dependencies — it is written against net/http and encoding/json.

Reference#

func New(apiKey string, opts ...Option) *Provider

Parameters

  • apiKey — sent as Authorization: Bearer.
  • opts — functional options, applied in order.
OptionSignatureDefaultDescription
WithBaseURLfunc WithBaseURL(url string) OptionOpenAI's own hostOverrides the API host — an Azure deployment, a proxy, or the sandbox.
WithHTTPClientfunc WithHTTPClient(hc *http.Client) Optionhttp.DefaultClientSupplies the *http.Client used for every request.
WithOrganizationfunc WithOrganization(org string) OptionSets the OpenAI-Organization header, for accounts that bill per org.
WithProjectfunc WithProject(project string) OptionSets the OpenAI-Project header.
WithMaxTokensFieldfunc WithMaxTokensField(field string) Optionmax_completion_tokensChooses which wire field carries Request.MaxTokens. OpenAI renamed max_tokens to max_completion_tokens; a host that has not followed needs the old name.

Caveats

  • It shares one implementation with openaicompat (internal/oai), so request mapping, response parsing, streaming and error classification are byte-identical. See the comparison.
  • Thinking is ignored unless both Enabled and Effort are set. So &Thinking{Enabled: false} does nothing — an explicit "off" has no wire representation here.
  • Effort: max is sent literally, and OpenAI does not define that value. Expect a 400.
  • ProviderOptions is a shallow top-level merge. Setting a nested object replaces it wholesale.
  • ToolResult.IsError is lossy: it prefixes "error: " to the content and drops the flag entirely when the content is empty.
  • Model listing reports almost nothing — no display name, context window or output cap. The gap is upstream.
  • StopStopSequence is never produced. A stop-sequence hit arrives as plain stop, so it becomes StopEndTurn.

Usage#

Constructing

goCompiles
client := skyl.New(openai.New(os.Getenv("OPENAI_API_KEY")))
client := skyl.New(openai.New(os.Getenv("OPENAI_API_KEY")))

An organisation and project

goCompiles
p := openai.New(key,
	openai.WithOrganization(os.Getenv("OPENAI_ORG")),
	openai.WithProject(os.Getenv("OPENAI_PROJECT")),
)
p := openai.New(key,
	openai.WithOrganization(os.Getenv("OPENAI_ORG")),
	openai.WithProject(os.Getenv("OPENAI_PROJECT")),
)

Azure or a host that has not renamed max_tokens

goCompiles
// OpenAI renamed max_tokens to max_completion_tokens; a host that has not
// followed needs the old name.
p := openai.New(key,
	openai.WithBaseURL("https://my-resource.openai.azure.com/openai/v1"),
	openai.WithMaxTokensField("max_tokens"),
)
// OpenAI renamed max_tokens to max_completion_tokens; a host that has not
// followed needs the old name.
p := openai.New(key,
	openai.WithBaseURL("https://my-resource.openai.azure.com/openai/v1"),
	openai.WithMaxTokensField("max_tokens"),
)

Turning reasoning off, which Thinking cannot do here

goCompiles
req.ProviderOptions = map[string]any{"reasoning_effort": "minimal"}
req.ProviderOptions = map[string]any{"reasoning_effort": "minimal"}

Against the sandbox

goCompiles
p := openai.New("sandbox-key",
	openai.WithBaseURL("http://127.0.0.1:8099/openai/v1"))
p := openai.New("sandbox-key",
	openai.WithBaseURL("http://127.0.0.1:8099/openai/v1"))

Troubleshooting#

Turning reasoning off did not reduce cost

&Thinking{Enabled: false} is ignored by this adapter. Send reasoning_effort through ProviderOptions.

A 400 mentioning max_tokens

The host expects the older field name. Use WithMaxTokensField("max_tokens").

My generationConfig-style override lost other fields

The merge is shallow: a nested object you set replaces the whole object. Restate every sibling key skyl would have set — including messages and tools, which are the dangerous ones.

Streaming reports zero usage

The host must honour stream_options.include_usage. OpenAI itself does; many compatible hosts do not.

Edit this page on GitHub