Skip to main content
LLM wrappers capture tools the model executes inside a wrapped call. For tools your own code invokes directly, wrap the function with wrapTool — every execution is then captured as a tool event with input, output, duration, and status.

Wrap a function

import { Carbon } from "@carbon-js/sdk";

const carbon = new Carbon();

const getWeather = carbon.wrapTool({
  name: "get_weather",
  run: async ({ city }: { city: string }) => {
    const response = await fetch(`https://api.weather.example/v1/${city}`);
    return response.json();
  },
});

const weather = await getWeather({ city: "Tokyo" });
The wrapped function has the same signature and return type as run. Sync and async functions both work.
  • On success, the event records the serialized input and output with status.state: "ok".
  • On failure, the event records the error with status.state: "error" and the original error is rethrown — wrapping never swallows exceptions.

Attach metadata

The wrapped function accepts one optional trailing argument carrying Carbon metadata. It is detected by the presence of a traceId, context, or additionalProperties key and is not passed to your run function:
const traceId = carbon.createTraceId();

const weather = await getWeather(
  { city: "Tokyo" },
  { traceId, context: { agentId: "travel-agent", userId: "user-481" } },
);
This puts the tool event on the same trace as the LLM calls around it — see Traces and context.
Detection is by key presence only. If your tool’s real last argument has a traceId, context, or additionalProperties key, it would be treated as Carbon metadata — rename the field or wrap the value in an object.