> ## Documentation Index
> Fetch the complete documentation index at: https://docs.upsonic.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat Metrics

> Track tokens, cost, requests, tool calls, and timing across an entire chat session.

## Overview

Every chat session exposes a single read-only **`chat.usage`** property. It returns an `AggregatedUsage` view derived from the [centralized usage registry](/concepts/usage-registry) on each access, scoped to this chat's `chat_usage_id`.

The session's own agent calls, sub-agents, memory summarization, reliability passes, culture, and policy checks all inherit the chat scope and roll into `chat.usage` automatically.

For wall-clock session length, use `chat.duration` (or `chat.end_time - chat.start_time` for an explicit window).

## Accessing Chat Metrics

Read **`chat.usage`** on any `Chat` instance. It always returns an `AggregatedUsage` — zero-valued before the first message, populated thereafter.

### Token Metrics

| Property | Type | Description |
| - | - | - |
| `input_tokens` | `int` | Prompt tokens across all model calls in the session |
| `output_tokens` | `int` | Completion tokens across all model calls |
| `total_tokens` | `int` | Sum of `input_tokens + output_tokens` |
| `cache_read_tokens` | `int` | Tokens read from prompt cache |
| `cache_write_tokens` | `int` | Tokens written to prompt cache |
| `reasoning_tokens` | `int` | Reasoning (chain-of-thought) tokens |

### Request & Tool Metrics

| Property | Type | Description |
| - | - | - |
| `requests` | `int` | Number of LLM API requests across the session |
| `tool_calls` | `int` | Number of tool calls across the session |

### Timing Metrics

| Property | Type | Description |
| - | - | - |
| `duration` | `float` | Sum of per-call durations recorded on entries (seconds) |
| `model_execution_time` | `float` | Total time spent inside LLM API calls (seconds) |
| `tool_execution_time` | `float` | Total time spent executing tools (seconds) |
| `upsonic_execution_time` | `float` | Framework overhead = `duration − model − tool` (seconds) |
| `time_to_first_token` | `float \| None` | Earliest TTFT across contributing entries |

### Cost Metrics

| Property | Type | Description |
| - | - | - |
| `cost` | `float \| None` | Sum of `cost_usd` across contributing entries. `None` if no entry was priced; `0.0` means priced and free. |

### Aggregation Metadata

| Property | Type | Description |
| - | - | - |
| `entry_count` | `int` | Number of underlying `UsageEntry` rows contributing to this view |
| `models` | `list[str]` | Distinct model identifiers that contributed (first-seen order) |

### Session Wall-Clock & Messages

| Property | Type | Description |
| - | - | - |
| `chat.duration` | `float` | Wall-clock session length in seconds |
| `chat.start_time` | `float` | Unix timestamp when the session opened |
| `chat.end_time` | `float \| None` | Unix timestamp when the session closed (`None` if active) |
| `len(chat.all_messages)` | `int` | Total messages in the session |

## Example

```python theme={null}
import asyncio
from upsonic import Agent, Chat


async def main():
    agent = Agent("anthropic/claude-sonnet-4-5")
    chat = Chat(session_id="session1", user_id="user1", agent=agent)

    await chat.invoke("Hello")
    await chat.invoke("How are you?")

    u = chat.usage
    print(f"Requests:        {u.requests}")
    print(f"Input tokens:    {u.input_tokens}")
    print(f"Output tokens:   {u.output_tokens}")
    print(f"Tool calls:      {u.tool_calls}")
    if u.cost is not None:
        print(f"Cost:            ${u.cost:.4f}")
    print(f"Model time:      {u.model_execution_time:.2f}s")
    print(f"Tool time:       {u.tool_execution_time:.2f}s")
    print(f"Framework time:  {u.upsonic_execution_time:.2f}s")
    print(f"Models used:     {u.models}")

    # Wall-clock session length
    print(f"Wall-clock:      {chat.duration:.1f}s")
    print(f"Messages:        {len(chat.all_messages)}")


if __name__ == "__main__":
    asyncio.run(main())
```

## JSON-Friendly Output

```python theme={null}
import json

snapshot = {
    **chat.usage.to_dict(),
    "duration_wallclock": chat.duration,
    "messages": len(chat.all_messages),
}
print(json.dumps(snapshot, indent=2))
```

## Scope & Propagation

* **Across invocations** — Every `chat.invoke` / `chat.stream` adds entries under the chat's scope. Reading `chat.usage` re-aggregates them, so the figures always reflect the latest state.
* **Sub-pipeline rollup** — Memory summarization, reliability validator/editor, culture, policy, and sub-agent calls inherit the chat scope via context variables and roll into `chat.usage` automatically.
* **Retry idempotency** — The registry is keyed by `entry_id`. Retried requests replace their prior entry instead of double-counting.
* **Persistence** — When you configure storage on `Chat`, recorded entries persist alongside the conversation. Re-opening the same `session_id` re-hydrates the registry, so `chat.usage` continues from where it left off across processes and restarts.

## Legacy Migration

<Note>
  Legacy chat-level properties and helpers have been removed in favour of `chat.usage`:

  | Legacy | Replacement |
  | - | - |
  | `chat.input_tokens` | `chat.usage.input_tokens` |
  | `chat.output_tokens` | `chat.usage.output_tokens` |
  | `chat.total_tokens` | `chat.usage.total_tokens` |
  | `chat.total_cost` | `chat.usage.cost` |
  | `chat.total_requests` | `chat.usage.requests` |
  | `chat.total_tool_calls` | `chat.usage.tool_calls` |
  | `chat.run_duration`, `chat.time_to_first_token` | `chat.usage.duration`, `chat.usage.time_to_first_token` |
  | `chat.get_usage()` | `chat.usage` |
  | `chat.get_session_metrics()`, `chat.get_session_summary()`, `SessionMetrics` | `chat.usage` + `chat.duration` + `len(chat.all_messages)` |
  | `chat.get_cost_history()` | (registry query — filter `UsageEntry` rows by `chat_usage_id`) |
</Note>

## Related Documentation

* [Usage Registry](/concepts/usage-registry) — Architecture, scope tags, persistence
* [Agent Metrics](/concepts/agents/metrics) — Accumulated agent-level view
* [Task Metrics](/concepts/tasks/metrics) — Per-task scoped view
* [Team Metrics](/concepts/team/metrics) — Per-team scoped view
* [Storage Backends](/concepts/chat/storage-backends) — Persisting usage across processes


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.