Coolhand captures a rich set of fields for every LLM request log. This guide explains what each field means, how to interpret it, and which providers may leave it blank.
Provider (Source API)
The Source API identifies which LLM provider handled the request. Possible values:
| Value | Provider |
|---|---|
openai |
OpenAI |
anthropic |
Anthropic |
azure |
Azure OpenAI |
vertex |
Google Vertex AI |
gemini |
Google Gemini |
ollama |
Ollama (self-hosted) |
copilot |
GitHub Copilot |
bedrock |
AWS Bedrock (OpenAI-compatible endpoint) |
bedrock_anthropic |
AWS Bedrock (native Anthropic Messages API endpoint) |
openrouter |
OpenRouter |
elevenlabs |
ElevenLabs Conversational AI |
Claude Code and Claude Cowork sessions (captured from locally-saved session transcripts) are also logged as anthropic — they bill against the same Anthropic API price sheet as a direct API call. See Application below for how to tell them apart.
Model
The specific model that processed the request (e.g., gpt-4o, claude-3-5-sonnet-20241022).
Gotcha — Copilot: GitHub Copilot's API includes a model field in its response. Copilot SDK versions 1.0.0 and later populate this field (e.g., claude-haiku-4.5). Older SDK versions return null, so Copilot logs from pre-1.0.0 collectors will have a blank model field.
Gotcha — ElevenLabs: ElevenLabs post-call transcription webhooks do not include the underlying model name in their payload. Model will always be blank for ElevenLabs logs.
Gotcha — Vertex AI: Many Vertex responses (notably embeddings) omit the model name from the response payload entirely. Coolhand falls back to reading the model out of the request URL, which encodes it as .../publishers/<vendor>/models/<model-id>, so these logs are still attributed to the right model. Model stays blank for Vertex calls against tuned or custom-trained models, whose URLs carry a numeric resource id rather than a published model name.
Temperature
The sampling temperature used for the request, which controls output randomness. Values typically range from 0.0 (deterministic) to 1.0 or 2.0 (highly varied).
Gotcha — some providers don't expose this: Certain providers manage temperature server-side or simply don't include it in their request/response payloads. When temperature is blank, Coolhand records it as empty (no value) — it does not substitute a default. This means a blank temperature field indicates the provider did not report it, not that the request ran at any particular temperature.
| Provider | Temperature Available? |
|---|---|
| OpenAI | Yes |
| Anthropic | Yes |
| Azure | Yes |
| Vertex AI | Yes |
| Gemini | Yes |
| Ollama | Yes |
| GitHub Copilot | No |
| ElevenLabs | No |
| Claude Code | No |
| Claude Cowork | No |
Request Type (Group)
Classifies the shape of the request:
| Value | Meaning |
|---|---|
chat |
Multi-turn conversation (messages array) |
user_prompt |
Single user turn, no system prompt |
user_prompt_with_system_prompt |
Single user turn with a system prompt |
embedding |
Embedding generation request |
other |
Anything that doesn't fit the above |
Token Fields
Coolhand captures several token counts, which are the basis for cost estimation and usage analytics.
Input Tokens
The number of tokens in the request (prompt + context). This is what you're billed for on the input side.
Gotcha — Copilot: Input token counts are available for Copilot SDK 1.0.0+ logs (extracted from the granular tokenDetails breakdown). For older SDK versions without that breakdown, Coolhand falls back to the top-level inputTokens minus cache tokens.
Cached Input Tokens
Tokens served from the provider's prompt cache. When non-zero, these tokens were billed at a reduced rate. Not all providers support prompt caching.
| Provider | Cached Input Tokens? |
|---|---|
| OpenAI | Yes |
| Anthropic | Yes |
| Azure | Yes |
| Vertex AI | Yes |
| Gemini | Yes |
| Ollama | No |
| GitHub Copilot | Yes (via cache_read token details) |
| ElevenLabs | No |
| Claude Code | Yes |
| Claude Cowork | Yes |
Cache Creation Input Tokens
Tokens written into the provider's prompt cache on the first request that populates a cache entry. These are billed at a higher rate than regular input tokens but subsequent requests that read from that cache are cheaper. Only Anthropic-style providers report this separately.
This is the aggregate cache-write count across every cache TTL. When the provider also reports a per-TTL breakdown, the TTL-specific fields below carry it and this field remains the total.
| Provider | Cache Creation Input Tokens? |
|---|---|
| OpenAI | No |
| Anthropic | Yes |
| Azure | No |
| Vertex AI | No |
| Gemini | No |
| Ollama | No |
| GitHub Copilot | Yes (via the cache_write token details) |
| ElevenLabs | No |
| Claude Code | Yes |
| Claude Cowork | Yes |
5-Minute Cache Creation Tokens
Cache writes made with Anthropic's 5-minute TTL, billed at 1.25× the base input rate. Blank for providers that don't report a per-TTL cache-write breakdown, and blank for older Anthropic payloads recorded before the breakdown existed — in both cases the whole write is priced from Cache Creation Input Tokens at the aggregate rate instead.
| Provider | 5-Minute Cache Creation Tokens? |
|---|---|
| OpenAI | No |
| Anthropic | Yes |
| Azure | No |
| Vertex AI | No |
| Gemini | No |
| Ollama | No |
| GitHub Copilot | No |
| ElevenLabs | No |
| Claude Code | Yes |
| Claude Cowork | Yes |
1-Hour Cache Creation Tokens
Cache writes made with Anthropic's 1-hour TTL, billed at 2× the base input rate. Same blank-field behavior, and the same per-provider support, as the 5-minute field above.
Inference Geo
The geography the request was served from, when the provider reports it. Values are stored verbatim as the provider sends them — us for US-only inference, global for default routing, and not_available when the provider didn't resolve one. Claude 4.6 and newer carry a 1.1× price premium on US-only inference, so a value of us is what applies that premium to a log's cost; any other value carries no premium.
| Provider | Inference Geo? |
|---|---|
| OpenAI | No |
| Anthropic | Yes |
| Azure | No |
| Vertex AI | No |
| Gemini | No |
| Ollama | No |
| GitHub Copilot | No |
| ElevenLabs | No |
| Claude Code | Yes |
| Claude Cowork | Yes |
Output Tokens
The number of tokens generated in the response. This is the primary driver of output-side cost.
All providers report output tokens. Copilot reports output tokens when available.
Reasoning Tokens
Tokens consumed by extended thinking or chain-of-thought reasoning steps, separate from the visible output. Only applicable to models that support internal reasoning (e.g., OpenAI o-series, Gemini thinking models). Reasoning tokens are billed as part of your cost totals, at the model's reasoning rate where one is set, or at the model's standard output rate otherwise.
| Provider | Reasoning Tokens? |
|---|---|
| OpenAI | Yes (reasoning-capable models) |
| Azure | Yes (reasoning-capable models) |
| Vertex AI / Gemini | Yes |
| Anthropic | No (thinking token count not separated) |
| Ollama | No |
| GitHub Copilot | Yes (SDK 1.0.0+) |
| ElevenLabs | No |
| Claude Code | No (thinking token count not separated) |
| Claude Cowork | No (thinking token count not separated) |
Long-Context Pricing Tiers
Some models bill the entire request at a higher flat rate once a single request's input tokens exceed a threshold — for example, Gemini 2.5 Pro bills at a long-context rate once a request's input exceeds 200,000 tokens. This is a cliff, not a marginal split: crossing the threshold re-prices the whole request (input, output, cached, and reasoning tokens together) at the higher rate, not just the tokens above the threshold. Coolhand's cost estimates account for this automatically for models with a published long-context rate.
Audio Input Tokens
Tokens from audio modality inputs. Only relevant for multimodal requests that include audio. Currently available for OpenAI and Azure; all other providers report zero or blank.
Latency
The end-to-end request duration in milliseconds, from when the request was sent to when the response was fully received.
Gotcha — Vertex AI: Vertex AI does not include timing information in its API responses. Latency is unavailable for Vertex logs unless captured by your SDK or proxy layer before ingestion.
Gotcha — Anthropic: Anthropic does not natively return latency. Coolhand attempts to derive it from response headers (x-envoy-upstream-service-time) or a duration_ms field if your collector includes one.
Gotcha — Claude Code / Claude Cowork: Logs captured from locally-saved session transcripts do not include per-turn timing, so latency is normally blank for these logs.
Gotcha — Mixed semantics for OpenAI-compatible providers: For standard OpenAI requests, latency comes from the openai-processing-ms response header, which measures server-side processing time only. For providers that use the OpenAI request/response format but don't return that header (Vertex AI's OpenAI-compatible endpoint, Cloudflare AI Gateway proxies), latency falls back to the duration_ms field logged by your client SDK, which is total wall-clock time including network round-trip and queuing. These two values are not directly comparable, so latency figures should be interpreted with care when mixing logs from OpenAI and OpenAI-compatible providers.
Prompts and Responses
User Prompt
The user-facing input sent to the model. For multi-turn chat requests, this is the most recent user message. For single-turn requests, it's the full prompt text.
Gotcha — ElevenLabs: ElevenLabs logs are populated from post-call transcription webhooks, not real-time API calls. The User Prompt field contains all user-side utterances from the conversation transcript joined together; the Assistant Response field contains all agent-side utterances. Input/output token counts, latency, temperature, and system prompt are not available for ElevenLabs logs.
System Prompt
The system-level instructions sent alongside the request, if any. Many providers support a dedicated system field; others embed it as a message with role: system. Messages with role: developer (OpenAI's renamed system role for its reasoning models) are also captured as the system prompt.
Assistant Response
The full text output returned by the model. For tool-use or function-calling responses, this may be serialized as JSON rather than plain text.
Thinking Response
Step-by-step reasoning content produced by extended thinking models (e.g., Claude's thinking blocks, OpenAI o-series reasoning). This is separate from the visible assistant response and is only present when the model actually produced thinking output.
| Provider | Thinking Response? |
|---|---|
| OpenAI | Yes (reasoning-capable models) |
| Anthropic | Only when extended thinking is explicitly requested |
| Ollama | Yes (model-dependent) |
| GitHub Copilot | Yes (when reasoningText is present) |
| Azure | No |
| Vertex AI / Gemini | Yes (model-dependent — requires a model that emits thought parts, e.g. Gemini 2.5 Pro/Flash) |
| ElevenLabs | No |
| Claude Code | Yes (when the captured turn contains thinking blocks) |
| Claude Cowork | Yes (when the captured turn contains thinking blocks) |
Gotcha — Anthropic: Anthropic only returns thinking content when you explicitly enable extended thinking in the API request (by passing a thinking parameter with a token budget). Standard Anthropic requests without this flag will always have a blank thinking response, even on models that support it.
Additionally, Anthropic may redact individual thinking blocks when their safety systems flag the content. Redacted blocks are captured by Coolhand and displayed as [redacted thinking] rather than the actual reasoning text.
Status and Errors
Result
The outcome of the request:
| Value | Meaning |
|---|---|
success |
Request completed normally |
failed |
The provider returned an error (4xx/5xx) |
operational |
The request was a management/utility call rather than inference (e.g., batch job status polling, token-counting calls) and was intentionally skipped |
unsupported_api |
The request format is not recognized by Coolhand |
ingest_error |
An error occurred during log processing |
Error Details
A short description of the error when the result is failed. Blank for successful requests.
Provider ID
The unique identifier assigned to this request by the provider (e.g., OpenAI's chatcmpl-..., Anthropic's msg_...). Useful for cross-referencing logs in your provider's dashboard or for support tickets.
Linked Template
If this log was matched to one of your prompt templates, the template name is shown. Coolhand uses the user prompt content to find the best matching template automatically.
Collector
Identifies the SDK or collection method that sent this log to Coolhand. Useful when you have multiple ingestion paths (e.g., a Python SDK alongside a proxy).
Application
Identifies the client app a session came from, for source APIs that cover more than one app. Currently only set for Anthropic-family logs:
| Value | Application |
|---|---|
claude_code |
Claude Code (captured from locally-saved session transcripts) |
claude_cowork |
Claude Cowork (captured from locally-saved Cowork session transcripts) |
Blank for a direct Anthropic API call, and for every other provider.
Metadata
A free-form object your collector can attach to a log for your own context — unlike Provider ID or Collector, Coolhand doesn't parse or validate its contents beyond requiring valid JSON. The one convention Coolhand's own tooling relies on today is project_path: when set, it records the local project/repo directory a session was captured from (used by coolhand-cli's analyze-claude-sessions to attribute Claude Code sessions to the project they came from), and can be filtered on via the project_path query param on GET /api/v2/llm_request_logs. Blank ({}) when your collector doesn't send it.
Generator
Indicates whether this log came from live traffic or a bakeoff comparison run:
| Value | Meaning |
|---|---|
client_log |
Real request from your application |
bakeoff_comp |
Synthetic request generated during a bakeoff evaluation |
Background Agent
A flag that marks a Claude Code session as having been driven by an automated agent rather than a person typing at the keyboard. Coolhand sets it during ingestion: when every user turn in the captured session contains only tool results (no human-typed text), the session is classified as a background agent.
| Value | Meaning |
|---|---|
false |
At least one user turn contains human-typed text — a normal interactive session (default) |
true |
Every user turn is tool results only — the session was driven by an automated agent |
This flag is only meaningful for Claude Code logs (Application = claude_code); it is always false otherwise. Background-agent sessions are excluded from Claude Code expertise scoring, since those evaluations measure how a person directs Claude and an automated agent never responds to ongoing human feedback.
User Turn Count
The number of human-typed turns in a captured Claude Code session — each point where a person stepped in to give Claude an instruction or answer a question. Coolhand counts it during ingestion: user turns made up only of tool results (no human-typed text) are not counted. A value of 1 means the whole session was completed in a single prompt with no further human input.
This field is only populated for Claude Code logs (Application = claude_code); it is blank otherwise. It powers the per-run "User Turns" statistics shown for recurring step templates.
Duplicate Count
If Coolhand detected identical requests within a short window, this field shows how many duplicates were collapsed into this log entry. A non-zero value means the actual request was made more times than it appears.
Feedback Source
When feedback is submitted on a log, you can optionally identify who supplied it. This lets you separate human-given feedback from feedback an AI agent produced about its own work.
| Value | Meaning |
|---|---|
human |
A person submitted this feedback |
agent |
An AI agent submitted this feedback (e.g. via the CLI wildcard tool) |
unknown |
The source was not specified (default) |
The field is optional. When you don't set it, feedback is recorded as unknown so existing integrations are unaffected.