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

# Agent Session Traces

> Record what a decorated function did on each call, and recall those traces later

A minimal guide to agent session traces: decorate a function with `cognee.agent_memory(save_session_traces=True)`, call it a couple of times, then recall what happened — including calls that raised an error.

## Before You Start

* Complete [Quickstart](/getting-started/quickstart) to understand basic operations
* Ensure you have [LLM Providers](/setup-configuration/llm-providers) configured — the initial `remember()` call needs one, even though tracing itself does not
* Read [Sessions](/guides/sessions) first — this guide assumes you already know what `session_id` is and how it works

## Code in Action

```python theme={null}
import asyncio

import cognee

SESSION_ID = "agent_demo"


@cognee.agent_memory(
    session_id=SESSION_ID,
    with_memory=False,
    with_session_memory=False,
    save_session_traces=True,
    session_trace_summary=False,
)
async def lookup_teammate_status(name: str) -> str:
    statuses = {"Alice": "available"}
    if name not in statuses:
        raise ValueError(f"No status on file for {name!r}")
    return statuses[name]


async def main():
    await cognee.remember(
        "Alice and Bob are teammates.",
        self_improvement=False,
    )

    status = await lookup_teammate_status("Alice")
    print(f"Alice's status: {status}")

    try:
        await lookup_teammate_status("Bob")
    except ValueError as error:
        print(f"Expected error for Bob: {error}")

    alice_traces = await cognee.recall(
        query_text="Alice",
        session_id=SESSION_ID,
        scope="trace",
    )
    for trace in alice_traces:
        print(
            f"[{trace.status}] {trace.origin_function}({trace.method_params}) "
            f"-> {trace.method_return_value or trace.error_message}"
        )

    bob_traces = await cognee.recall(
        query_text="Bob",
        session_id=SESSION_ID,
        scope="trace",
    )
    for trace in bob_traces:
        print(
            f"[{trace.status}] {trace.origin_function}({trace.method_params}) "
            f"-> {trace.method_return_value or trace.error_message}"
        )

    other_session_traces = await cognee.recall(
        query_text="Alice",
        session_id="a_different_session",
        scope="trace",
    )
    print(f"Traces found in a fresh session: {len(other_session_traces)}")


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

## What Just Happened

### Step 1: Bootstrap Cognee and Decorate the Function

```python theme={null}
@cognee.agent_memory(
    session_id=SESSION_ID,
    with_memory=False,
    with_session_memory=False,
    save_session_traces=True,
    session_trace_summary=False,
)
async def lookup_teammate_status(name: str) -> str:
    statuses = {"Alice": "available"}
    if name not in statuses:
        raise ValueError(f"No status on file for {name!r}")
    return statuses[name]
```

```python theme={null}
await cognee.remember(
    "Alice and Bob are teammates.",
    self_improvement=False,
)
```

The `remember()` call runs once, before anything else, purely to make sure Cognee's database and default user exist — the decorated function itself never reads this fact back, because `with_memory=False`. `save_session_traces=True` is what turns tracing on — without it, the decorator would still run the function but record nothing. `with_memory=False` and `with_session_memory=False` keep this example focused on traces alone: no graph memory lookup, no conversation-history retrieval, just "what happened when this function ran." `session_trace_summary=False` skips the LLM-generated summary Cognee would otherwise attempt for each trace.

### Step 2: Call It Once Successfully

```python theme={null}
status = await lookup_teammate_status("Alice")
print(f"Alice's status: {status}")
```

`"Alice"` is in `statuses`, so the function returns normally. Behind the scenes, the decorator records this call's trace with `status="success"` and the returned value — automatically, without you constructing any trace object yourself.

### Step 3: Call It Again With an Error

```python theme={null}
try:
    await lookup_teammate_status("Bob")
except ValueError as error:
    print(f"Expected error for Bob: {error}")
```

`"Bob"` is not in `statuses`, so the function raises `ValueError`. The decorator still records this call's trace — this time with `status="error"` and the error message — then re-raises the exception, which is why the call is wrapped in `try`/`except` here.

### Step 4: Recall the Traces

```python theme={null}
alice_traces = await cognee.recall(
    query_text="Alice",
    session_id=SESSION_ID,
    scope="trace",
)
```

`scope="trace"` tells `recall()` to search recorded traces instead of the knowledge graph or conversation history. Trace search matches by keyword across each trace's function name, parameters, return value, and error message — `query_text="Alice"` matches the first call because `"Alice"` appears in its parameters. Each result exposes `origin_function`, `status`, `method_params`, `method_return_value`, and `error_message`, so both the successful call and the failed one are fully inspectable.

### Step 5: Confirm Isolation Between Sessions

```python theme={null}
other_session_traces = await cognee.recall(
    query_text="Alice",
    session_id="a_different_session",
    scope="trace",
)
print(f"Traces found in a fresh session: {len(other_session_traces)}")
```

The same query against a `session_id` that never ran `lookup_teammate_status` returns an empty list — traces are scoped per session, just like the conversation history covered in [Sessions](/guides/sessions).

## Traces vs. Other Session Concepts

<AccordionGroup>
  <Accordion title="Traces vs. conversation history">
    A trace records one function call — its inputs, status, and outcome. Conversation history (covered in [Sessions](/guides/sessions)) records question/answer turns from `recall()`. Both live in the same session cache and are scoped by `session_id`, but they answer different questions: "what did this code do?" vs. "what did we discuss?"
  </Accordion>

  <Accordion title="Traces vs. memory_context and automatic guidance">
    This guide keeps `with_memory=False` and `with_session_memory=False` so the decorated function never reads graph memory or session history back — it only writes traces. Enabling those flags (as `examples/guides/agent_memory_quickstart.py` does) lets a decorated function *use* memory during its own execution, which is a separate, more advanced concept from recording that the call happened.
  </Accordion>

  <Accordion title="Traces vs. graph persistence">
    Traces recorded here stay in the session cache — they are not written to the permanent knowledge graph. Bridging session content (including traces) into the graph is handled by `improve(session_ids=...)`, the same mechanism covered in [Session Distillation](/guides/session-distillation), and is out of scope for this guide.
  </Accordion>
</AccordionGroup>

<Columns cols={2}>
  <Card title="Sessions" icon="message-square" href="/guides/sessions">
    Learn the session-cache concept traces are built on
  </Card>

  <Card title="Agent Memory Quickstart" icon="bot" href="/guides/agent-memory-quickstart">
    See traces combined with session memory and graph memory
  </Card>
</Columns>
