AgentwatchConsole
SDK reference

Manual traces

Submit a trace by hand when a wrapper cannot reach the call you want to measure.

aw.trace() takes a complete trace payload and sends it. Reach for it when watch() does not fit: a multi-step pipeline you want recorded as one session, a streamed response assembled across several calls, or an agent whose real input is not its first argument.

refund-agent.ts
import { AgentWatchClient } from '@agentwatch-beta/sdk'

const aw = new AgentWatchClient({ apiKey: 'aw_live_...', agentId: '<agent-uuid>' })

const result = await aw.trace({
  input: 'Refund order #47829',
  output: "I've issued the refund…",
  model: 'llama-3.3-70b-versatile',
  latencyMs: 812,
  status: 'success',
  toolsUsed: ['search_kb', 'issue_refund'],
  promptTokens: 220,
  completionTokens: 180,
  totalTokens: 400,
})

Payload

inputstringrequired

What the agent was asked. Scored against the output by the correctness gate, so send the real user request rather than a rendered prompt template.

outputstringrequired

What the agent answered — the text a user would have seen.

status'success' | 'error'required

Whether the run completed. Errored runs still carry signal, so send them rather than dropping them.

latencyMsnumber

End-to-end duration in milliseconds. Feeds the latency baseline; a climbing latency is often the first visible sign of drift.

modelstring

Model identifier. Baselines are held per model, so a silent provider-side version bump shows up as a change point rather than as noise.

toolsUsedstring[]

Names of tools the run called. A shift in which tools fire is a behavioural change even when the text still reads fine.

promptTokensnumber

Tokens in the request.

completionTokensnumber

Tokens in the response.

totalTokensnumber

Prompt plus completion — sent explicitly rather than inferred.

metadataRecord<string, string | number | boolean>

Tags for this trace alone. Unlike the metadata set on a wrapper, these can vary per call.

Optional fields are worth sending

Only input, output, and status are required, but the optional fields are what the detectors work with. A trace without model or latencyMs still counts toward correctness and semantic drift; it just carries less.

The result

trace() resolves to a result instead of throwing. accepted tells you whether the trace was taken, and reason explains it when it was not.

ts
if (result.accepted) {
  console.log('Trace accepted')
} else {
  console.log('Trace was not accepted:', result.reason)
}
resolves either way — a rejected trace is a value, not an exception

This is the one place the SDK will tell you a trace did not land. Wrapped executions stay fire-and-forget by design and report nothing — see Guarantees. If an integration is not appearing in the console, a manual trace() is the fastest way to find out why.

Awaiting the call

  • In a request handler, do not await it. Let it settle after you have responded — the result is not worth your user's latency.
  • In a short-lived process — a queue worker, a serverless function, a script — await it, or the runtime may exit before the request leaves.
ts
// serverless: await, or the function may freeze mid-flight
export async function handler(event) {
  const output = await runPipeline(event)
  await aw.trace({ input: event.query, output, status: 'success' })
  return output
}
awaiting delivery is safe — trace() never rejects