@introspection-sdk/introspection-node
v0.8.3
Published
Introspection observability SDK for Node.js
Readme
@introspection-sdk/introspection-node
Node.js platform SDK for Introspection — open runtimes, drive tasks, and manage experiments, recipes, files, conversations, and shares.
Install
pnpm add @introspection-sdk/introspection-nodeFor OTel features (analytics, traces, instrumentors), also install the peer dependencies:
pnpm add @opentelemetry/api @opentelemetry/api-logs \
@opentelemetry/sdk-trace-base @opentelemetry/sdk-trace-node \
@opentelemetry/sdk-logs @opentelemetry/exporter-trace-otlp-proto \
@opentelemetry/exporter-logs-otlp-proto @opentelemetry/resources \
@opentelemetry/semantic-conventions @opentelemetry/context-async-hooks \
@opentelemetry/coreIntrospection API (runtimes, tasks, files)
The main Introspection API surface. No OTel packages required.
import { IntrospectionClient } from "@introspection-sdk/introspection-node";
const client = new IntrospectionClient();
const runner = await client.runtimes("customer-agent").run();
const run = await runner.tasks.start({
prompt: "Say hello in one sentence.",
});
for await (const event of run.stream()) {
console.log(event.type);
}
await runner.close();
await client.shutdown();Pi instrumentation
Pi is the supported agent-instrumentation path:
pnpm add @earendil-works/pi-agent-core @earendil-works/pi-aiimport * as introspection from "@introspection-sdk/introspection-node/otel";
import { Agent } from "@earendil-works/pi-agent-core";
import { getBuiltinModel } from "@earendil-works/pi-ai/providers/all";
await introspection.init({ serviceName: "my-app" });
const agent = new Agent({
initialState: {
model: getBuiltinModel("anthropic", "claude-sonnet-4-6"),
systemPrompt: "You are a helpful support agent.",
},
});
introspection.instrumentPi(agent, {
conversationId: "conv_123",
agentId: "support-agent",
agentName: "Support",
});
await agent.prompt("Help me understand my latest invoice.");
await introspection.shutdown();Both import styles work:
import {
init,
conversation,
track,
} from "@introspection-sdk/introspection-node/otel";Dual export
Build the OpenTelemetry provider yourself with both span processors:
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { IntrospectionSpanProcessor } from "@introspection-sdk/introspection-node/otel";
const provider = new NodeTracerProvider({
spanProcessors: [
new IntrospectionSpanProcessor({ token: process.env.INTROSPECTION_TOKEN }),
new BatchSpanProcessor(langfuseExporter),
],
});
provider.register();
await introspection.init({ tracerProvider: provider });IntrospectionSpanProcessor exports its own converted copy of each span, so the vendor processor receives the raw span and processor order is irrelevant. For a quick alternative: init({ spanProcessors: [new BatchSpanProcessor(langfuseExporter)] }).
Support for other frameworks is experimental.
Analytics events (track, feedback, identify)
import { IntrospectionLogs } from "@introspection-sdk/introspection-node/otel";
const logs = new IntrospectionLogs({
token: process.env.INTROSPECTION_TOKEN,
serviceName: "my-service",
});
await logs.withUserId("user_123", async () => {
await logs.withConversation("conv_456", "msg_123", async () => {
logs.feedback("thumbs_up", { comments: "Great response!" });
});
});
logs.track("Button Clicked", { buttonId: "submit" });
logs.identify("user_123", { email: "[email protected]" });
await logs.shutdown();Methods
| Method | Description |
| --------------------------- | ------------------------------ |
| track(event, properties?) | Track any user action |
| feedback(type, options?) | Track feedback on AI responses |
| identify(userId, traits?) | Associate a user with traits |
| flush() | Flush pending events |
| shutdown() | Shutdown and flush |
Context helpers (OTel baggage)
| Method | Description |
| ---------------------------------------------- | ---------------------------- |
| withUserId(id, callback) | Set user context |
| withConversation(id?, responseId?, callback) | Set conversation context |
| withAgent(name, id?, callback) | Set agent context |
| withAnonymousId(id, callback) | Set anonymous ID |
| withBaggage(values, callback) | Set arbitrary baggage values |
OpenTelemetry span processor
import { IntrospectionSpanProcessor } from "@introspection-sdk/introspection-node/otel";
import logfire from "@logfire/node";
logfire.configure({
additionalSpanProcessors: [
new IntrospectionSpanProcessor({ token: process.env.INTROSPECTION_TOKEN }),
],
});
logfire.instrumentOpenAI();Environment variables
export INTROSPECTION_TOKEN="intro_xxx"
export INTROSPECTION_BASE_API_URL="https://api.introspection.dev" # optional
export INTROSPECTION_BASE_OTEL_URL="https://otel.introspection.dev" # optional
export INTROSPECTION_SERVICE_NAME="my-service" # optional