@zespan/sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +327 -0
- package/dist/index.d.mts +588 -0
- package/dist/index.d.ts +588 -0
- package/dist/index.js +20 -0
- package/dist/index.mjs +20 -0
- package/package.json +80 -0
package/README.md
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
# @zespan/sdk
|
|
2
|
+
|
|
3
|
+
Agent observability for Node.js. Trace every AI call — latency, tokens, cost, errors — with one `init()`.
|
|
4
|
+
|
|
5
|
+
> For full documentation visit [docs.zespan.com](https://docs.zespan.com)
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @zespan/sdk
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @zespan/sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { init } from "@zespan/sdk";
|
|
19
|
+
|
|
20
|
+
init({
|
|
21
|
+
apiKey: "lqt_your_key_here",
|
|
22
|
+
projectId: "your_project_id",
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Get your API key and project ID from [app.zespan.com](https://app.zespan.com) → Project Settings → API Keys.
|
|
27
|
+
|
|
28
|
+
After `init()`, all calls to OpenAI, Anthropic, and Google GenAI are automatically traced. No further changes needed.
|
|
29
|
+
|
|
30
|
+
## Auto-instrumentation
|
|
31
|
+
|
|
32
|
+
By default, `init()` patches OpenAI, Anthropic, and Google GenAI as soon as they are imported. You do not need to wrap anything.
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { init } from "@zespan/sdk";
|
|
36
|
+
import OpenAI from "openai";
|
|
37
|
+
|
|
38
|
+
init({ apiKey: "lqt_...", projectId: "proj_..." });
|
|
39
|
+
|
|
40
|
+
const openai = new OpenAI();
|
|
41
|
+
// This call is automatically traced
|
|
42
|
+
const response = await openai.chat.completions.create({
|
|
43
|
+
model: "gpt-4o",
|
|
44
|
+
messages: [{ role: "user", content: "Hello" }],
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
To disable autopatch and wrap manually:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
init({ apiKey: "lqt_...", autopatch: false });
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Manual wrappers
|
|
55
|
+
|
|
56
|
+
When you need explicit control, or when using providers beyond OpenAI/Anthropic/Google:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { init, wrapOpenAI, wrapAnthropic, wrapGoogle } from "@zespan/sdk";
|
|
60
|
+
import OpenAI from "openai";
|
|
61
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
62
|
+
import { GoogleGenerativeAI } from "@google/generative-ai";
|
|
63
|
+
|
|
64
|
+
init({ apiKey: "lqt_...", autopatch: false });
|
|
65
|
+
|
|
66
|
+
const openai = wrapOpenAI(new OpenAI());
|
|
67
|
+
const anthropic = wrapAnthropic(new Anthropic());
|
|
68
|
+
const google = wrapGoogle(new GoogleGenerativeAI(process.env.GOOGLE_API_KEY!));
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**All available wrappers:**
|
|
72
|
+
|
|
73
|
+
| Function | Provider |
|
|
74
|
+
| ------------------------ | -------------------- |
|
|
75
|
+
| `wrapOpenAI(client)` | OpenAI |
|
|
76
|
+
| `wrapAnthropic(client)` | Anthropic |
|
|
77
|
+
| `wrapGoogle(client)` | Google Generative AI |
|
|
78
|
+
| `wrapOpenRouter(client)` | OpenRouter |
|
|
79
|
+
| `wrapBedrock(client)` | AWS Bedrock |
|
|
80
|
+
| `wrapMistral(client)` | Mistral |
|
|
81
|
+
| `wrapGroq(client)` | Groq |
|
|
82
|
+
| `wrapLiteLLM(client)` | LiteLLM |
|
|
83
|
+
|
|
84
|
+
## Configuration
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
init({
|
|
88
|
+
apiKey: "lqt_...", // required
|
|
89
|
+
projectId: "proj_...", // required — links traces to a project
|
|
90
|
+
environment: "production", // default: "production"
|
|
91
|
+
storePrompts: false, // store prompt/completion text (default: false)
|
|
92
|
+
redactKeys: ["password", "secret", "token", "api_key"], // keys to redact
|
|
93
|
+
sampleRate: 1.0, // 0.0–1.0, fraction of events to send
|
|
94
|
+
debug: false, // log SDK activity to console
|
|
95
|
+
batchSize: 50, // events per batch flush
|
|
96
|
+
flushInterval: 2000, // ms between batch flushes
|
|
97
|
+
autopatch: true, // auto-instrument OpenAI/Anthropic/Google
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## User and session context
|
|
102
|
+
|
|
103
|
+
Tag traces with user ID, session ID, or custom metadata:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { withZespanContext } from "@zespan/sdk";
|
|
107
|
+
|
|
108
|
+
await withZespanContext(
|
|
109
|
+
{ userId: "user_123", sessionId: "sess_abc", tags: { feature: "chat" } },
|
|
110
|
+
async () => {
|
|
111
|
+
// All AI calls inside here are tagged with this context
|
|
112
|
+
await openai.chat.completions.create({ ... });
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Agent tracing
|
|
118
|
+
|
|
119
|
+
Group multi-step agent workflows into a single trace:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
import { withAgent } from "@zespan/sdk";
|
|
123
|
+
|
|
124
|
+
await withAgent(
|
|
125
|
+
{
|
|
126
|
+
name: "SupportAgent",
|
|
127
|
+
role: "specialist",
|
|
128
|
+
framework: "custom",
|
|
129
|
+
tools: [{ name: "lookup_order", description: "Look up order by ID" }],
|
|
130
|
+
},
|
|
131
|
+
async (agent) => {
|
|
132
|
+
agent.logPlan(["Look up order", "Check policy", "Draft reply"]);
|
|
133
|
+
|
|
134
|
+
const result = await agent.traceTool(
|
|
135
|
+
"lookup_order",
|
|
136
|
+
{ order_id: "123" },
|
|
137
|
+
async () => fetchOrder("123")
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
agent.delegateTo("RefundAgent", "refund requested");
|
|
141
|
+
|
|
142
|
+
// Wrapped LLM calls inside here inherit agent context
|
|
143
|
+
await openai.chat.completions.create({ ... });
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Manual spans
|
|
149
|
+
|
|
150
|
+
Trace custom operations that aren't LLM calls:
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { startSpan } from "@zespan/sdk";
|
|
154
|
+
|
|
155
|
+
const { span, run } = startSpan({
|
|
156
|
+
name: "document-retrieval",
|
|
157
|
+
span_kind: "retrieval",
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
await run(async () => {
|
|
161
|
+
const docs = await vectorStore.search(query);
|
|
162
|
+
await span.end({ status: "success" });
|
|
163
|
+
return docs;
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Framework integrations
|
|
168
|
+
|
|
169
|
+
### LangChain
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
import { ZespanCallbackHandler } from "@zespan/sdk";
|
|
173
|
+
|
|
174
|
+
const handler = new ZespanCallbackHandler();
|
|
175
|
+
|
|
176
|
+
const chain = new LLMChain({ llm, prompt, callbacks: [handler] });
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Vercel AI SDK
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import { instrumentVercelAI, getLumiqVercelTelemetry } from "@zespan/sdk";
|
|
183
|
+
|
|
184
|
+
instrumentVercelAI();
|
|
185
|
+
|
|
186
|
+
// Or per-call:
|
|
187
|
+
const result = await generateText({
|
|
188
|
+
model: openai("gpt-4o"),
|
|
189
|
+
prompt: "Hello",
|
|
190
|
+
experimental_telemetry: getLumiqVercelTelemetry({ traceId: "my-trace" }),
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Google ADK
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
import { instrumentADK } from "@zespan/sdk";
|
|
198
|
+
|
|
199
|
+
instrumentADK(); // patches all ADK agents globally
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Or wrap a specific agent:
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
import { wrapADKAgent } from "@zespan/sdk";
|
|
206
|
+
|
|
207
|
+
const traced = wrapADKAgent(myAgent, { name: "MyAgent" });
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### LlamaIndex
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
import { LumiqLlamaIndexHandler } from "@zespan/sdk";
|
|
214
|
+
|
|
215
|
+
const handler = new LumiqLlamaIndexHandler();
|
|
216
|
+
Settings.callbackManager.addEventHandler(handler);
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### CrewAI / AutoGen / PydanticAI
|
|
220
|
+
|
|
221
|
+
These frameworks use OTEL-based instrumentation. See exports:
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
import {
|
|
225
|
+
CREWAI_OTEL_ENV,
|
|
226
|
+
getCrewAIInstrumentationGuide,
|
|
227
|
+
} from "@zespan/sdk";
|
|
228
|
+
import { injectAutoGenContext } from "@zespan/sdk";
|
|
229
|
+
import { getPydanticAIConfig } from "@zespan/sdk";
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Prompt management
|
|
233
|
+
|
|
234
|
+
Fetch versioned prompts from Zespan with 5-minute client-side cache:
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
import { getZespanClient } from "@zespan/sdk";
|
|
238
|
+
|
|
239
|
+
const client = getZespanClient();
|
|
240
|
+
|
|
241
|
+
// Latest version
|
|
242
|
+
const prompt = await client.prompts.get("support-reply");
|
|
243
|
+
|
|
244
|
+
// Specific version or label
|
|
245
|
+
const prompt = await client.prompts.get("support-reply", { version: 3 });
|
|
246
|
+
const prompt = await client.prompts.get("support-reply", {
|
|
247
|
+
label: "production",
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Compile variables
|
|
251
|
+
const text = client.prompts.compile(prompt, {
|
|
252
|
+
user_name: "Alice",
|
|
253
|
+
product: "Pro",
|
|
254
|
+
});
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Guardrails
|
|
258
|
+
|
|
259
|
+
Check content against your configured guardrail rules before or after LLM calls:
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
import { getZespanClient, GuardrailBlockedError } from "@zespan/sdk";
|
|
263
|
+
|
|
264
|
+
const client = getZespanClient();
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
const check = await client.checkGuardrails({
|
|
268
|
+
text: userMessage,
|
|
269
|
+
phase: "pre",
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
if (!check.allowed) {
|
|
273
|
+
return "Request blocked by content policy.";
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const response = await openai.chat.completions.create({ ... });
|
|
277
|
+
|
|
278
|
+
const postCheck = await client.checkGuardrails({
|
|
279
|
+
text: response.choices[0].message.content!,
|
|
280
|
+
phase: "post",
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
return postCheck.modifiedText ?? response.choices[0].message.content;
|
|
284
|
+
} catch (err) {
|
|
285
|
+
if (err instanceof GuardrailBlockedError) {
|
|
286
|
+
return "Response blocked by content policy.";
|
|
287
|
+
}
|
|
288
|
+
throw err;
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Guardrails can also be applied automatically via wrapper options:
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
const openai = wrapOpenAI(new OpenAI(), { guardrails: true });
|
|
296
|
+
// or fine-grained:
|
|
297
|
+
const openai = wrapOpenAI(new OpenAI(), {
|
|
298
|
+
guardrails: { pre: true, post: true, failClosed: false },
|
|
299
|
+
});
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## Flush on exit
|
|
303
|
+
|
|
304
|
+
The SDK flushes automatically on `process.beforeExit`. For serverless functions or short-lived scripts, flush manually:
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
import { getZespanClient } from "@zespan/sdk";
|
|
308
|
+
|
|
309
|
+
await getZespanClient().flush();
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## OpenTelemetry
|
|
313
|
+
|
|
314
|
+
Enable native OTEL export alongside Zespan:
|
|
315
|
+
|
|
316
|
+
```ts
|
|
317
|
+
init({
|
|
318
|
+
apiKey: "lqt_...",
|
|
319
|
+
enableOTel: true,
|
|
320
|
+
otelEndpoint: "http://localhost:4318",
|
|
321
|
+
otelServiceName: "my-service",
|
|
322
|
+
});
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
## TypeScript
|
|
326
|
+
|
|
327
|
+
The SDK is fully typed. All wrapper functions preserve the original client's type signature.
|