Run chat completions
Run chat completions, the unified response envelope, tokenize, and count_tokens over the Algenta LLM API — with streaming, from curl, Python, TypeScript, or the CLI.
The Algenta LLM API exposes an OpenAI-shaped surface for text generation and token accounting. This guide covers the four request-side routes: POST /v1/chat/completions (a chat transcript in, an assistant message out), POST /v1/responses (a unified envelope over the same models), and POST /v1/tokenize / POST /v1/count_tokens (deterministic token accounting). Chat and responses both support streaming.
Every route names a model id. Use a built-in utility model for deterministic behavior, or a provider-backed id for a real LLM — see LLM models & providers.
Before you start
You need:
An API key sent as
Authorization: Bearer $ALGENTA_API_KEY. See Authentication.$ALGENTA_API_URL—https://api.algenta.ai(hosted) or your engine, e.g.http://localhost:8000.A
modelid fromGET /v1/models. The examples useprovider.openai:gpt-4o; substitute any chat-capable id you see in the catalog (the built-intext.tokenizeralso serves chat deterministically).
Chat completions
Send an ordered messages transcript. Each message has a role (system, user, assistant, developer, or tool) and content.
curl -sS -X POST "$ALGENTA_API_URL/v1/chat/completions" \
-H "Authorization: Bearer $ALGENTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "provider.openai:gpt-4o",
"messages": [
{"role": "system", "content": "You are concise."},
{"role": "user", "content": "Summarize the CAP theorem in one sentence."}
]
}'import os
from decision_engine import AlgentaClient
client = AlgentaClient(
api_key=os.environ["ALGENTA_API_KEY"],
base_url=os.environ.get("ALGENTA_API_URL", "https://api.algenta.ai"),
)
result = client.chat_completions(
[
{"role": "system", "content": "You are concise."},
{"role": "user", "content": "Summarize the CAP theorem in one sentence."},
],
model="provider.openai:gpt-4o",
)
print(result.choices[0].message.content)The 200 response is a chat.completion: one assistant choices[0].message.content, plus usage and — for provider-routed models — which backend served it.
Stream the completion
Set stream: true to receive Server-Sent Events instead of one JSON body. The stream emits chat.completion.chunk events with incremental delta.content, then a final data: [DONE].
Tool calling
Pass tools (a list of function definitions) on a provider-backed model and the assistant message can answer with tool_calls instead of (or alongside) content. finish_reason is "tool_calls" whenever the model called one; a request that never sets tools keeps returning finish_reason: "stop" exactly as before. tool_choice ("auto", "required", "none", or {"type": "function", "function": {"name": "..."}}) and parallel_tool_calls are optional. Non-streaming only for now — pass stream: true together with tools and the engine returns 422 model_capability_unsupported rather than silently dropping the tool call from the SSE stream.
The assistant message carries tool_calls instead of (or alongside) text, and the arguments are always a JSON-encoded string (function.arguments), matching the OpenAI wire shape regardless of which backend actually served the request:
To continue the conversation, append the assistant's tool_calls message and a role: "tool" message carrying the result (tool_call_id must match the call it answers):
Per-backend tool-calling support
Backend
Tools
tool_choice
openai, openai_compatible, groq, xai, mistral
Full — forwarded verbatim
"auto", "required", "none", or a named-function choice
anthropic
Full — translated to Claude's tool_use/tool_result blocks
Same set, translated to Claude's tool_choice
google_genai
Full — translated to functionDeclarations; Gemini assigns no call id, so the engine synthesizes one
Same set, translated to functionCallingConfig
cohere
Full
"auto" and "required"/"none" only — forcing one named function returns 422 model_capability_unsupported (Cohere's Chat v2 API has no per-function forcing)
ollama
Full
"auto" only — forcing "required"/"none"/a named function returns 422 model_capability_unsupported (/api/chat has no request-side forcing knob)
algenta_local
Supported on a checkpoint with a chat template (rendered into the Qwen3 template's tools preamble; <tool_call> blocks in the generation are parsed back into structured tool_calls) — refuses 422 model_capability_unsupported on a checkpoint with no chat template
"auto" (default) and "none" only — the template's preamble is a hint the model may act on, not a mechanism that forces one, so "required"/a named-function choice return 422 model_capability_unsupported
text.tokenizer
Not supported — 422 model_capability_unsupported
—
The unified response envelope
POST /v1/responses runs the same models behind one envelope. The response carries output items and usage, and supports stream: true. input accepts either of two shapes, which are never mixed:
Legacy shape — a single string, or a list of strings. Each string is an INDEPENDENT single-turn request against the model; a list of N strings makes N separate completions in one call, not a conversation. This is unchanged from before and is what every example below without
tools/previous_response_iduses.Typed shape — a list of OpenResponses-style items, each an object with a
type:message({"type": "message", "role": "user"|"assistant"|"system"|"developer", "content": "..."}),function_call(an assistant tool call, mirroringtool_callson a Chat Completions message), orfunction_call_output(a tool's result, mirroring arole: "tool"message). A typed array is processed as ONE multi-turn conversation, exactly like a Chat Completionsmessageslist. The engine classifies a list as typed the moment every item is an object with atypekey; anything else falls back to the legacy shape.
The 200 response is a response object with status: "completed", an output array, and usage.
Tool calling and multi-turn conversations
Pass tools/tool_choice/parallel_tool_calls together with the typed input-array shape to run a real multi-turn conversation with tool calling — the same knobs, translation, and per-backend support matrix as chat completions' tool calling above. A tool-call-only turn returns content[0].text: null alongside a populated content[0].tool_calls and finish_reason: "tool_calls". As with chat completions, stream: true together with a turn that calls a tool returns 422 model_capability_unsupported rather than dropping the tool call from the SSE stream.
To continue the conversation, send only the NEW turn's items (a function_call_output answering the prior tool call, or a new message) and set previous_response_id to the id from the prior call — the engine prepends that call's stored history for you:
Tokenize and count tokens
POST /v1/tokenize and POST /v1/count_tokens run a tokenizer model deterministically. They default to text.tokenizer; pass any tokenizer-capable model.
/v1/tokenize returns { model, tokenizer_kind, tokens, token_count }; /v1/count_tokens returns { model, tokenizer_kind, token_count }.
Troubleshooting
Next steps
Last updated
Was this helpful?