--- name: signal-llm-gateway description: How to call LLMs through the Signal Labs LLM gateway (https://llm.sine.signallabs.ai). Use whenever code, an agent or a harness needs a model call at Signal Labs - OpenAI-compatible and Anthropic-compatible endpoints, one API key, per-person budgets. --- # Signal Labs LLM gateway One endpoint for every model Signal Labs runs. It speaks the OpenAI API and the Anthropic Messages API, so any OpenAI or Anthropic SDK, LangChain, LiteLLM, Claude Code or a custom harness works by changing the base URL and the key. Built on LiteLLM; models are served from AWS Bedrock (US regions). ## Get a key 1. A human opens https://llm.sine.signallabs.ai and signs in with GitHub (members of the SignalLabsAI org only). 2. They click **Create key**. The key starts with `sk-` and is shown once. 3. Store it in the environment as `SIGNAL_LLM_KEY`. Never hard-code it or commit it. If you are an agent and `SIGNAL_LLM_KEY` is not set, stop and ask the user to create a key at https://llm.sine.signallabs.ai. Do not try to create keys yourself: key creation requires the user's browser sign-in. ## Endpoints | What | Base URL | Auth header | |---|---|---| | OpenAI-compatible | `https://llm.sine.signallabs.ai/v1` | `Authorization: Bearer $SIGNAL_LLM_KEY` | | Anthropic Messages | `https://llm.sine.signallabs.ai` (SDK appends `/v1/messages`) | `x-api-key: $SIGNAL_LLM_KEY` or `Authorization: Bearer ...` | | List models | `GET https://llm.sine.signallabs.ai/v1/models` | Bearer | | This document | `GET https://llm.sine.signallabs.ai/skill` | none | Supported OpenAI routes: `/v1/chat/completions` (streaming, tools, JSON mode, images), `/v1/models`. Supported Anthropic route: `/v1/messages` (streaming, tools, thinking). ## Models Use the name in the left column as `model`. Prices are USD per million tokens and are what your budget is charged. | model | input $/M | output $/M | good for | |---|---:|---:|---| | `claude-opus-5-5` | 4.40 | 22.00 | Strongest Claude. Hard reasoning, long agentic coding sessions. | | `claude-sonnet-5-5` | 2.20 | 11.00 | Default workhorse. Coding, agents, analysis. | | `claude-haiku-5-5` | 0.11 | 0.55 | Fast and cheap Claude. Classification, extraction, sub-agents. | | `gpt-6.1-sol` | 11.00 | 55.00 | OpenAI frontier model. Price is a conservative placeholder. | | `kimi-k3` | 3.30 | 16.50 | Moonshot Kimi K3. Thinking model. | | `deepseek-v3.2` | 0.62 | 1.85 | DeepSeek V3.2. Strong open model at a low price. | | `qwen3-coder-next` | 0.50 | 1.20 | Qwen3 Coder Next. Cheap coding model. | | `qwen3-next-80b` | 0.14 | 1.20 | Qwen3 Next 80B-A3B. Very cheap general model. | | `gpt-oss-120b` | 0.15 | 0.60 | OpenAI gpt-oss-120b. Cheap open reasoning model. | | `nova-2-lite` | 0.33 | 2.75 | Amazon Nova 2 Lite. Multimodal, cheap. | Defaults if you have no reason to choose: `claude-sonnet-5-5` for agents and coding, `claude-haiku-5-5` for high-volume cheap calls, `claude-opus-5-5` only for the hardest steps. ## Examples ### curl ```bash curl https://llm.sine.signallabs.ai/v1/chat/completions \ -H "Authorization: Bearer $SIGNAL_LLM_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "claude-sonnet-5-5", "messages": [{"role": "user", "content": "Hello"}]}' ``` ### Python, OpenAI SDK ```python import os from openai import OpenAI client = OpenAI(base_url="https://llm.sine.signallabs.ai/v1", api_key=os.environ["SIGNAL_LLM_KEY"]) r = client.chat.completions.create( model="claude-sonnet-5-5", messages=[{"role": "user", "content": "Hello"}], ) print(r.choices[0].message.content) ``` Streaming: pass `stream=True` and iterate. Tool calling: pass `tools=[...]` in the OpenAI format; the gateway translates it for every model. ### Python, Anthropic SDK ```python import os import anthropic client = anthropic.Anthropic(base_url="https://llm.sine.signallabs.ai", api_key=os.environ["SIGNAL_LLM_KEY"]) r = client.messages.create( model="claude-sonnet-5-5", max_tokens=1024, messages=[{"role": "user", "content": "Hello"}], ) print(r.content[0].text) ``` ### TypeScript, OpenAI SDK ```ts import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://llm.sine.signallabs.ai/v1", apiKey: process.env.SIGNAL_LLM_KEY }); const r = await client.chat.completions.create({ model: "claude-sonnet-5-5", messages: [{ role: "user", content: "Hello" }], }); ``` ### Claude Code ```bash export ANTHROPIC_BASE_URL="https://llm.sine.signallabs.ai" export ANTHROPIC_AUTH_TOKEN="$SIGNAL_LLM_KEY" export ANTHROPIC_MODEL="claude-sonnet-5-5" export ANTHROPIC_DEFAULT_HAIKU_MODEL="claude-haiku-5-5" claude ``` ### LangChain ```python from langchain_openai import ChatOpenAI llm = ChatOpenAI(base_url="https://llm.sine.signallabs.ai/v1", api_key=os.environ["SIGNAL_LLM_KEY"], model="claude-sonnet-5-5") ``` ## Building an agent harness on the gateway - Treat the gateway as a plain OpenAI endpoint. Keep the base URL and key in config, not in code. - Pick the model per step: a cheap model (`claude-haiku-5-5`, `qwen3-next-80b`, `gpt-oss-120b`) for classification, extraction and sub-agents; `claude-sonnet-5-5` for the main loop; escalate to `claude-opus-5-5` only when the cheaper model fails. - Keep one model for a whole multi-turn session where you can. Switching models mid-conversation throws away the provider's prompt cache and costs more. - Use one key per project or agent, so spend is easy to attribute. A person may have up to 10 keys. - Set `max_tokens` on every call. Thinking models (`kimi-k3`, `gpt-oss-120b`) spend tokens on reasoning before the answer; give them room or you get empty content. - Set a client timeout of at least 300 s for long generations, and retry 429 and 5xx with backoff. ## Budgets and errors Every person has a monthly budget shared by all their keys (default $25 unless an admin raised it). Spend so far is on https://llm.sine.signallabs.ai. | Status | Meaning | What to do | |---|---|---| | 401 | Missing, wrong or revoked key | Check `SIGNAL_LLM_KEY`; make a new key at https://llm.sine.signallabs.ai | | 422, `"type": "budget_exceeded"` | Monthly budget used up | Ask an admin, or wait for the reset date shown in the portal | | 400 "Invalid model name" | Model not served here | `GET /v1/models` for the list | | 429 | Rate limit, ours or Bedrock's | Retry with exponential backoff | | 5xx | Upstream provider error | Retry; if it persists try another model | ## Rules - Do not send client data (Optum, Norfolk Southern, etc.) unless the engagement allows AWS Bedrock in US regions. - The gateway logs who called which model, tokens and cost. It does not store prompt or response text. - Never print, log or commit keys.