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-Organizationheader 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
okis 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
okis 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
_typeis “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_callsis 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:
ok : bool - < True when
responseis valid.response : ChatCompletionResponse - < Decoded response on success.
error : OpenAIError - < Error detail on failure.
- 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
EmbeddingDataper 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
responseis 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
modelsis 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
modelis 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
responseis 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
audioholds 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
textis 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
responseis 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_formatis “url”).b64_json : string - < Base64-encoded image (when
response_formatis “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
responseis valid.response : ImageResponse - < Decoded response on success.
error : OpenAIError - < Error detail on failure.
4.5.2. Client and transport
configure_request (var req: HttpRequest?#; client: OpenAIClient)
get_and_decode (client: OpenAIClient; path: string; var response: auto(RT)) : OpenAIError
openai_client (base_url: string; api_key: string = “”) : OpenAIClient
post_for_bytes (client: OpenAIClient; path: string; body_json: string) : BytesOutcome
post_json (client: OpenAIClient; path: string; body_json: string) : HttpOutcome
- 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:
req : HttpRequest?#
client : OpenAIClient
- 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:
client : OpenAIClient
path : string
response : auto(RT)
- get_json(client: OpenAIClient; path: string ): HttpOutcome
GETs path (with auth + org header + timeout) and returns the raw outcome.
- Arguments:
client : OpenAIClient
path : string
- 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:
client : OpenAIClient
path : string
body_json : string
- post_json(client: OpenAIClient; path: string; body_json: string ): HttpOutcome
POSTs a JSON body and returns the raw outcome (status + body, or error).
- Arguments:
client : OpenAIClient
path : string
body_json : string
4.5.3. Chat completions
- chat(client: OpenAIClient; req: ChatCompletionRequest ): ChatResult
Sends a non-streaming /chat/completions request and decodes the response.
- Arguments:
client : OpenAIClient
req : ChatCompletionRequest
- 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:
client : OpenAIClient
req : ChatCompletionRequest
on_delta : block<(delta:string):void>
- chat_text(client: OpenAIClient; model: string; prompt: string ): string
Convenience: one user turn, returns the assistant’s text (”” on error).
- Arguments:
client : OpenAIClient
model : string
prompt : string
- 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:
client : OpenAIClient
model : string
text : string
- embeddings(client: OpenAIClient; req: EmbeddingRequest ): EmbeddingResult
Sends an /embeddings request and decodes the response.
- Arguments:
client : OpenAIClient
req : EmbeddingRequest
4.5.5. Models
- list_models(client: OpenAIClient ): ModelsResult
Lists available models (GET /models).
- Arguments:
client : OpenAIClient
- retrieve_model(client: OpenAIClient; model: string ): ModelResult
Retrieves a single model by id (GET /models/{id}).
- Arguments:
client : OpenAIClient
model : string
4.5.6. Legacy completions
- complete(client: OpenAIClient; model: string; prompt: string ): string
Convenience: completes prompt, returns the text (”” on error).
- Arguments:
client : OpenAIClient
model : string
prompt : string
- completions(client: OpenAIClient; req: CompletionRequest ): CompletionResult
Sends a legacy /completions request and decodes the response.
- Arguments:
client : OpenAIClient
req : CompletionRequest
4.5.7. Audio (TTS and STT)
speak (client: OpenAIClient; model: string; voice: string; text: string) : array<uint8>
speech (client: OpenAIClient; req: SpeechRequest) : SpeechResult
transcribe (client: OpenAIClient; model: string; file_path: string) : TranscriptionResult
translate (client: OpenAIClient; model: string; file_path: string) : TranscriptionResult
- 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:
client : OpenAIClient
req : SpeechRequest
- transcribe(client: OpenAIClient; model: string; file_path: string ): TranscriptionResult
Transcribes the audio file at file_path (POST /audio/transcriptions).
- Arguments:
client : OpenAIClient
model : string
file_path : string
- translate(client: OpenAIClient; model: string; file_path: string ): TranscriptionResult
Translates the audio file at file_path into English (POST /audio/translations).
- Arguments:
client : OpenAIClient
model : string
file_path : string
4.5.8. Moderations
- moderations(client: OpenAIClient; req: ModerationRequest ): ModerationResult
Classifies text for policy violations (POST /moderations).
- Arguments:
client : OpenAIClient
req : ModerationRequest
4.5.9. Image generation
- generate_image(client: OpenAIClient; req: ImageRequest ): ImageResult
Generates images from a prompt (POST /images/generations).
- Arguments:
client : OpenAIClient
req : ImageRequest
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