Skip to content

Trace an answer and its cost

Every agent turn leaves a provenance record: a graph of the turn, from the user's message through each model call and tool call to the answer. It names the model of each call, its tokens and its cost, and the version of each tool. Use it to answer "where did this answer come from?" and "what did it cost?".

Fetch it by the run's id. With kindgi dev, $KINDGI_API_URL and $KINDGI_API_TOKEN are the URL and token it prints (they're also in the pack's .kindgirc.json).

Terminal window
curl "$KINDGI_API_URL/v1/provenance/3622fc4e-a54d-4df8-a84f-14a957eed7db" \
-H "Authorization: Bearer $KINDGI_API_TOKEN"
{
"id": "5a31107b-d942-4741-a96d-2ea5a2eb34c3",
"runId": "3622fc4e-a54d-4df8-a84f-14a957eed7db",
…
"dag": {
"nodes": [
{ "id": "input:0", "kind": "input", "timestamp": "2026-10-03T19:55:06.872Z" },
{ "id": "model-call:1", "kind": "model-call", "timestamp": "2026-10-03T19:55:07.001Z",
"modelVersion": "dev-echo/dev-echo-v1",
"attributes": { "step": 1, "costUsd": 0, "finishReason": "tool-use", "promptTokens": 20, "completionTokens": 6 } },
{ "id": "tool-call:dev-echo-call-1", "kind": "tool-call", "timestamp": "2026-10-03T19:55:07.131Z",
"attributes": { "toolId": "acme-ops.echo", "toolVersion": "0.1.0", "invocationId": "dev-echo-call-1", "toolVersionRange": "0.1.0" } },
{ "id": "tool-result:dev-echo-call-1", "kind": "tool-result", "timestamp": "2026-10-03T19:55:07.131Z" },
{ "id": "model-call:2", "kind": "model-call", "timestamp": "2026-10-03T19:55:07.168Z",
"modelVersion": "dev-echo/dev-echo-v1",
"attributes": { "step": 2, "costUsd": 0, "finishReason": "stop", "promptTokens": 30, "completionTokens": 12 } },
{ "id": "model-output:2", "kind": "model-output", "timestamp": "2026-10-03T19:55:07.229Z", "modelVersion": "dev-echo/dev-echo-v1" }
],
"edges": [
{ "from": "model-call:1", "to": "input:0", "kind": "caused-by" },
{ "from": "tool-call:dev-echo-call-1", "to": "model-call:1", "kind": "invoked" },
{ "from": "tool-result:dev-echo-call-1", "to": "tool-call:dev-echo-call-1", "kind": "produced" },
{ "from": "model-call:2", "to": "input:0", "kind": "caused-by" },
{ "from": "model-output:2", "to": "model-call:2", "kind": "produced" }
]
}
}

Read it from the answer backwards: the answer (model-output:2) was produced by the second model call, which answered the user's message (input:0); the first model call invoked acme-ops.echo 0.1.0, which produced a result.

Node What it is
input The message the turn answered.
model-call One call to a model: modelVersion is provider/model; attributes has the tokens, the cost in USD and why the model stopped.
tool-call, tool-result A tool the model called, with the exact tool version that ran, and what it returned.
model-output The answer.

Edges point from an effect to its cause: caused-by, invoked, produced.

kindgi runs get <run-id> shows the same graph, under output.provenance.

trace.ts
import { createClient } from '@kindgi/sdk/client';
import type { RunId } from '@kindgi/sdk/types';
const kindgi = createClient(); // KINDGI_API_URL, KINDGI_API_TOKEN, or the running kindgi dev
const record = await kindgi.provenance.get(process.argv[2] as RunId);
for (const node of record.dag.nodes) {
console.log(node.kind, node.modelVersion ?? '', node.attributes ?? '');
}
input
model-call dev-echo/dev-echo-v1 {
step: 1,
costUsd: 0,
finishReason: 'tool-use',
promptTokens: 20,
completionTokens: 6
}
tool-call {
toolId: 'acme-ops.echo',
toolVersion: '0.1.0',
invocationId: 'dev-echo-call-1',
toolVersionRange: '0.1.0'
}
…

Each model-call node's costUsd is its tokens times the prices its provider was registered with (see Connect a model). dev-echo is free, so its calls cost 0. With a provider registered at promptUsdPer1kTokens: 0.001 and completionUsdPer1kTokens: 0.002, a call with 258 prompt tokens and 53 completion tokens:

{ "id": "model-call:1", "kind": "model-call", "timestamp": "2026-10-03T20:02:55.367Z",
"modelVersion": "ollama/llama3.1",
"attributes": { "step": 1, "costUsd": 0.00036400000000000007, "finishReason": "stop", "promptTokens": 258, "completionTokens": 53 } }

The whole turn's total is in the run's output, under usage:

Terminal window
kindgi runs get <run-id>
"usage": {
"steps": 1,
"durationMs": 2249,
"promptTokens": 258,
"totalCostUsd": 0.00036400000000000007,
"completionTokens": 53
},

A flow run has no record of its own:

{"error":{"code":"provenance-not-found","message":"No provenance record for run \"41027166-71ec-4bd6-b516-cc47c0787da4\"","details":{"runId":"41027166-71ec-4bd6-b516-cc47c0787da4"},"requestId":"req-997f000a-22f6-470a-b52b-acdd21d6e228"}}

Each agent step is a run of its own, with its own record. The step's output in the flow's journal has that run's id:

Terminal window
kindgi runs journal <flow-run-id>
{
"sequence": 9,
"kind": "step.completed",
"nodeId": "respond",
"payload": {
"output": {
"text": "Tool responded: …",
"runId": "4bdae2f9-ff67-48a3-9549-49028d290cc1",
…

Fetch the record for 4bdae2f9-….

GET /v1/provenance lists records, newest first, without their graphs. Filter by runId or by createdAfter:

Terminal window
curl "$KINDGI_API_URL/v1/provenance?createdAfter=2026-10-03T20:08:00Z&limit=3" \
-H "Authorization: Bearer $KINDGI_API_TOKEN"
{"data":[{"id":"8771ea27-dc53-4c55-a799-dc78136182b0","runId":"98d49ad7-fb24-4d0f-a9e0-b5d1743a4392","tenantId":"3a9fb26d-9782-4bdb-a4f9-3c97d2644b72","version":"1.0.0","createdAt":"2026-10-03T20:10:08.430Z","signed":false},…]}

See Provenance in the HTTP API.