4.5. OpenAI-compatible API client (chat, embeddings, audio, vision, …)

A pure-daslang client for OpenAI-compatible REST APIs — OpenAI itself, plus any server that speaks the same surface (Ollama, OpenRouter, Kokoro, LM Studio, vLLM, …). Built on dashv for HTTP and daslib/json_boost for serialization.

The API is split into one module per section; require only what you use:

require openai/openai_chat          // chat completions, tools, JSON mode, streaming
require openai/openai_embeddings    // text embeddings
require openai/openai_models        // list / retrieve models
require openai/openai_completions   // legacy text completions
require openai/openai_audio         // text-to-speech and transcription
require openai/openai_moderations   // content moderation
require openai/openai_images        // image generation
require openai/openai_vision        // image-input chat

Each section module re-exports openai_common (the client, the unified OpenAIError, and the HTTP transport), so requiring a section is enough.

Every consumer root MUST set options rtti — otherwise the @optional / @rename field annotations are ignored and requests serialize every field (e.g. "n":0), which real servers reject:

options rtti
require openai/openai_chat

let client = openai_client("https://api.openai.com/v1", get_env("OPENAI_API_KEY"))
print("{chat_text(client, "gpt-4o-mini", "Say hi in one sentence.")}\n")

See OPENAI-01 — Your First Chat for a hands-on tutorial, or the rest of the dasOPENAI tutorials.

4.5.1. Structures

OpenAIClient

Connection + auth config. Override base_url to target any OpenAI-compatible server.

Fields:
  • base_url : string = “https://api.openai.com/v1” - < API base URL, no trailing slash.

  • api_key : string - < Bearer token; empty for servers that need no auth (e.g. local Ollama).

  • organization : string - < Optional OpenAI-Organization header value; empty to omit.

  • timeout_seconds : int = 60 - < Per-request timeout in seconds; 0 disables it.

  • default_model : string - < Optional default model id for convenience helpers.

OpenAIError

Unified error. kind is “transport” | “http” | “api” | “decode”.

Fields:
  • kind : string - < Error category: “transport” | “http” | “api” | “decode”; empty means no error.

  • status : int - < HTTP status code, or 0 when the request never completed.

  • message : string - < Human-readable error message.

  • _type : string - < Provider error type, when the server returned one.

  • code : string - < Provider error code, when the server returned one.

Usage

Token accounting returned with most responses.

Fields:
  • prompt_tokens : int - < Tokens consumed by the prompt.

  • completion_tokens : int - < Tokens in the generated completion.

  • total_tokens : int - < Prompt + completion tokens.

HttpOutcome

Internal transport result of a JSON request (post_json / get_json).

Fields:
  • ok : bool - < True on a 2xx response.

  • status : int - < HTTP status code.

  • body : string - < Raw response body.

  • error : OpenAIError - < Populated when ok is false.

BytesOutcome

Internal transport result of a binary request (post_for_bytes).

Fields:
  • ok : bool - < True on a 2xx response.

  • status : int - < HTTP status code.

  • bytes : array<uint8> - < Raw response bytes (e.g. audio).

  • error : OpenAIError - < Populated when ok is false.

ResponseFormat

Chat response_format: _type is “text” | “json_object” | “json_schema”.

Fields:
  • _type : string - < “text” | “json_object” | “json_schema”.

  • json_schema : string - < Raw JSON-schema string, when _type is “json_schema”.

FunctionDef

A tool’s function declaration. parameters is a raw JSON-schema string.

Fields:
  • name : string - < Function name the model may call.

  • description : string - < What the function does (helps the model decide when to call it).

  • parameters : string - < Raw JSON-schema string describing the arguments.

Tool

A tool the model may call. _type is “function”.

Fields:
  • _type : string - < Tool type (“function”).

  • _function : FunctionDef - < The function declaration.

ToolCallFunction

The function a tool call targets.

Fields:
  • name : string - < Function name.

  • arguments : string - < JSON-encoded argument string.

ToolCall

A tool call requested by the model. _function.arguments is a JSON string.

Fields:
  • id : string - < Unique id for this call; echo it back in the tool result.

  • _type : string - < Tool type (“function”).

  • _function : ToolCallFunction - < The requested function + arguments.

ChatMessage

A single chat message. role is “system” | “user” | “assistant” | “tool”.

Fields:
  • role : string - < “system” | “user” | “assistant” | “tool”.

  • content : string - < Message text; may be empty when tool_calls is set.

  • name : string - < Optional author name.

  • tool_calls : array< ToolCall> - < Tool calls the assistant is requesting.

  • tool_call_id : string - < For role “tool”: the id of the call this message answers.

ChatCompletionRequest

Request body for /chat/completions. Default-valued optional fields are omitted on send.

Fields:
  • model : string - < Chat model id.

  • messages : array< ChatMessage> - < The conversation, in order.

  • temperature : float - < Sampling temperature.

  • top_p : float - < Nucleus-sampling probability mass.

  • n : int - < Number of choices to generate.

  • stream : bool - < Request a streamed response (set automatically by chat_stream).

  • max_tokens : int - < Maximum tokens to generate.

  • max_completion_tokens : int - < Newer cap on generated tokens.

  • frequency_penalty : float - < Penalize tokens by how often they have appeared.

  • presence_penalty : float - < Penalize tokens that already appeared at all.

  • seed : int - < Seed for (best-effort) deterministic sampling.

  • stop : array<string> - < Stop sequences.

  • user : string - < Optional end-user id for abuse monitoring.

  • response_format : string - < JSON-mode format (see json_object_format).

  • tools : array< Tool> - < Tools the model may call.

  • tool_choice : string - < Tool selection (“auto”, “none”, or a specific name).

ChatChoice

One completion choice.

Fields:
  • index : int - < Index of this choice.

  • message : ChatMessage - < The assistant message.

  • finish_reason : string - < Why generation stopped (“stop”, “length”, “tool_calls”, …).

ChatCompletionResponse

Response body for a non-streaming /chat/completions call.

Fields:
  • id : string - < Completion id.

  • _object : string - < Object type (“chat.completion”).

  • created : int64 - < Unix creation time.

  • model : string - < Model that produced the response.

  • choices : array< ChatChoice> - < Generated choices.

  • usage : Usage - < Token accounting.

ChatResult

Outcome of chat: when ok is true response is valid, else inspect error.

Fields:
ToolCallFunctionDelta

Incremental function fields in a streamed tool-call delta. arguments accretes across frames.

Fields:
  • name : string - < Function name (sent once, on the first frame for this call).

  • arguments : string - < Partial JSON argument text; concatenate across frames in order.

ToolCallDelta

One streamed tool-call fragment. Fragments with the same index reassemble into one ToolCall.

Fields:
  • index : int - < Which tool call this fragment belongs to.

  • id : string - < Call id (sent once, on the first frame).

  • _type : string - < Tool type (“function”), sent once.

  • _function : ToolCallFunctionDelta - < Incremental function name / arguments.

ChatMessageDelta

Incremental message fields in a streamed chunk (object == “chat.completion.chunk”).

Fields:
  • role : string - < Role, sent on the first delta.

  • content : string - < Incremental text content.

  • tool_calls : array< ToolCallDelta> - < Incremental tool-call fragments (reassembled by chat_stream).

ChunkChoice

One choice within a streamed chunk.

Fields:
  • index : int - < Index of this choice.

  • delta : ChatMessageDelta - < Incremental message fields for this frame.

  • finish_reason : string - < Set on the final chunk for this choice.

ChatCompletionChunk

One streamed delta frame.

Fields:
  • id : string - < Completion id (stable across chunks).

  • _object : string - < Object type (“chat.completion.chunk”).

  • created : int64 - < Unix creation time.

  • model : string - < Model producing the stream.

  • choices : array< ChunkChoice> - < Incremental choices in this frame.

ChatStreamResult

Outcome of chat_stream: content is the full accumulated assistant text.

Fields:
  • ok : bool - < True on a successful stream.

  • content : string - < Full accumulated assistant text.

  • finish_reason : string - < Why generation stopped (“stop”, “tool_calls”, …).

  • tool_calls : array< ToolCall> - < Reassembled tool calls (empty unless the model streamed any).

  • error : OpenAIError - < Error detail on failure.

EmbeddingRequest

Request body for /embeddings. input is always sent as an array of strings (a single string is just a one-element array).

Fields:
  • model : string - < Embedding model id.

  • input : array<string> - < Texts to embed, one element per string.

  • encoding_format : string - < “float” (default) or “base64”.

  • dimensions : int - < Optional output dimensionality, for models that support it.

  • user : string - < Optional end-user id for abuse monitoring.

EmbeddingUsage

Token accounting for an embeddings request.

Fields:
  • prompt_tokens : int - < Tokens in the input.

  • total_tokens : int - < Total tokens billed.

EmbeddingData

One input’s embedding.

Fields:
  • _object : string - < Object type (“embedding”).

  • index : int - < Position in the input array.

  • embedding : array<float> - < The embedding vector.

EmbeddingResponse

Response body for /embeddings.

Fields:
  • _object : string - < Object type (“list”).

  • data : array< EmbeddingData> - < One EmbeddingData per input, in order.

  • model : string - < Model that produced the embeddings.

  • usage : EmbeddingUsage - < Token accounting.

EmbeddingResult

Outcome of embeddings: when ok is true response is valid, else inspect error.

Fields:
  • ok : bool - < True when response is valid.

  • response : EmbeddingResponse - < Decoded response on success.

  • error : OpenAIError - < Error detail on failure.

Model

A single model entry.

Fields:
  • id : string - < Model id (e.g. “gpt-4o-mini”).

  • _object : string - < Object type (“model”).

  • created : int64 - < Unix creation time, when provided.

  • owned_by : string - < Owning organization, when provided.

ModelsResult

Outcome of list_models: models valid when ok is true.

Fields:
  • ok : bool - < True when models is valid.

  • models : array< Model> - < Available models on success.

  • error : OpenAIError - < Error detail on failure.

ModelResult

Outcome of retrieve_model: model valid when ok is true.

Fields:
  • ok : bool - < True when model is valid.

  • model : Model - < The retrieved model on success.

  • error : OpenAIError - < Error detail on failure.

CompletionRequest

Request body for the legacy /completions endpoint.

Fields:
  • model : string - < Completion model id.

  • prompt : string - < The prompt to complete.

  • max_tokens : int - < Maximum tokens to generate.

  • temperature : float - < Sampling temperature.

  • top_p : float - < Nucleus-sampling probability mass.

  • n : int - < Number of completions to generate.

  • stop : array<string> - < Stop sequences.

  • seed : int - < Seed for (best-effort) deterministic sampling.

  • user : string - < Optional end-user id for abuse monitoring.

CompletionChoice

One generated completion.

Fields:
  • text : string - < The completion text.

  • index : int - < Index of this choice.

  • finish_reason : string - < Why generation stopped (e.g. “stop”, “length”).

CompletionResponse

Response body for /completions.

Fields:
  • id : string - < Completion id.

  • _object : string - < Object type (“text_completion”).

  • created : int64 - < Unix creation time.

  • model : string - < Model that produced the completion.

  • choices : array< CompletionChoice> - < Generated choices.

  • usage : Usage - < Token accounting.

CompletionResult

Outcome of completions: response valid when ok is true.

Fields:
  • ok : bool - < True when response is valid.

  • response : CompletionResponse - < Decoded response on success.

  • error : OpenAIError - < Error detail on failure.

SpeechRequest

Request body for /audio/speech. The response is raw audio bytes, not JSON.

Fields:
  • model : string - < TTS model id.

  • input : string - < Text to synthesize.

  • voice : string - < Voice name (e.g. “alloy”).

  • response_format : string - < Audio format (“mp3”, “wav”, …); server default if empty.

  • speed : float - < Playback speed multiplier (1.0 = normal).

SpeechResult

Outcome of speech: audio holds the raw bytes when ok is true.

Fields:
  • ok : bool - < True when audio holds the result.

  • audio : array<uint8> - < Raw audio bytes on success.

  • error : OpenAIError - < Error detail on failure.

TranscriptionResult

Outcome of transcribe / translate: text valid when ok is true.

Fields:
  • ok : bool - < True when text is valid.

  • text : string - < Recognized text on success.

  • error : OpenAIError - < Error detail on failure.

ModerationRequest

Request body for /moderations. input is always sent as an array of strings.

Fields:
  • model : string - < Moderation model id.

  • input : array<string> - < Texts to classify, one element per string.

ModerationCategoryResult

One moderation verdict. categories and category_scores are keyed by category name (e.g. “violence”, “hate/threatening”), so no per-category field declarations are needed.

Fields:
  • flagged : bool - < True if the input was flagged in any category.

  • categories : table<string;bool> - < Per-category boolean verdicts, keyed by category name.

  • category_scores : table<string;double> - < Per-category confidence scores, keyed by category name.

ModerationResponse

Response body for /moderations.

Fields:
  • id : string - < Moderation request id.

  • model : string - < Model that produced the verdicts.

  • results : array< ModerationCategoryResult> - < One verdict per input.

ModerationResult

Outcome of moderations: response valid when ok is true.

Fields:
  • ok : bool - < True when response is valid.

  • response : ModerationResponse - < Decoded response on success.

  • error : OpenAIError - < Error detail on failure.

ImageRequest

Request body for /images/generations.

Fields:
  • prompt : string - < Text description of the desired image.

  • model : string - < Image model id.

  • n : int - < Number of images to generate.

  • size : string - < Image dimensions (e.g. “1024x1024”).

  • quality : string - < Quality hint (e.g. “standard”, “hd”).

  • style : string - < Style hint (e.g. “vivid”, “natural”).

  • response_format : string - < “url” or “b64_json”.

  • user : string - < Optional end-user id for abuse monitoring.

ImageData

One generated image.

Fields:
  • url : string - < Image URL (when response_format is “url”).

  • b64_json : string - < Base64-encoded image (when response_format is “b64_json”).

  • revised_prompt : string - < The prompt the model actually used, if it revised yours.

ImageResponse

Response body for /images/generations.

Fields:
  • created : int64 - < Unix creation time.

  • data : array< ImageData> - < Generated images.

ImageResult

Outcome of generate_image: response valid when ok is true.

Fields:
  • ok : bool - < True when response is valid.

  • response : ImageResponse - < Decoded response on success.

  • error : OpenAIError - < Error detail on failure.

4.5.2. Client and transport

configure_request(req: HttpRequest?#; client: OpenAIClient )

Applies auth (Bearer), the optional OpenAI-Organization header, and the client timeout to a manually-built request — shared by every transport path so they behave identically.

Arguments:
get_and_decode(client: OpenAIClient; path: string; response: auto(RT) ): OpenAIError

GETs path, then decodes a 2xx response into response (see post_and_decode).

Arguments:
get_json(client: OpenAIClient; path: string ): HttpOutcome

GETs path (with auth + org header + timeout) and returns the raw outcome.

Arguments:
openai_client(base_url: string; api_key: string = "" ): OpenAIClient

Builds a client for the given base URL (no trailing slash) and optional API key.

Arguments:
  • base_url : string

  • api_key : string

parse_error_body(status: int; body: string ): OpenAIError

Decodes an OpenAI {"error":{...}} body into an OpenAIError (falls back to a plain HTTP error).

Arguments:
  • status : int

  • body : string

percent_encode(s: string ): string

Percent-encodes a string for safe use as a single URL path segment (e.g. a model id like “google/gemma-…” whose ‘/’ would otherwise be parsed as extra path segments).

Arguments:
  • s : string

post_and_decode(client: OpenAIClient; path: string; body_json: string; response: auto(RT) ): OpenAIError

POSTs a JSON body, then decodes a 2xx response into response. Returns a default (empty-kind) OpenAIError on success, or the transport/decode error.

Arguments:
  • client : OpenAIClient

  • path : string

  • body_json : string

  • response : auto(RT)

post_for_bytes(client: OpenAIClient; path: string; body_json: string ): BytesOutcome

POSTs a JSON body and returns the raw response bytes (e.g. audio), or a parsed error.

Arguments:
post_json(client: OpenAIClient; path: string; body_json: string ): HttpOutcome

POSTs a JSON body and returns the raw outcome (status + body, or error).

Arguments:

4.5.3. Chat completions

chat(client: OpenAIClient; req: ChatCompletionRequest ): ChatResult

Sends a non-streaming /chat/completions request and decodes the response.

Arguments:
chat_stream(client: OpenAIClient; req: ChatCompletionRequest; on_delta: block<(delta:string):void> ): ChatStreamResult

Streams a /chat/completions response, invoking on_delta with each text increment as it arrives. Returns the full accumulated content plus status.

Text deltas (choices[0].delta.content) are accumulated into result.content; streamed tool-call fragments are reassembled by index into result.tool_calls (on_delta fires for text only). Tolerates CRLF line endings and SSE comment lines.

Arguments:
chat_text(client: OpenAIClient; model: string; prompt: string ): string

Convenience: one user turn, returns the assistant’s text (”” on error).

Arguments:
json_object_format(): string

Returns the response_format value for JSON mode (assign to req.response_format).

4.5.4. Embeddings

embed(client: OpenAIClient; model: string; text: string ): array<float>

Convenience: embed a single string, returns the vector (empty on error).

Arguments:
embeddings(client: OpenAIClient; req: EmbeddingRequest ): EmbeddingResult

Sends an /embeddings request and decodes the response.

Arguments:

4.5.5. Models

list_models(client: OpenAIClient ): ModelsResult

Lists available models (GET /models).

Arguments:
retrieve_model(client: OpenAIClient; model: string ): ModelResult

Retrieves a single model by id (GET /models/{id}).

Arguments:

4.5.6. Legacy completions

complete(client: OpenAIClient; model: string; prompt: string ): string

Convenience: completes prompt, returns the text (”” on error).

Arguments:
completions(client: OpenAIClient; req: CompletionRequest ): CompletionResult

Sends a legacy /completions request and decodes the response.

Arguments:

4.5.7. Audio (TTS and STT)

speak(client: OpenAIClient; model: string; voice: string; text: string ): array<uint8>

Convenience: synthesize text with voice, returns audio bytes (empty on error).

Arguments:
  • client : OpenAIClient

  • model : string

  • voice : string

  • text : string

speech(client: OpenAIClient; req: SpeechRequest ): SpeechResult

Synthesizes speech (POST /audio/speech); returns the raw audio bytes.

Arguments:
transcribe(client: OpenAIClient; model: string; file_path: string ): TranscriptionResult

Transcribes the audio file at file_path (POST /audio/transcriptions).

Arguments:
translate(client: OpenAIClient; model: string; file_path: string ): TranscriptionResult

Translates the audio file at file_path into English (POST /audio/translations).

Arguments:

4.5.8. Moderations

moderations(client: OpenAIClient; req: ModerationRequest ): ModerationResult

Classifies text for policy violations (POST /moderations).

Arguments:

4.5.9. Image generation

generate_image(client: OpenAIClient; req: ImageRequest ): ImageResult

Generates images from a prompt (POST /images/generations).

Arguments:

4.5.10. Vision

chat_vision(client: OpenAIClient; model: string; text: string; image_url: string; max_tokens: int = 300 ): ChatResult

One-shot vision request: a single user turn with text plus an image (http(s) URL or a data: URL). Returns the normal chat result (assistant text in choices[0].message.content).

Arguments:
  • client : OpenAIClient

  • model : string

  • text : string

  • image_url : string

  • max_tokens : int

vision_request_body(model: string; text: string; image_url: string; max_tokens: int = 300 ): string

Builds the JSON body for a one-shot vision request (a user turn with text + one image).

Arguments:
  • model : string

  • text : string

  • image_url : string

  • max_tokens : int