> ## 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.

# Customize Ops

> Learn how to color your Ops for better visibility, how to modify what's logged, and how to control the sampling rate

A Weave Op is a versioned function that automatically logs all Calls.

<Tabs>
  <Tab title="Python">
    To create an Op, decorate a python function with `weave.op()`

    ```python lines theme={null}
    import weave

    @weave.op()
    def track_me(v):
        return v + 5

    weave.init('intro-example')
    track_me(15)
    ```

    Calling an Op creates a new Op version if the code has changed from the last call, and logs the inputs and outputs of the function.

    Functions that you decorate with `@weave.op()` behave normally (without code versioning and tracking) if you do not call `weave.init('your-project-name')` before calling them.

    Ops can be [served](/weave/guides/tools/serve) or [deployed](/weave/guides/tools/deploy) using the Weave toolbelt.
  </Tab>

  <Tab title="TypeScript">
    To create an Op, wrap a typescript function with `weave.op`

    ```typescript lines theme={null}
    import * as weave from 'weave'

    function trackMe(v: number) {
        return v + 5
    }

    const trackMeOp = weave.op(trackMe)
    trackMeOp(15)

    // You can also do this inline, which may be more convenient
    const trackMeInline = weave.op((v: number) => v + 5)
    trackMeInline(15)
    ```
  </Tab>
</Tabs>

## Customize display names

<Tabs>
  <Tab title="Python">
    You can customize the Op's display name by setting the `name` parameter in the `@weave.op` decorator:

    ```python lines theme={null}
    @weave.op(name="custom_name")
    def func():
        ...
    ```
  </Tab>

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

## Apply kinds and colors

To better organize your Ops in the Weave UI, you can apply custom kinds and colors to them by adding the `kind` and `color` arguments to the `@weave.op` decorators in your code. For example, the following code applies an `LLM` `kind` and a `blue` `color` to the parent function, and a `tool` `kind` and a `red` `color` to a nested function:

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

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

    @weave.op(kind="LLM", color="blue")
    def llm_func():
        @weave.op(kind="tool", color="red")
        def tool_func():
            return "tool result"

        tool_result = tool_func()
        
        return f"llm result with {tool_result}"

    llm_func()
    ```
  </Tab>

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

This applies the colors and kinds to your Ops in the Weave UI, like this:

<Frame>
  <img src="https://mintcdn.com/wb-21fd5541/mYTjDOL9RmCf9f6G/images/weave/weave_colors_kinds.png?fit=max&auto=format&n=mYTjDOL9RmCf9f6G&q=85&s=1da0fd3625dbba102fa17c7d3b6c4f03" alt="The Weave UI, showing a parent call with a LLM kind and a blue color, and a nested call with a tool kind and a red color." width="1288" height="605" data-path="images/weave/weave_colors_kinds.png" />
</Frame>

The available `kind` values are:

* `agent`
* `llm`
* `tool`
* `search`

The available `color` values are:

* `red`
* `orange`
* `yellow`
* `green`
* `blue`
* `purple`

## Customize logged inputs and outputs

<Tabs>
  <Tab title="Python">
    If you want to change the data that Weave logs without modifying the original function (for example, to hide sensitive data), you can pass `postprocess_inputs` and `postprocess_output` to the Op decorator.

    `postprocess_inputs` takes in a dict where the keys are the argument names and the values are the argument values, and returns a dict with the transformed inputs.

    `postprocess_output` takes in any value which would normally be returned by the function and returns the transformed output.

    ```python lines theme={null}
    from dataclasses import dataclass
    from typing import Any
    import weave

    @dataclass
    class CustomObject:
        x: int
        secret_password: str

    def postprocess_inputs(inputs: dict[str, Any]) -> dict[str, Any]:
        return {k:v for k,v in inputs.items() if k != "hide_me"}

    def postprocess_output(output: CustomObject) -> CustomObject:
        return CustomObject(x=output.x, secret_password="REDACTED")

    @weave.op(
        postprocess_inputs=postprocess_inputs,
        postprocess_output=postprocess_output,
    )
    def func(a: int, hide_me: str) -> CustomObject:
        return CustomObject(x=a, secret_password=hide_me)

    weave.init('hide-data-example') # 🐝
    func(a=1, hide_me="password123")
    ```
  </Tab>

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

## Control sampling rate

<Tabs>
  <Tab title="Python">
    You can control how frequently an Op's calls are traced by setting the `tracing_sample_rate` parameter in the `@weave.op` decorator. This is useful for high-frequency Ops where you only need to trace a subset of calls.

    While we recommend collecting all traces during agent development to help you better shape and understand its behavior, we recommend configuring trace sampling in production to help lower rate costs while still maintaining observability into your agent's behavior.

    Weave applies sampling rates only to outer-most Ops. If a nested Op has a sample rate but a parent Op calls it first, the sampling rate of the nested Op is ignored.

    ```python lines theme={null}
    @weave.op(tracing_sample_rate=0.1)  # Only trace ~10% of calls
    def high_frequency_op(x: int) -> int:
        return x + 1

    @weave.op(tracing_sample_rate=1.0)  # Always trace (default)
    def always_traced_op(x: int) -> int:
        return x + 1
    ```

    When an Op's call is not sampled:

    * The function executes normally
    * No trace data is sent to Weave
    * Child Ops are also not traced for that call

    The sampling rate must be between 0.0 and 1.0 inclusive.
  </Tab>

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

## Control call link output

If you want to suppress the printing of call links during logging, you can set the `WEAVE_PRINT_CALL_LINK` environment variable to `false`. This can be useful if you want to reduce output verbosity and reduce clutter in your logs.

```bash lines theme={null}
export WEAVE_PRINT_CALL_LINK=false
```

## Deleting an Op

<Tabs>
  <Tab title="Python">
    To delete a version of an Op, call `.delete()` on the Op ref.

    ```python lines theme={null}
    weave.init('intro-example')
    my_op_ref = weave.ref('track_me:v1')
    my_op_ref.delete()
    ```

    Accessing a deleted Op returns an error.
  </Tab>

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