Skip to content

Chat & General Inference

Before You Run Examples

All examples in this page assume environment variables are available. For convenience, create a .env file in the repository root (you can copy from .env.example) with:

TUDELFT_TULIP_BASE_URL=https://api.tulip.tudelft.nl
TUDELFT_TULIP_API_KEY=YOUR_API_KEY
TUDELFT_TULIP_MODEL_ALIAS=chat
TUDELFT_TULIP_CAPABILITY=chat

Set TUDELFT_TULIP_BASE_URL to host root only (for example https://api.tulip.tudelft.nl). The Python helper normalizes it to a capability-specific /v1 endpoint automatically.

What these examples assume

  • The Python snippets on this page assume a local helper file common.py that loads environment variables and exports shared constants.
  • If you cloned this repository, examples/common.py is already present and the scripts run as shown below.
  • If you have not cloned the repo and are working with Python, expand the helper snippet below and place common.py next to the example you want to run.
  • Python run commands use pixi run python ...; dependencies come from pixi.toml.
  • Bash examples pretty-print JSON using jq, so you may need to install it.
  • TUDELFT_TULIP_CAPABILITY chooses the path segment (chat, code, embed).
  • TUDELFT_TULIP_MODEL_ALIAS chooses the deployed model alias.
If you have not cloned the repo and are working with Python, create common.py next to the example
common.py
import os

from dotenv import load_dotenv

load_dotenv()  # loads .env if present

TUDELFT_TULIP_BASE_URL = os.getenv(
    "TUDELFT_TULIP_BASE_URL", "https://api.tulip.tudelft.nl"
)
TUDELFT_TULIP_CAPABILITY = os.getenv("TUDELFT_TULIP_CAPABILITY", "chat")
TUDELFT_TULIP_API_KEY = os.getenv("TUDELFT_TULIP_API_KEY", "DUMMY_KEY")
TUDELFT_TULIP_MODEL_ALIAS = os.getenv("TUDELFT_TULIP_MODEL_ALIAS", "chat")

# Normalize TUDELFT_TULIP_BASE_URL to capability/v1. Docs recommend host root only,
# but we also accept URLs that already include capability or capability/v1.
_base_url = TUDELFT_TULIP_BASE_URL.rstrip("/")
if _base_url.endswith("/v1"):
    TUDELFT_TULIP_BASE_URL = _base_url
elif _base_url.endswith(f"/{TUDELFT_TULIP_CAPABILITY}"):
    TUDELFT_TULIP_BASE_URL = f"{_base_url}/v1"
else:
    TUDELFT_TULIP_BASE_URL = f"{_base_url}/{TUDELFT_TULIP_CAPABILITY}/v1"

This tutorial covers two endpoints:

  • /v1/responses
  • /v1/chat/completions

Quick setup

  • Use curl-responses-basic.sh / python_responses_basic.py for /v1/responses, and curl-chat-completions.sh / python_chat_completions.py for /v1/chat/completions.

Responses API

Recommended approach

OpenAI recommends /v1/responses for new projects. It supports all capabilities (chat, code, embed) and provides a unified interface for text and non-text outputs. For more, seeOpenAI Responses API.

curl-responses-basic.sh
#!/bin/bash

SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
if [ -f "${SCRIPT_DIR}/../.env" ]; then
  source "${SCRIPT_DIR}/../.env"
fi

curl -s --fail --show-error ${TUDELFT_TULIP_BASE_URL}/${TUDELFT_TULIP_CAPABILITY}/v1/responses \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${TUDELFT_TULIP_API_KEY}" \
  -d '{
    "model": "'"${TUDELFT_TULIP_MODEL_ALIAS}"'",
    "input": "Tell me a three sentence bedtime story about a unicorn."
  }' | jq .
Run:
bash examples/curl-responses-basic.sh

SDK: OpenAI Python client (OpenAI)

python_responses_basic.py
from common import (
    TUDELFT_TULIP_API_KEY,
    TUDELFT_TULIP_BASE_URL,
    TUDELFT_TULIP_MODEL_ALIAS,
)
from openai import OpenAI

client = OpenAI(base_url=TUDELFT_TULIP_BASE_URL, api_key=TUDELFT_TULIP_API_KEY)
model = TUDELFT_TULIP_MODEL_ALIAS

response = client.responses.create(
    model=model,
    input="Tell me a three sentence bedtime story about a unicorn.",
)

print(response.output_text)
Run:
pixi run python examples/python_responses_basic.py

Success looks like

  • Bash: curl-responses-basic.sh prints a valid JSON response object from /v1/responses.
  • Python: python_responses_basic.py prints extracted model text via response.output_text.

Chat Completions

Legacy endpoint (chat/completions only)

/v1/chat/completions is available for chat and code capabilities only. It does not support embeddings. For new projects or to work with all capabilities uniformly, prefer /v1/responses above. For more, seeOpenAI Chat Completions API.

curl-chat-completions.sh
#!/bin/bash

SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
if [ -f "${SCRIPT_DIR}/../.env" ]; then
  source "${SCRIPT_DIR}/../.env"
fi

curl -s --fail --show-error ${TUDELFT_TULIP_BASE_URL}/${TUDELFT_TULIP_CAPABILITY}/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${TUDELFT_TULIP_API_KEY}" \
  -d '{
    "model": "'"${TUDELFT_TULIP_MODEL_ALIAS}"'",
    "max_tokens": 256,
    "temperature": 0.2,
    "messages": [
      { "role": "system", "content": "You are a helpful coding assistant for TU Delft." },
      { "role": "user", "content": "Write a tiny Python function that prints the TU Delft logo in ASCII." }
    ]
  }' | jq .
Run:
bash examples/curl-chat-completions.sh

SDK: OpenAI Python client (OpenAI)

python_chat_completions.py
from common import (
    TUDELFT_TULIP_API_KEY,
    TUDELFT_TULIP_BASE_URL,
    TUDELFT_TULIP_MODEL_ALIAS,
)
from openai import OpenAI

client = OpenAI(base_url=TUDELFT_TULIP_BASE_URL, api_key=TUDELFT_TULIP_API_KEY)
model = TUDELFT_TULIP_MODEL_ALIAS

completion = client.chat.completions.create(
    model=model,
    messages=[
        {
            "role": "developer",
            "content": "You are a helpful coding assistant for TU Delft.",
        },
        {
            "role": "user",
            "content": (
                "Write a tiny Python function that prints the TU Delft logo in ASCII."
            ),
        },
    ],
)

print(completion.choices[0].message.content)
Run:
pixi run python examples/python_chat_completions.py

Success looks like

  • Bash: curl-chat-completions.sh returns valid JSON from /v1/chat/completions.
  • Python: python_chat_completions.py prints assistant text from completion.choices[0].message.content.

Async & Streaming (Python)

Async responses

SDK: OpenAI Python async client (AsyncOpenAI)

python_responses_async.py
import asyncio

from common import (
    TUDELFT_TULIP_API_KEY,
    TUDELFT_TULIP_BASE_URL,
    TUDELFT_TULIP_MODEL_ALIAS,
)
from openai import AsyncOpenAI

client = AsyncOpenAI(base_url=TUDELFT_TULIP_BASE_URL, api_key=TUDELFT_TULIP_API_KEY)
model = TUDELFT_TULIP_MODEL_ALIAS


async def main() -> None:
    response = await client.responses.create(
        model=model, input="Explain disestablishmentarianism to a smart five year old."
    )
    print(response.output_text)


asyncio.run(main())

Run:

pixi run python examples/python_responses_async.py

Success looks like

  • Script finishes normally and prints text output.
  • No async transport or timeout errors for a basic request.

Streaming chat

Endpoint pattern: Chat completions with stream=True

Warning

Some deployments may not expose OpenAI Responses streaming events yet. This example uses chat-completions streaming for maximum compatibility. For more, seeOpenAI Streaming Responses guide.

python_responses_stream.py
from common import (
    TUDELFT_TULIP_API_KEY,
    TUDELFT_TULIP_BASE_URL,
    TUDELFT_TULIP_MODEL_ALIAS,
)
from openai import OpenAI

client = OpenAI(base_url=TUDELFT_TULIP_BASE_URL, api_key=TUDELFT_TULIP_API_KEY)
model = TUDELFT_TULIP_MODEL_ALIAS

stream = client.chat.completions.create(
    model=model,
    messages=[{"role": "user", "content": "Hello TULIP streaming test!"}],
    stream=True,
)

for chunk in stream:
    # Each chunk is a ChatCompletionChunk; content trickles in delta.
    if chunk.choices and chunk.choices[0].delta and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
print()

Run:

pixi run python examples/python_responses_stream.py

Success looks like

  • Output appears progressively token-by-token or chunk-by-chunk.
  • Stream completes with no protocol or parsing errors.