wiretap-llm 0.1.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 +112 -0
- package/dist/client.d.ts +35 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +192 -0
- package/dist/json.d.ts +19 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/types/telemetry.d.ts +56 -0
- package/dist/types/telemetry.d.ts.map +1 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# wiretap-llm
|
|
2
|
+
|
|
3
|
+
Telemetry client for sending LLM logs to your Wiretap instance.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install wiretap-llm
|
|
9
|
+
# or
|
|
10
|
+
bun add wiretap-llm
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { TelemetryClient, createId, toIso } from "wiretap-llm";
|
|
17
|
+
|
|
18
|
+
// Create client
|
|
19
|
+
const client = new TelemetryClient({
|
|
20
|
+
baseUrl: process.env.WIRETAP_BASE_URL!,
|
|
21
|
+
apiKey: process.env.WIRETAP_API_KEY!,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Send a log
|
|
25
|
+
client.report({
|
|
26
|
+
id: createId(),
|
|
27
|
+
timestamp: toIso(new Date()),
|
|
28
|
+
project: "", // Inferred from API key
|
|
29
|
+
source: "openrouter",
|
|
30
|
+
method: "POST",
|
|
31
|
+
url: "https://openrouter.ai/api/v1/chat/completions",
|
|
32
|
+
path: "/v1/chat/completions",
|
|
33
|
+
model: "anthropic/claude-sonnet-4",
|
|
34
|
+
streamed: true,
|
|
35
|
+
timing: {
|
|
36
|
+
started_at: toIso(startTime),
|
|
37
|
+
ended_at: toIso(endTime),
|
|
38
|
+
duration_ms: endTime.getTime() - startTime.getTime(),
|
|
39
|
+
},
|
|
40
|
+
request: {
|
|
41
|
+
body_json: requestBody,
|
|
42
|
+
},
|
|
43
|
+
stream: {
|
|
44
|
+
output_text: "Hello!",
|
|
45
|
+
finish_reason: "stop",
|
|
46
|
+
usage: { prompt_tokens: 10, completion_tokens: 5 },
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// On app shutdown
|
|
51
|
+
await client.shutdown();
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Configuration
|
|
55
|
+
|
|
56
|
+
### TelemetryClient Options
|
|
57
|
+
|
|
58
|
+
| Option | Type | Required | Default | Description |
|
|
59
|
+
|--------|------|----------|---------|-------------|
|
|
60
|
+
| `baseUrl` | string | Yes | - | Your Wiretap instance URL |
|
|
61
|
+
| `apiKey` | string | Yes | - | Your Wiretap API key |
|
|
62
|
+
| `project` | string | No | - | Project slug (usually inferred from API key) |
|
|
63
|
+
| `environment` | string | No | - | Environment name (e.g., "production") |
|
|
64
|
+
| `defaultMetadata` | object | No | - | Metadata added to all logs |
|
|
65
|
+
| `timeoutMs` | number | No | 5000 | Request timeout |
|
|
66
|
+
| `maxBatchSize` | number | No | 25 | Max logs per batch |
|
|
67
|
+
| `flushIntervalMs` | number | No | 2000 | Auto-flush interval |
|
|
68
|
+
| `maxLogBytes` | number | No | 1000000 | Max log size before truncation |
|
|
69
|
+
| `onError` | function | No | - | Error handler |
|
|
70
|
+
|
|
71
|
+
## API
|
|
72
|
+
|
|
73
|
+
### `client.report(log: TelemetryLog)`
|
|
74
|
+
|
|
75
|
+
Queue a log for sending. Logs are batched and sent automatically.
|
|
76
|
+
|
|
77
|
+
### `client.flush()`
|
|
78
|
+
|
|
79
|
+
Manually flush pending logs.
|
|
80
|
+
|
|
81
|
+
### `client.shutdown()`
|
|
82
|
+
|
|
83
|
+
Flush remaining logs and stop the client. Call on app shutdown.
|
|
84
|
+
|
|
85
|
+
## Helper Utilities
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { createId, toIso, sanitizeHeaders, safeJsonParse } from "wiretap-llm";
|
|
89
|
+
|
|
90
|
+
// Generate unique ID
|
|
91
|
+
const id = createId(); // "abc123..."
|
|
92
|
+
|
|
93
|
+
// ISO timestamp
|
|
94
|
+
const ts = toIso(new Date()); // "2024-01-20T..."
|
|
95
|
+
|
|
96
|
+
// Remove sensitive headers
|
|
97
|
+
const headers = sanitizeHeaders(req.headers); // Strips auth headers
|
|
98
|
+
|
|
99
|
+
// Safe JSON parse
|
|
100
|
+
const { ok, value } = safeJsonParse(jsonString);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Environment Variables
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
WIRETAP_BASE_URL=https://your-wiretap-instance.com
|
|
107
|
+
WIRETAP_API_KEY=wt_your_api_key
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { JsonValue } from "./json";
|
|
2
|
+
import type { TelemetryLog } from "./types/telemetry";
|
|
3
|
+
export type TelemetryClientOptions = {
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
apiKey: string;
|
|
6
|
+
/** Optional - project is automatically inferred from API key on server */
|
|
7
|
+
project?: string;
|
|
8
|
+
environment?: string;
|
|
9
|
+
defaultMetadata?: Record<string, JsonValue>;
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
maxBatchSize?: number;
|
|
12
|
+
flushIntervalMs?: number;
|
|
13
|
+
maxLogBytes?: number;
|
|
14
|
+
onError?: (err: unknown) => void;
|
|
15
|
+
};
|
|
16
|
+
export declare class TelemetryClient {
|
|
17
|
+
readonly baseUrl: string;
|
|
18
|
+
readonly apiKey: string;
|
|
19
|
+
readonly project?: string;
|
|
20
|
+
readonly environment?: string;
|
|
21
|
+
readonly defaultMetadata?: Record<string, JsonValue>;
|
|
22
|
+
private timeoutMs;
|
|
23
|
+
private maxBatchSize;
|
|
24
|
+
private flushIntervalMs;
|
|
25
|
+
private maxLogBytes;
|
|
26
|
+
private queue;
|
|
27
|
+
private flushing;
|
|
28
|
+
private timer;
|
|
29
|
+
private onError?;
|
|
30
|
+
constructor(opts: TelemetryClientOptions);
|
|
31
|
+
report(log: TelemetryLog): void;
|
|
32
|
+
flush(): Promise<void>;
|
|
33
|
+
shutdown(): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,KAAK,EAAyB,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE7E,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CAClC,CAAC;AAEF,qBAAa,eAAe;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAErD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAA+C;IAE5D,OAAO,CAAC,OAAO,CAAC,CAAyB;gBAE7B,IAAI,EAAE,sBAAsB;IAuBxC,MAAM,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI;IAmCzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA0EtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAQhC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { TelemetryClient } from "./client";
|
|
2
|
+
export type { TelemetryClientOptions } from "./client";
|
|
3
|
+
export type { TelemetryBatchPayload, TelemetryLog, TelemetryTrace, } from "./types/telemetry";
|
|
4
|
+
export { createId, safeJsonParse, sanitizeHeaders, toIso, truncateUtf8 } from "./json";
|
|
5
|
+
export type { JsonPrimitive, JsonValue } from "./json";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,YAAY,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAGvD,YAAY,EACV,qBAAqB,EACrB,YAAY,EACZ,cAAc,GACf,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACvF,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
// src/json.ts
|
|
2
|
+
function toIso(d) {
|
|
3
|
+
return d.toISOString();
|
|
4
|
+
}
|
|
5
|
+
function createId() {
|
|
6
|
+
const c = globalThis.crypto;
|
|
7
|
+
if (c?.randomUUID)
|
|
8
|
+
return c.randomUUID();
|
|
9
|
+
return `id_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`;
|
|
10
|
+
}
|
|
11
|
+
function safeJsonParse(text) {
|
|
12
|
+
try {
|
|
13
|
+
const v = JSON.parse(text);
|
|
14
|
+
return { ok: true, value: v };
|
|
15
|
+
} catch (e) {
|
|
16
|
+
return { ok: false, error: e instanceof Error ? e.message : "Invalid JSON" };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
var SENSITIVE_HEADERS = new Set([
|
|
20
|
+
"authorization",
|
|
21
|
+
"cookie",
|
|
22
|
+
"set-cookie",
|
|
23
|
+
"x-api-key",
|
|
24
|
+
"api-key"
|
|
25
|
+
]);
|
|
26
|
+
function sanitizeHeaders(headers) {
|
|
27
|
+
const out = {};
|
|
28
|
+
if (!headers)
|
|
29
|
+
return out;
|
|
30
|
+
const set = (k, v) => {
|
|
31
|
+
const key = k.toLowerCase();
|
|
32
|
+
if (SENSITIVE_HEADERS.has(key))
|
|
33
|
+
return;
|
|
34
|
+
out[key] = v;
|
|
35
|
+
};
|
|
36
|
+
if (headers instanceof Headers) {
|
|
37
|
+
headers.forEach((v, k) => set(k, v));
|
|
38
|
+
} else if (Array.isArray(headers)) {
|
|
39
|
+
for (const [k, v] of headers)
|
|
40
|
+
set(k, v);
|
|
41
|
+
} else {
|
|
42
|
+
for (const [k, v] of Object.entries(headers))
|
|
43
|
+
set(k, String(v));
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
function truncateUtf8(input, maxBytes) {
|
|
48
|
+
const enc = new TextEncoder;
|
|
49
|
+
const bytes = enc.encode(input);
|
|
50
|
+
if (bytes.length <= maxBytes)
|
|
51
|
+
return { text: input, truncated: false };
|
|
52
|
+
const sliced = bytes.slice(0, maxBytes);
|
|
53
|
+
const dec = new TextDecoder("utf-8", { fatal: false });
|
|
54
|
+
return { text: dec.decode(sliced), truncated: true };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/client.ts
|
|
58
|
+
class TelemetryClient {
|
|
59
|
+
baseUrl;
|
|
60
|
+
apiKey;
|
|
61
|
+
project;
|
|
62
|
+
environment;
|
|
63
|
+
defaultMetadata;
|
|
64
|
+
timeoutMs;
|
|
65
|
+
maxBatchSize;
|
|
66
|
+
flushIntervalMs;
|
|
67
|
+
maxLogBytes;
|
|
68
|
+
queue = [];
|
|
69
|
+
flushing = false;
|
|
70
|
+
timer = null;
|
|
71
|
+
onError;
|
|
72
|
+
constructor(opts) {
|
|
73
|
+
this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
|
|
74
|
+
this.apiKey = opts.apiKey;
|
|
75
|
+
this.project = opts.project;
|
|
76
|
+
this.environment = opts.environment;
|
|
77
|
+
this.defaultMetadata = opts.defaultMetadata;
|
|
78
|
+
this.timeoutMs = opts.timeoutMs ?? 5000;
|
|
79
|
+
this.maxBatchSize = opts.maxBatchSize ?? 25;
|
|
80
|
+
this.flushIntervalMs = opts.flushIntervalMs ?? 2000;
|
|
81
|
+
this.maxLogBytes = opts.maxLogBytes ?? 1e6;
|
|
82
|
+
this.onError = opts.onError;
|
|
83
|
+
if (this.flushIntervalMs > 0) {
|
|
84
|
+
this.timer = setInterval(() => void this.flush(), this.flushIntervalMs);
|
|
85
|
+
if (typeof this.timer === "object" && "unref" in this.timer) {
|
|
86
|
+
this.timer.unref();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
report(log) {
|
|
91
|
+
if (this.project) {
|
|
92
|
+
log.project = log.project || this.project;
|
|
93
|
+
}
|
|
94
|
+
log.environment = log.environment ?? this.environment;
|
|
95
|
+
if (this.defaultMetadata) {
|
|
96
|
+
log.metadata = { ...this.defaultMetadata, ...log.metadata ?? {} };
|
|
97
|
+
}
|
|
98
|
+
const raw = JSON.stringify(log);
|
|
99
|
+
const truncated = truncateUtf8(raw, this.maxLogBytes);
|
|
100
|
+
if (!truncated.truncated) {
|
|
101
|
+
this.queue.push(log);
|
|
102
|
+
} else {
|
|
103
|
+
this.queue.push({
|
|
104
|
+
...log,
|
|
105
|
+
request: {
|
|
106
|
+
...log.request,
|
|
107
|
+
body_text: "[truncated - log exceeded maxLogBytes]",
|
|
108
|
+
body_truncated: true
|
|
109
|
+
},
|
|
110
|
+
error: log.error ?? { message: "Log truncated to maxLogBytes" }
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
if (this.queue.length >= this.maxBatchSize) {
|
|
114
|
+
this.flush();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async flush() {
|
|
118
|
+
if (this.flushing)
|
|
119
|
+
return;
|
|
120
|
+
if (this.queue.length === 0)
|
|
121
|
+
return;
|
|
122
|
+
this.flushing = true;
|
|
123
|
+
const batch = this.queue.splice(0, this.maxBatchSize);
|
|
124
|
+
try {
|
|
125
|
+
const payload = { logs: batch };
|
|
126
|
+
const ctrl = new AbortController;
|
|
127
|
+
const t = setTimeout(() => ctrl.abort(), this.timeoutMs);
|
|
128
|
+
const res = await fetch(`${this.baseUrl}/v1/logs/batch`, {
|
|
129
|
+
method: "POST",
|
|
130
|
+
headers: {
|
|
131
|
+
"content-type": "application/json",
|
|
132
|
+
authorization: `Bearer ${this.apiKey}`
|
|
133
|
+
},
|
|
134
|
+
body: JSON.stringify(payload),
|
|
135
|
+
signal: ctrl.signal
|
|
136
|
+
});
|
|
137
|
+
clearTimeout(t);
|
|
138
|
+
if (res.status === 207) {
|
|
139
|
+
const body = await res.json().catch(() => null);
|
|
140
|
+
const failedIds = new Set;
|
|
141
|
+
if (body && typeof body === "object") {
|
|
142
|
+
const failed = body.failed;
|
|
143
|
+
if (Array.isArray(failed)) {
|
|
144
|
+
for (const item of failed) {
|
|
145
|
+
if (item && typeof item === "object") {
|
|
146
|
+
const id = item.id;
|
|
147
|
+
if (typeof id === "string") {
|
|
148
|
+
failedIds.add(id);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (failedIds.size > 0) {
|
|
155
|
+
const retry = batch.filter((log) => failedIds.has(log.id));
|
|
156
|
+
if (retry.length > 0) {
|
|
157
|
+
this.queue.unshift(...retry);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const partialMessage = body && typeof body === "object" ? body.partial_success?.error_message : undefined;
|
|
161
|
+
const message = typeof partialMessage === "string" ? partialMessage : "Telemetry partial success";
|
|
162
|
+
this.onError?.(new Error(message));
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (!res.ok) {
|
|
166
|
+
this.queue.unshift(...batch);
|
|
167
|
+
const errorText = await res.text().catch(() => "");
|
|
168
|
+
throw new Error(`Telemetry ingest failed: ${res.status} ${res.statusText} - ${errorText}`);
|
|
169
|
+
}
|
|
170
|
+
} catch (err) {
|
|
171
|
+
this.queue.unshift(...batch);
|
|
172
|
+
this.onError?.(err);
|
|
173
|
+
} finally {
|
|
174
|
+
this.flushing = false;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async shutdown() {
|
|
178
|
+
if (this.timer) {
|
|
179
|
+
clearInterval(this.timer);
|
|
180
|
+
this.timer = null;
|
|
181
|
+
}
|
|
182
|
+
await this.flush();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
export {
|
|
186
|
+
truncateUtf8,
|
|
187
|
+
toIso,
|
|
188
|
+
sanitizeHeaders,
|
|
189
|
+
safeJsonParse,
|
|
190
|
+
createId,
|
|
191
|
+
TelemetryClient
|
|
192
|
+
};
|
package/dist/json.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type JsonPrimitive = string | number | boolean | null;
|
|
2
|
+
export type JsonValue = JsonPrimitive | JsonValue[] | {
|
|
3
|
+
[key: string]: JsonValue;
|
|
4
|
+
};
|
|
5
|
+
export declare function toIso(d: Date): string;
|
|
6
|
+
export declare function createId(): string;
|
|
7
|
+
export declare function safeJsonParse(text: string): {
|
|
8
|
+
ok: true;
|
|
9
|
+
value: JsonValue;
|
|
10
|
+
} | {
|
|
11
|
+
ok: false;
|
|
12
|
+
error: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function sanitizeHeaders(headers: HeadersInit | undefined): Record<string, string>;
|
|
15
|
+
export declare function truncateUtf8(input: string, maxBytes: number): {
|
|
16
|
+
text: string;
|
|
17
|
+
truncated: boolean;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AAC7D,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,SAAS,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEnF,wBAAgB,KAAK,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAErC;AAED,wBAAgB,QAAQ,IAAI,MAAM,CAIjC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAOzG;AAUD,wBAAgB,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmBxF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAQlG"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { JsonValue } from "../json";
|
|
2
|
+
export type TelemetryTrace = {
|
|
3
|
+
trace_id?: string;
|
|
4
|
+
span_id?: string;
|
|
5
|
+
parent_span_id?: string;
|
|
6
|
+
};
|
|
7
|
+
export type TelemetryLog = {
|
|
8
|
+
id: string;
|
|
9
|
+
timestamp: string;
|
|
10
|
+
project: string;
|
|
11
|
+
environment?: string;
|
|
12
|
+
source: string;
|
|
13
|
+
method: string;
|
|
14
|
+
url: string;
|
|
15
|
+
path: string;
|
|
16
|
+
model?: string;
|
|
17
|
+
generation_id?: string;
|
|
18
|
+
streamed: boolean;
|
|
19
|
+
timing: {
|
|
20
|
+
started_at: string;
|
|
21
|
+
ended_at?: string;
|
|
22
|
+
duration_ms?: number;
|
|
23
|
+
};
|
|
24
|
+
metadata?: Record<string, JsonValue>;
|
|
25
|
+
trace?: TelemetryTrace;
|
|
26
|
+
request: {
|
|
27
|
+
headers?: Record<string, string>;
|
|
28
|
+
body_json?: JsonValue;
|
|
29
|
+
body_text?: string;
|
|
30
|
+
body_truncated?: boolean;
|
|
31
|
+
};
|
|
32
|
+
response?: {
|
|
33
|
+
status: number;
|
|
34
|
+
headers?: Record<string, string>;
|
|
35
|
+
body_json?: JsonValue;
|
|
36
|
+
body_text?: string;
|
|
37
|
+
body_truncated?: boolean;
|
|
38
|
+
};
|
|
39
|
+
stream?: {
|
|
40
|
+
sse_events?: JsonValue[];
|
|
41
|
+
sse_events_truncated?: boolean;
|
|
42
|
+
output_text?: string;
|
|
43
|
+
tool_calls?: JsonValue;
|
|
44
|
+
finish_reason?: string | null;
|
|
45
|
+
usage?: JsonValue;
|
|
46
|
+
};
|
|
47
|
+
usage?: JsonValue;
|
|
48
|
+
error?: {
|
|
49
|
+
message: string;
|
|
50
|
+
stack?: string;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
export type TelemetryBatchPayload = {
|
|
54
|
+
logs: TelemetryLog[];
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../../src/types/telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAElB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IAEb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAElB,MAAM,EAAE;QACN,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IAEF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACrC,KAAK,CAAC,EAAE,cAAc,CAAC;IAEvB,OAAO,EAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,SAAS,CAAC,EAAE,SAAS,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,cAAc,CAAC,EAAE,OAAO,CAAC;KAC1B,CAAC;IAEF,QAAQ,CAAC,EAAE;QACT,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,SAAS,CAAC,EAAE,SAAS,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,cAAc,CAAC,EAAE,OAAO,CAAC;KAC1B,CAAC;IAEF,MAAM,CAAC,EAAE;QACP,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC;QACzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;QAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,SAAS,CAAC;QACvB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,KAAK,CAAC,EAAE,SAAS,CAAC;KACnB,CAAC;IAEF,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB,KAAK,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,YAAY,EAAE,CAAC;CACtB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "wiretap-llm",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Telemetry client for sending LLM logs to Wiretap",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "bun build ./src/index.ts --outdir ./dist --target node && tsc --emitDeclarationOnly",
|
|
21
|
+
"dev": "bun build ./src/index.ts --outdir ./dist --target node --watch",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"prepublishOnly": "bun run build"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"llm",
|
|
27
|
+
"telemetry",
|
|
28
|
+
"openrouter",
|
|
29
|
+
"openai",
|
|
30
|
+
"observability",
|
|
31
|
+
"monitoring",
|
|
32
|
+
"ai",
|
|
33
|
+
"wiretap"
|
|
34
|
+
],
|
|
35
|
+
"author": "Saint",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/kingbootoshi/wiretap.git",
|
|
40
|
+
"directory": "packages/sdk"
|
|
41
|
+
},
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/kingbootoshi/wiretap/issues"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/kingbootoshi/wiretap/tree/main/packages/sdk#readme",
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=18"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"typescript": "^5.7.2"
|
|
51
|
+
}
|
|
52
|
+
}
|