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

# Trace generator functions

> Track sync and async generator functions with W&B Weave tracing

W\&B Weave supports tracing both sync and async generator functions, including deeply nested patterns.

<Warning>
  Because generators yield values lazily, Weave logs outputs only when the generator is fully consumed (for example, when you convert it to a list).
  To ensure Weave captures outputs in the trace, fully consume the generator (for example, with `list()`).
</Warning>

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from typing import Generator
    import weave

    weave.init("my-project")

    # This function uses a simple sync generator.
    # Weave will trace the Call and its input (`x`),
    # but output values are only captured once the generator is consumed (for example, with `list()`).
    @weave.op
    def basic_gen(x: int) -> Generator[int, None, None]:
        yield from range(x)

    # A normal sync function used within the generator pipeline.
    # Its calls are also traced independently by Weave.
    @weave.op
    def inner(x: int) -> int:
        return x + 1

    # A sync generator that calls another traced function (`inner`).
    # Each yielded value comes from a separate traced Call to `inner`.
    @weave.op
    def nested_generator(x: int) -> Generator[int, None, None]:
        for i in range(x):
            yield inner(i)

    # A more complex generator that composes the above generator.
    # Tracing here produces a hierarchical Call tree:
    # - `deeply_nested_generator` (parent)
    #   - `nested_generator` (child)
    #     - `inner` (grandchild)
    @weave.op
    def deeply_nested_generator(x: int) -> Generator[int, None, None]:
        for i in range(x):
            for j in nested_generator(i):
                yield j

    # The generator must be *consumed* for Weave to capture outputs.
    # This is true for both sync and async generators.
    res = deeply_nested_generator(4)
    list(res)  # Triggers tracing of all nested calls and yields
    ```
  </Tab>

  <Tab title="TypeScript">
    ```plaintext theme={null}
    This feature is not available in the TypeScript SDK yet.
    ```
  </Tab>
</Tabs>

The following screenshot shows the **Traces** page with a selected trace of the preceding code.  The center panel shows the trace tree for the selected trace. The trace tree shows the `deeply_nested_generator`, `nested_generator`, and `inner` Ops in the trace tree hierarchy.

<img src="https://mintcdn.com/wb-21fd5541/4ANo4MV8FzCjYewG/weave/guides/tracking/imgs/generators.png?fit=max&auto=format&n=4ANo4MV8FzCjYewG&q=85&s=da7f687c1e1db490ec563a88a7a5931f" alt="Weave Traces page showing a selected trace tree illustrating deeply nested Ops" width="2078" height="1134" data-path="weave/guides/tracking/imgs/generators.png" />

## Consuming generators

Weave captures generator outputs only after you fully consume the generator. Consume the generator by iterating over it (for example, with `list()`, a `for` loop, or `next()` until exhaustion). The same applies to async generators when you use `async for` or equivalent consumption.

For more on decorating functions and methods with `@weave.op`, see [Create calls](/weave/guides/tracking/create-call).

## Accumulate yielded values into a single trace

You can use the `weave.op`'s `accumulator` parameter to customize how yielded values are combined from generator functions, for example, to join streamed text tokens into a single string. The accumulator is a two-argument function that Weave calls once per yielded value, building up a result incrementally.

<Note>
  The `accumulator` parameter is not available for the TypeScript.
</Note>

The following example demonstrates a custom accumulator that appends each yielded value to a list, so Weave records that list as the call output after the generator is fully consumed.

```python theme={null}
from typing import Generator
import weave

weave.init("your-team-name/your-project-name")

# Weave calls this after each yield; acc is None on the first call.
# The last value you return becomes the traced Op output.
def list_accumulator(acc, value):
    if acc is None:
        acc = []
    acc.append(value)
    return acc

# Set the accumulator parameter
@weave.op(accumulator=list_accumulator)
def basic_gen_with_accumulator(x: int) -> Generator[int, None, None]:
    yield from range(x)

# Iterate to completion so every yield runs and the accumulator can produce the final traced output.
result = list(basic_gen_with_accumulator(3))
print(result)
```
