> ## Documentation Index
> Fetch the complete documentation index at: https://asymptotelabs-fix-postinstall-refresh-user-hooks.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Observe

> Wrap custom agent functions with Asymptote Observe

## Observe API

Use `Observe.observe()` to create spans for custom agent orchestration: planning, tool execution, policy checks, handoffs, retrieval, and other work that provider SDKs do not expose.

## Wrap A Function

```typescript title="Wrap a tool call" lines theme={null}
import {
  ATTR_BEACON_EVENT_ACTION,
  ATTR_BEACON_EVENT_CATEGORY,
  ATTR_BEACON_HARNESS_NAME,
  ATTR_BEACON_TOOL_NAME,
  Observe,
} from "@asymptote/sdk";

const runSearch = Observe.observe(
  {
    name: "agent.tool.search",
    attributes: {
      [ATTR_BEACON_HARNESS_NAME]: "custom_agent",
      [ATTR_BEACON_EVENT_ACTION]: "tool.invoked",
      [ATTR_BEACON_EVENT_CATEGORY]: "tool",
      [ATTR_BEACON_TOOL_NAME]: "search_docs",
    },
  },
  async (query: string) => {
    return searchDocs(query);
  },
);

await runSearch("How does Beacon normalize endpoint events?");
await Observe.flush();
```

The wrapped function preserves the original return behavior for sync functions, promises, and async iterables. Errors are recorded on the span and then rethrown.

## Observe Options

| Option         | Purpose                                                    |
| -------------- | ---------------------------------------------------------- |
| `name`         | Span name                                                  |
| `spanKind`     | Optional OpenTelemetry span kind                           |
| `attributes`   | Span attributes, including Beacon compatibility attributes |
| `ignoreInput`  | Do not record `asymptote.observe.input.count`              |
| `ignoreOutput` | Do not record `asymptote.observe.output.type`              |

## Avoid Sensitive Metadata

Set `ignoreInput` or `ignoreOutput` when wrapper metadata should avoid recording argument counts or output type.

```typescript title="Ignore input and output metadata" lines theme={null}
const lookupSecretSafely = Observe.observe(
  {
    name: "agent.secret.lookup",
    ignoreInput: true,
    ignoreOutput: true,
  },
  async (id: string) => lookupSecret(id),
);
```

Beacon compatibility attributes should still be chosen carefully. Do not place raw secrets, credentials, or high-risk prompt content in custom attributes.

## Common Beacon Actions

Use Beacon compatibility attributes when a custom step should normalize into a known event category.

| Action               | Typical category | Example use                                         |
| -------------------- | ---------------- | --------------------------------------------------- |
| `prompt.submitted`   | `prompt`         | User prompt or agent turn                           |
| `tool.invoked`       | `tool`           | Function call, retrieval step, or external API call |
| `command.executed`   | `command`        | Shell command or build step                         |
| `file.modified`      | `file`           | Agent-created or edited file                        |
| `mcp.tool_invoked`   | `mcp`            | MCP server tool call                                |
| `approval.requested` | `approval`       | Human review or policy gate                         |

```typescript title="Wrap an MCP tool call" lines theme={null}
import {
  ATTR_BEACON_EVENT_ACTION,
  ATTR_BEACON_EVENT_CATEGORY,
  ATTR_BEACON_MCP_SERVER,
  ATTR_BEACON_MCP_TOOL,
  Observe,
} from "@asymptote/sdk";

const callMcpTool = Observe.observe(
  {
    name: "agent.mcp.call",
    attributes: {
      [ATTR_BEACON_EVENT_ACTION]: "mcp.tool_invoked",
      [ATTR_BEACON_EVENT_CATEGORY]: "mcp",
      [ATTR_BEACON_MCP_SERVER]: "docs",
      [ATTR_BEACON_MCP_TOOL]: "search",
    },
  },
  async (query: string) => searchDocsMcp(query),
);
```

See the [SDK reference](/sdk/reference#beacon-compatibility-attributes) for the full attribute list.
