Chat compatible con OpenAI
Usa POST /v1/chat/completions y GET /v1/models con el SDK de OpenAI para Python o JavaScript cambiando la URL base y la clave API. La compatibilidad abarca Chat Completions de texto, no todas las funciones de OpenAI.
Autenticación y modelos
Usa la clave actual de la consola: Authorization: Bearer sk-your-key. La lista incluye modelos de texto disponibles e identificadores públicos. Usa el id devuelto, no el nombre visible. Los precios y las voces siguen en /v1/chat/catalog.
curl https://api.coldstart.win/v1/models -H "Authorization: Bearer sk-your-key"{"object":"list","data":[{"id":"chat-standard","object":"model","created":0,"owned_by":"girllab"}]}Solicitudes e historial
Cada solicitud debe enviar el array messages completo y ordenado. Roles: system, developer, user, assistant, tool. El contenido puede ser texto o un array de { "type": "text", "text": "..." }. No se añade historial del servidor ni una personalidad predeterminada. Envía las instrucciones del sistema necesarias y el historial pertinente en cada turno.
curl https://api.coldstart.win/v1/chat/completions \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{"model":"chat-standard","messages":[{"role":"system","content":"You are a helpful assistant."},{"role":"user","content":"Hello!"}],"max_tokens":256}'{
"id": "chatcmpl_example",
"object": "chat.completion",
"created": 1792540800,
"model": "chat-standard",
"choices": [{"index": 0, "message": {"role": "assistant", "content": "Hello!", "refusal": null}, "logprobs": null, "finish_reason": "stop"}],
"usage": {"prompt_tokens": 12, "completion_tokens": 3, "total_tokens": 15}
}Parámetros admitidos
Son obligatorios model y un array messages no vacío. Opcionales: stream (false por defecto), temperature (0–2), top_p (0–1), max_tokens o max_completion_tokens (entero 1–8192, excluyentes), stop (una cadena o 1–4 cadenas), presence_penalty y frequency_penalty (−2–2), seed (entero seguro), n (solo 1). Si se omiten, se usan los valores del servicio; su efecto depende del modelo. stream_options: {"include_usage": true} requiere stream: true. Los valores null opcionales usan los predeterminados. El JSON tiene un límite de 15 MiB; el contexto depende de la capacidad de tokens del modelo.
Streaming y uso
SSE usa solo data:, sin eventos personalizados event: delta o event: completed. Lee choices[0].delta.content, el finish_reason final (stop, length, content_filter, tool_calls) y data: [DONE]. Con include_usage: true, un bloque extra con choices: [] y el usage final precede al cierre; los demás llevan usage: null. Sin esta opción se omite usage. Todos los bloques comparten ID local, fecha de creación e ID público del modelo.
{"model":"chat-standard","messages":[{"role":"user","content":"Hello!"}],"stream":true,"stream_options":{"include_usage":true}}data: {"id":"chatcmpl_example","object":"chat.completion.chunk","created":1792540800,"model":"chat-standard","choices":[{"index":0,"delta":{"role":"assistant","content":""},"logprobs":null,"finish_reason":null}],"usage":null}
data: {"id":"chatcmpl_example","object":"chat.completion.chunk","created":1792540800,"model":"chat-standard","choices":[{"index":0,"delta":{"content":"Hello!"},"logprobs":null,"finish_reason":null}],"usage":null}
data: {"id":"chatcmpl_example","object":"chat.completion.chunk","created":1792540800,"model":"chat-standard","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null}
data: {"id":"chatcmpl_example","object":"chat.completion.chunk","created":1792540800,"model":"chat-standard","choices":[],"usage":{"prompt_tokens":12,"completion_tokens":3,"total_tokens":15}}
data: [DONE]Errores y alcance
Formato de error: { "error": { "message": "...", "type": "invalid_request_error", "param": null, "code": "invalid_request" } }. HTTP 400 indica datos inválidos o no admitidos; 401 clave inválida, 402 saldo insuficiente, 429 límite de solicitudes, 503 fallo temporal y 504 tiempo agotado. Los detalles se anonimizan. Antes del stream se devuelve un error HTTP JSON; después, un bloque data: {"error": ...} lo cierra sin marcador de éxito. Una respuesta parcial no está completa. Límites: 90 segundos hasta el primer texto, 60 segundos sin texto nuevo (reiniciados con cada delta), 60 segundos sin streaming.
No se admiten entradas de imagen/audio, búsqueda o ejecución de código alojadas, los antiguos functions / function_call, tipos de herramientas personalizados, logprobs, múltiples candidatos, store, Responses API ni parámetros no indicados. Se rechazan expresamente. Para voz, usa /v1/chat/speech.
Facturación y ejemplos SDK
Se mantienen el saldo, los precios públicos y la facturación de tokens de entrada/salida. Se reservan créditos antes de generar, se liquida el uso real al finalizar y se libera el sobrante. Los fallos, uso inválido o desconexión antes de liquidar liberan la reserva. Cancelar después de liquidar no revierte el cargo. Las llamadas aparecen en el historial de uso y el panel de administración. El JSON estándar incluye usage, sin un billing personalizado. Repetir solicitudes puede generar nuevos cargos; no hay garantía de idempotencia.
pip install openai
npm install openaiimport os
from openai import OpenAI
client = OpenAI(api_key=os.environ["KARMAN_API_KEY"], base_url="https://api.coldstart.win/v1", max_retries=0)
print([model.id for model in client.models.list().data])
model = os.environ["KARMAN_MODEL"]
messages = [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Hello!"}]
reply = client.chat.completions.create(model=model, messages=messages, max_tokens=256)
print(reply.choices[0].message.content)
stream = client.chat.completions.create(model=model, messages=messages, max_tokens=256,
stream=True, stream_options={"include_usage": True})
for chunk in stream:
if chunk.choices:
print(chunk.choices[0].delta.content or "", end="", flush=True)
if chunk.usage:
print("\n", chunk.usage)import OpenAI from "openai";
const client = new OpenAI({ apiKey: process.env.KARMAN_API_KEY, baseURL: "https://api.coldstart.win/v1", maxRetries: 0 });
const models = await client.models.list();
console.log(models.data.map(model => model.id));
const stream = await client.chat.completions.create({
model: process.env.KARMAN_MODEL,
messages: [{ role: "user", content: "Hello!" }],
stream: true,
stream_options: { include_usage: true }
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta.content ?? "");
if (chunk.usage) console.log("\n", chunk.usage);
}Herramientas de agentes y salida estructurada
Consulta models[].capabilities en /v1/chat/catalog: tool_calling, parallel_tool_calls, json_mode, structured_outputs. Las capacidades dependen del modelo; las no admitidas devuelven HTTP 400 antes de generar. Tu aplicación ejecuta las herramientas. La API no ejecuta funciones ni guarda la memoria del agente.
Se admiten tools (hasta 128 funciones), tool_choice (auto, none, required o una función concreta) y parallel_tool_calls (booleano, requiere tools). Las funciones aceptan name, description, parameters de JSON Schema y strict opcional. Lee message.tool_calls; content puede ser null. Añade el mensaje assistant sin cambios y un mensaje role: "tool" por llamada con su tool_call_id. Devuelve todos los resultados, incluidos los errores, antes de la siguiente llamada. Conserva identificadores únicos y el orden.
En streaming, agrupa choices[0].delta.tool_calls por index, concatena los fragmentos de function.arguments y conserva id, type, function.name. Ejecuta solo tras finish_reason: "tool_calls" y el fin correcto del flujo; nunca con length o errores. Los deltas de herramientas reinician el límite de inactividad de 60 segundos; el primer resultado tiene 90 segundos. Valida nombres, argumentos y permisos, y limita las rondas.
response_format admite text, json_object y json_schema con json_schema: {name, schema, strict, description?}. En modo JSON, solicita JSON expresamente en el prompt. Los esquemas estrictos requieren todas las propiedades en required y additionalProperties: false; null permite valores opcionales. No combines JSON Schema con parallel_tool_calls: true. Comprueba refusal, length y errores antes de analizar. El esquema no garantiza la veracidad. Definiciones, argumentos y resultados cuentan como tokens; cada ronda del modelo se factura por separado.
Bucle completo de herramientas
import os, json
from openai import OpenAI
client = OpenAI(api_key=os.environ["KARMAN_API_KEY"],
base_url="https://api.coldstart.win/v1", max_retries=0)
model = os.environ["KARMAN_MODEL"]
tools = [{"type": "function", "function": {
"name": "lookup_memory", "description": "Read a saved preference.",
"parameters": {"type": "object", "properties": {"topic": {"type": "string"}},
"required": ["topic"], "additionalProperties": False},
"strict": True
}}]
messages = [{"role": "user", "content": "What food do I like? Use my saved memory."}]
for _ in range(4):
reply = client.chat.completions.create(
model=model, messages=messages, tools=tools,
tool_choice="auto", parallel_tool_calls=False, max_tokens=512)
choice = reply.choices[0]
message = choice.message
if message.refusal or choice.finish_reason not in ("stop", "tool_calls"):
raise RuntimeError("Incomplete or refused response")
messages.append(message.model_dump(exclude_none=True))
if not message.tool_calls:
print(message.content)
break
for call in message.tool_calls:
try:
if call.function.name != "lookup_memory":
raise ValueError("Unknown function")
args = json.loads(call.function.arguments)
if not isinstance(args, dict) or set(args) != {"topic"} or not isinstance(args["topic"], str):
raise ValueError("Invalid arguments")
result = {"topic": args["topic"], "preference": "apples"}
except (ValueError, TypeError):
result = {"error": "Invalid tool request"}
messages.append({"role": "tool", "tool_call_id": call.id,
"content": json.dumps(result)})
else:
raise RuntimeError("Agent round limit reached")Ejemplo de salida estructurada
reply = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": "I like apples. Extract this preference as JSON."}],
response_format={"type": "json_schema", "json_schema": {
"name": "memory", "strict": True,
"schema": {"type": "object", "properties": {"preference": {"type": "string"}},
"required": ["preference"], "additionalProperties": False}
}}, max_tokens=256)
choice = reply.choices[0]
if choice.finish_reason != "stop" or choice.message.refusal:
raise RuntimeError("Incomplete or refused response")
memory = json.loads(choice.message.content)
print(memory)