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

# tp.wrapToolCall() method — TracePilot SDK reference

> Wrap any async tool or function call to capture a span. Optionally mark it as destructive to flag operations that modify external state in the dashboard.

`tp.wrapToolCall()` wraps any asynchronous function — a database write, an email send, a web search, or any other tool invocation — and records it as a structured span linked to a parent span in your execution tree. Set `isDestructive: true` on operations that modify external state so the dashboard surfaces a warning badge, making it easy to audit side effects during debugging.

## Signature

```typescript theme={null}
tp.wrapToolCall<T>(
  toolName: string,
  call: () => Promise<T>,
  parentSpanId: string,
  stepOrder: number,
  isDestructive?: boolean
): Promise<{ result: T; spanId: string }>
```

## Parameters

<ParamField path="toolName" type="string" required>
  A human-readable display name for the tool. This label appears in the dashboard's execution tree and is used to identify the span when debugging.
</ParamField>

<ParamField path="call" type="() => Promise<T>" required>
  A zero-argument async function that executes the tool. Wrap your call in an arrow function so TracePilot can time it and capture any errors that are thrown.
</ParamField>

<ParamField path="parentSpanId" type="string" required>
  The `spanId` of the parent span. Tool calls must always be linked to a parent — typically the `spanId` returned by the `wrapOpenAI` call that decided to invoke this tool.
</ParamField>

<ParamField path="stepOrder" type="number" required>
  An integer that controls where this span appears among its siblings in the execution tree. Use sequential integers (1, 2, 3…) to preserve the correct order in the dashboard.
</ParamField>

<ParamField path="isDestructive" type="boolean">
  When `true`, the dashboard marks this span with a **⚠ Destructive** badge. Use this flag for any operation that modifies external state — sending emails, writing to a database, publishing messages, calling payment APIs, and so on. Defaults to `false`.
</ParamField>

## Return value

<ResponseField name="result" type="T">
  The value resolved by your `call` function, returned unchanged. The generic type `T` is inferred from your function's return type.
</ResponseField>

<ResponseField name="spanId" type="string">
  The ID of the span created for this tool call. You can pass this as `parentSpanId` to downstream `wrapOpenAI` or `wrapToolCall` calls to nest them further.
</ResponseField>

## Examples

<CodeGroup>
  ```typescript Destructive tool call (send-email) theme={null}
  import { TracePilot } from 'tracepilot-sdk';

  const tp = new TracePilot(process.env.TRACEPILOT_API_KEY!);

  async function runAgent() {
    await tp.startTrace('notification-agent');

    // ... prior LLM call returns planSpanId

    const { result, spanId } = await tp.wrapToolCall(
      'send-email',
      () => sendEmail(to, subject, body),
      planSpanId,
      2,
      true  // marks this span with a ⚠ Destructive badge
    );

    console.log('Email sent:', result.messageId);
  }
  ```

  ```typescript Non-destructive tool call (web-search) theme={null}
  import { TracePilot } from 'tracepilot-sdk';

  const tp = new TracePilot(process.env.TRACEPILOT_API_KEY!);

  async function runAgent(query: string) {
    await tp.startTrace('research-agent');

    const messages = [{ role: 'user', content: query }];

    const { result: plan, spanId: planSpanId } = await tp.wrapOpenAI(
      () => openai.chat.completions.create({ model: 'gpt-4o', messages }),
      messages,
      undefined,
      1
    );

    // Read-only search — no isDestructive flag needed
    const { result: searchResult, spanId: searchSpanId } = await tp.wrapToolCall(
      'web-search',
      () => webSearch(plan.choices[0].message.content),
      planSpanId,
      2
    );

    return searchResult;
  }
  ```
</CodeGroup>

<Warning>
  Set `isDestructive: true` for any tool that modifies external state. This includes — but is not limited to — sending emails or SMS messages, writing or deleting database records, publishing to message queues, making payment API calls, posting to social media, and modifying files on disk. The badge serves as a safety signal during Fork & Rerun sessions, letting you quickly identify which spans had real-world side effects.
</Warning>
