Text generation
POST /chat/completions generates a completion from a list of messages. model and messages
are required. temperature, max_tokens, top_p, stop, reasoning_effort, and stream are optional.
reasoning_effort sets how much a reasoning model thinks before it answers. List the models
to see which levels each one accepts and its default, and see the
chat completions reference for the details.
Any field this page doesn’t name is passed to the model as sent, so a parameter your model supports that these docs haven’t caught up with still reaches it.
Show the prompt
Help me set this up to use Bayle AI, an OpenAI-compatible API. Full guide: https://docs.bayle.ai/guides/text-generation/
Goal: add Bayle chat completions to this project, with streaming and function calling.
1. Find or create the OpenAI client for this project (Python or Node, whichever it already uses) and point it at Bayle:
Python: OpenAI(api_key=os.environ["BAYLE_API_KEY"], base_url="https://api.bayle.ai")
Node: new OpenAI({ apiKey: process.env.BAYLE_API_KEY, baseURL: 'https://api.bayle.ai' })
2. Pick a model: curl -s "https://api.bayle.ai/models?type=text" | jq -r '.data[] | select(.model_spec.capabilities.supportsFunctionCalling) | .id'
Show me the list and let me choose MODEL_ID. Use it for everything below.
3. Add a basic completion: client.chat.completions.create(model=MODEL_ID, messages=[system + user], temperature=0.7, max_tokens=200). The API adds no system message of its own, so send mine or none.
4. Add streaming with stream=True. Read every chunk, but guard against the usage event: its `choices` list is empty, so check `chunk.choices` before reading `choices[0]`. Read to the end of the stream; a 200 status does not prove it succeeded, because a failure can arrive as an error event inside the stream.
5. Add function calling: pass `tools` (type "function", with name, description and a JSON-schema `parameters`) and `tool_choice` ("auto", "required", or an object naming one function). When the model returns tool calls, run the function and send the result back as a tool message.
6. Test: run the streaming call with the prompt "Count to five." and show me the output. If function calling is wired, ask "What's the weather in Lisbon?" with a get_weather tool and show the tool call.
Rules:
1. The base URL is https://api.bayle.ai exactly as written. Append no path to it.
2. Read the key from the BAYLE_API_KEY environment variable. Never write the key itself into a file you create, a command, a commit or the chat. Where the tool keeps the key in its own settings screen, tell me where to paste it. If BAYLE_API_KEY is not set, stop and ask me to create a key at https://chat.bayle.ai/developers and export it.
3. Take model ids only from GET https://api.bayle.ai/models (no key needed). Never guess one.
4. Finish with one real test request, show me the result and list the files you changed.A basic completion
Section titled “A basic completion”completion = client.chat.completions.create( model="MODEL_ID", messages=[ {"role": "system", "content": "You are terse."}, {"role": "user", "content": "Why is the sky blue?"}, ], temperature=0.7, max_tokens=200,)print(completion.choices[0].message.content)const completion = await client.chat.completions.create({ model: 'MODEL_ID', messages: [ { role: 'system', content: 'You are terse.' }, { role: 'user', content: 'Why is the sky blue?' }, ], temperature: 0.7, max_tokens: 200,})console.log(completion.choices[0].message.content)curl https://api.bayle.ai/chat/completions \ -H "Authorization: Bearer $BAYLE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "MODEL_ID", "messages": [ {"role": "system", "content": "You are terse."}, {"role": "user", "content": "Why is the sky blue?"} ], "temperature": 0.7, "max_tokens": 200 }'System messages
Section titled “System messages”The API adds no system message and no other instructions of its own: a request reaches the model with exactly the messages you send. You can send your own system message, as the example above does, or none at all.
The Bayle web chat (chat.bayle.ai) is a client of this API, and it adds a Bayle system message to its own conversation requests. That message belongs to the chat, not to the API: a request you send to POST /chat/completions never carries it.
Streaming
Section titled “Streaming”Set stream to true and the response becomes a text/event-stream instead of a single JSON body.
stream = client.chat.completions.create( model="MODEL_ID", messages=[{"role": "user", "content": "Count to five."}], stream=True,)for chunk in stream: delta = chunk.choices[0].delta.content if chunk.choices else None if delta: print(delta, end="", flush=True)const stream = await client.chat.completions.create({ model: 'MODEL_ID', messages: [{ role: 'user', content: 'Count to five.' }], stream: true,})for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? '')}curl -N https://api.bayle.ai/chat/completions \ -H "Authorization: Bearer $BAYLE_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "MODEL_ID", "messages": [{"role": "user", "content": "Count to five."}], "stream": true}'What the stream looks like
Section titled “What the stream looks like”One data: line per event, each carrying a JSON object, separated by blank lines, ending with a
terminal data: [DONE] marker.
data: {"id":"...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
data: {"id":"...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"One"},"finish_reason":null}]}
data: {"id":"...","object":"chat.completion.chunk","choices":[],"usage":{"prompt_tokens":12,"completion_tokens":8,"total_tokens":20},"cost":{"usd":0.00002,"diem":0.0}}
data: [DONE]Two things about the end of a stream are worth building for.
The second-to-last event is a usage event: choices is empty and usage is populated. Code
that assumes every event has a choices[0] will trip over it. An SDK handles this for you.
If generation fails part-way, you get an error event inside the stream rather than a truncated body. It carries the same error envelope as a non-streaming failure, and it arrives before the terminal marker.
Function calling
Section titled “Function calling”Pass tools, and optionally tool_choice to steer the decision.
completion = client.chat.completions.create( model="MODEL_ID", messages=[{"role": "user", "content": "What's the weather in Lisbon?"}], tools=[ { "type": "function", "function": { "name": "get_weather", "description": "Look up current weather for a city.", "parameters": { "type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"], }, }, } ], tool_choice="auto",)tool_choice takes three forms: "auto", "required", or an object naming one function,
{"type": "function", "function": {"name": "get_weather"}}.
Built-in tools are given by type alone, with no function body:
{"tools": [{"type": "web_search"}]}Vision
Section titled “Vision”A message’s content may be an array of parts instead of a string. Mix text and images freely.
completion = client.chat.completions.create( model="VISION_MODEL_ID", messages=[ { "role": "user", "content": [ {"type": "text", "text": "What is in this image?"}, {"type": "image_url", "image_url": {"url": "https://example.com/photo.jpg"}}, ], } ],)The url may be a public https URL or a data: URI, so a local file works once base64 encoded:
import base64, pathlib
encoded = base64.b64encode(pathlib.Path("photo.jpg").read_bytes()).decode()image_part = {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{encoded}"}}Use a model whose type supports vision. List the models to find one.