Manual instrumentation
Open core · self-host + all Splyntra Cloud plans
Auto-instrumentation covers supported frameworks and providers. For your own code — custom agents, hand-rolled tool functions, or a provider without a native instrumentor — wrap or decorate the function and it becomes a span like any other.
There are three primitives, one per span kind:
| Span kind | Python decorator | TypeScript wrapper | TypeScript decorator |
|---|---|---|---|
agent | @trace_agent(name, workflow) | wrapAgent(fn, name, workflow) | @traceAgent(name, workflow) |
tool_call | @trace_tool(name) | wrapTool(fn, name) | @traceTool(name) |
llm_call | @trace_llm(model, provider) | wrapLLM(fn, model, provider) | @traceLLM(model, provider) |
Tracing your functions
- Python
- TypeScript
Decorate the function. Both sync and async functions are supported.
from splyntra import trace_agent, trace_tool, trace_llm
@trace_agent(name="support_agent", workflow="refund")
def run(query: str):
customer = read_customer("42")
return call_llm(query)
@trace_tool(name="crm.read")
def read_customer(id: str):
...
@trace_llm(model="gpt-4o", provider="openai")
def call_llm(prompt: str) -> dict:
# Return a dict with a "usage" key for token/cost analytics.
...
Use function wrappers (TypeScript and JavaScript):
import { wrapAgent, wrapTool, wrapLLM } from "@splyntra/sdk";
const readCustomer = wrapTool(
async (id: string) => db.get(id),
"crm.read",
);
const callLLM = wrapLLM(
async (prompt: string) =>
openai.chat.completions.create({ model: "gpt-4o", messages: [{ role: "user", content: prompt }] }),
"gpt-4o",
"openai",
);
const runAgent = wrapAgent(
async (query: string) => {
await readCustomer("42");
return callLLM(query);
},
"support_agent",
"refund",
);
Or decorators (TypeScript only) with "experimentalDecorators": true in tsconfig.json:
import { traceAgent, traceTool, traceLLM } from "@splyntra/sdk";
class SupportAgent {
@traceAgent("support_agent", "refund")
async run(query: string) { /* ... */ }
@traceTool("crm.read")
async readCustomer(id: string) { /* ... */ }
@traceLLM("gpt-4o", "openai")
async complete(prompt: string) { /* ... */ }
}
Returning usage for cost
For an LLM function to contribute to cost analytics, its
return value must carry token usage. Splyntra reads prompt_tokens and
completion_tokens from a usage field on the returned object — the same shape
providers return.
- Python
- TypeScript
@trace_llm(model="gpt-4o", provider="openai")
def call_llm(prompt: str) -> dict:
return {
"text": "...",
"usage": {"prompt_tokens": 812, "completion_tokens": 143},
}
const callLLM = wrapLLM(
async (prompt: string) => ({
text: "...",
usage: { prompt_tokens: 812, completion_tokens: 143 },
}),
"gpt-4o",
"openai",
);
If usage is omitted the call is still traced — only the cost figure is missing.
Sync and async
The Python decorators work on both sync and async functions. The TypeScript wrappers and decorators work on async functions returning promises, matching the async style of the provider SDKs.
Next steps
- Traces & risk — the span kinds you are producing.
- Cost analytics — how
usagebecomes cost. - Python SDK · TypeScript SDK — full references.