ironside 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/LICENSE.md +58 -0
- package/README.md +91 -0
- package/dist/src/batcher.d.ts +51 -0
- package/dist/src/batcher.js +90 -0
- package/dist/src/batcher.js.map +1 -0
- package/dist/src/client.d.ts +70 -0
- package/dist/src/client.js +171 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/index.d.ts +9 -0
- package/dist/src/index.js +5 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/types.d.ts +64 -0
- package/dist/src/types.js +6 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/wrappers/anthropic.d.ts +22 -0
- package/dist/src/wrappers/anthropic.js +188 -0
- package/dist/src/wrappers/anthropic.js.map +1 -0
- package/dist/src/wrappers/openai.d.ts +26 -0
- package/dist/src/wrappers/openai.js +162 -0
- package/dist/src/wrappers/openai.js.map +1 -0
- package/dist/src/wrappers/streaming.d.ts +17 -0
- package/dist/src/wrappers/streaming.js +86 -0
- package/dist/src/wrappers/streaming.js.map +1 -0
- package/dist/src/wrappers/vercel-ai.d.ts +29 -0
- package/dist/src/wrappers/vercel-ai.js +30 -0
- package/dist/src/wrappers/vercel-ai.js.map +1 -0
- package/package.json +55 -0
- package/src/batcher.ts +109 -0
- package/src/client.ts +267 -0
- package/src/index.ts +24 -0
- package/src/types.ts +75 -0
- package/src/wrappers/anthropic.ts +276 -0
- package/src/wrappers/openai.ts +283 -0
- package/src/wrappers/streaming.ts +92 -0
- package/src/wrappers/vercel-ai.ts +73 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Ironside Sustainable Use License v1.0
|
|
2
|
+
|
|
3
|
+
## Acceptance
|
|
4
|
+
|
|
5
|
+
By using the software, you agree to all of the terms and conditions below.
|
|
6
|
+
|
|
7
|
+
## Copyright License
|
|
8
|
+
|
|
9
|
+
The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations below.
|
|
10
|
+
|
|
11
|
+
## Limitations
|
|
12
|
+
|
|
13
|
+
**Use.** You may use, modify, and self-host the software — including for your own commercial internal business purposes — subject to the limitations below.
|
|
14
|
+
|
|
15
|
+
**Competing Use.** You may not use the software to create a product or service that competes with the software or any product or service offered by the licensor. You may not offer the software to third parties on a hosted or managed basis (i.e. running it as a service on your infrastructure for other organizations to use), or embed the software into a product or service you provide to third parties, without a separate commercial agreement with the licensor. Self-hosting the software for your own organization's own use is always permitted and is not a competing use.
|
|
16
|
+
|
|
17
|
+
**SDK Integration Exception.** Notwithstanding the Competing Use and Distribution limitations, you may use, copy, modify, embed, and distribute the `ironside` client package as part of a product or service you provide to third parties, including for commercial purposes, solely to instrument that product or service and send telemetry to an Ironside deployment. This exception does not permit you to offer Ironside itself as a hosted or managed service for third parties, distribute the SDK as a standalone paid product, or use the SDK to create a product or service that competes with Ironside.
|
|
18
|
+
|
|
19
|
+
**Distribution.** You may distribute the software or provide it to others only if you do so free of charge for non-commercial purposes, or with a separate commercial agreement with the licensor.
|
|
20
|
+
|
|
21
|
+
**Attribution.** You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor's trademarks is subject to applicable law.
|
|
22
|
+
|
|
23
|
+
## Patent License
|
|
24
|
+
|
|
25
|
+
The licensor grants you a license, under any patent claims the licensor can license or becomes able to license, to make, have made, use, sell, offer for sale, import, and have imported the software, in each case subject to the limitations and conditions in this license. This patent license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to the infringement of any patent, your patent license for the software granted under these terms ends immediately.
|
|
26
|
+
|
|
27
|
+
## Distribution Requirements
|
|
28
|
+
|
|
29
|
+
If you distribute copies or modifications of the software, you must:
|
|
30
|
+
|
|
31
|
+
1. Give each recipient a copy of this license.
|
|
32
|
+
2. Include a prominent notice in any modified version stating that you have modified the software.
|
|
33
|
+
|
|
34
|
+
## Fair Use
|
|
35
|
+
|
|
36
|
+
This license is not intended to limit any rights you have under applicable copyright doctrines of fair use, fair dealing, or other equivalents.
|
|
37
|
+
|
|
38
|
+
## Termination
|
|
39
|
+
|
|
40
|
+
If you use the software in violation of this license, such use is not licensed, and your license will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your license will be reinstated. If you violate these license terms after such reinstatement, any further violation of these terms will cause your license to terminate automatically and permanently.
|
|
41
|
+
|
|
42
|
+
## No Liability
|
|
43
|
+
|
|
44
|
+
As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.
|
|
45
|
+
|
|
46
|
+
## Definitions
|
|
47
|
+
|
|
48
|
+
The **licensor** is the entity offering these terms — Luka Živković.
|
|
49
|
+
|
|
50
|
+
The **software** is the software the licensor makes available under these terms, including any portion of it.
|
|
51
|
+
|
|
52
|
+
**You** refers to the individual or entity agreeing to these terms.
|
|
53
|
+
|
|
54
|
+
**Your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. Control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
Copyright 2026 Luka Živković. All rights reserved.
|
package/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# `ironside`
|
|
2
|
+
|
|
3
|
+
The official Node.js/TypeScript client for sending LLM traces directly to Ironside. It provides automatic OpenAI and Anthropic instrumentation, manual trace/span/generation handles, media uploads, and score recording.
|
|
4
|
+
|
|
5
|
+
Requires Node.js 20 or newer. The package is ESM-only.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
Install the SDK together with whichever provider client your application uses:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install ironside openai
|
|
13
|
+
# or: npm install ironside @anthropic-ai/sdk
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Provider packages are not runtime dependencies of `ironside`; the wrappers accept the client instance already used by your application.
|
|
17
|
+
|
|
18
|
+
## Provider wrappers
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import OpenAI from "openai";
|
|
22
|
+
import { init, wrapOpenAI } from "ironside";
|
|
23
|
+
|
|
24
|
+
const ironside = init({
|
|
25
|
+
apiKey: process.env.IRONSIDE_API_KEY!,
|
|
26
|
+
host: process.env.IRONSIDE_HOST ?? "http://localhost:8788",
|
|
27
|
+
onError(error) {
|
|
28
|
+
console.error("Ironside ingest failed", error);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const openai = wrapOpenAI(
|
|
33
|
+
new OpenAI({ apiKey: process.env.OPENAI_API_KEY }),
|
|
34
|
+
ironside
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
await openai.chat.completions.create({
|
|
38
|
+
model: "gpt-4o",
|
|
39
|
+
messages: [{ role: "user", content: "Hello" }]
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
await ironside.shutdown();
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`wrapAnthropic(client, ironside)` instruments `messages.create()` in the same way. Both wrappers mutate and return the same provider client, preserve streaming behavior, and record input/output, model, token usage, and common sampling parameters. For OpenAI streaming token usage, request `stream_options: { include_usage: true }`.
|
|
46
|
+
|
|
47
|
+
## Manual instrumentation
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { init } from "ironside";
|
|
51
|
+
|
|
52
|
+
const ironside = init({
|
|
53
|
+
apiKey: process.env.IRONSIDE_API_KEY!,
|
|
54
|
+
host: "https://ironside.example.com"
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const trace = ironside.trace({
|
|
58
|
+
name: "answer-question",
|
|
59
|
+
userId: "user-123",
|
|
60
|
+
input: { question: "Why is the sky blue?" }
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const generation = trace.generation({
|
|
64
|
+
name: "generate-answer",
|
|
65
|
+
model: "example-model",
|
|
66
|
+
input: { prompt: "Why is the sky blue?" }
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
generation.end({
|
|
70
|
+
output: { answer: "Rayleigh scattering." },
|
|
71
|
+
usageDetails: { input_tokens: 8, output_tokens: 4 },
|
|
72
|
+
costDetails: { total_usd: 0.00012 }
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
trace.score({ name: "correctness", value: 1, source: "eval" });
|
|
76
|
+
trace.update({ output: { answer: "Rayleigh scattering." } });
|
|
77
|
+
|
|
78
|
+
await ironside.shutdown();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Instrumentation calls buffer events and do not block application requests. Call `flush()` at a lifecycle boundary when needed, and always call `shutdown()` during graceful process termination so buffered and in-flight events finish sending. Failed background batches are reported through `onError`; they are not thrown into the instrumented request path.
|
|
82
|
+
|
|
83
|
+
`recordGenerateTextResult()` is available for results returned by the Vercel AI SDK. `uploadMedia()` stores binary content separately and returns an `ironside://media/...` reference suitable for trace input or output.
|
|
84
|
+
|
|
85
|
+
## Choosing an integration
|
|
86
|
+
|
|
87
|
+
This package is the ergonomic Node.js integration and supports Ironside-specific cost and score fields. Third-party frameworks and non-Node runtimes should prefer Ironside's canonical OTLP/HTTP endpoint with OpenTelemetry `gen_ai.*` attributes. Low-level integrations can send the native JSON envelope directly at `POST /api/v1/ingest`.
|
|
88
|
+
|
|
89
|
+
## License
|
|
90
|
+
|
|
91
|
+
[Ironside Sustainable Use License v1.0](./LICENSE.md), including its SDK Integration Exception for embedding and distributing this package as part of commercial applications that send telemetry to Ironside.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { IngestRequestEvent } from "./types.js";
|
|
2
|
+
export interface BatcherOptions {
|
|
3
|
+
apiKey: string;
|
|
4
|
+
host: string;
|
|
5
|
+
/** Flush automatically once this many events are buffered. */
|
|
6
|
+
maxBatchSize?: number;
|
|
7
|
+
/** Flush automatically after this many ms, even if under maxBatchSize. */
|
|
8
|
+
flushIntervalMs?: number;
|
|
9
|
+
/** Injectable for tests; defaults to global fetch. */
|
|
10
|
+
fetchImpl?: typeof fetch;
|
|
11
|
+
/** Called with a failed batch's events + the error; default: console.error. Never throws back into the caller's hot path. */
|
|
12
|
+
onError?: (error: unknown, events: IngestRequestEvent[]) => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Buffers ingest events in memory and flushes them to POST /api/v1/ingest
|
|
16
|
+
* in the background — instrumentation calls (trace/span/generation) never
|
|
17
|
+
* block on network I/O. Flushes are fire-and-forget from the caller's
|
|
18
|
+
* perspective; failures are reported via onError, not thrown, since a
|
|
19
|
+
* trace SDK must never be the reason an application request fails.
|
|
20
|
+
*/
|
|
21
|
+
export declare class EventBatcher {
|
|
22
|
+
private readonly apiKey;
|
|
23
|
+
private readonly host;
|
|
24
|
+
private readonly maxBatchSize;
|
|
25
|
+
private readonly flushIntervalMs;
|
|
26
|
+
private readonly fetchImpl;
|
|
27
|
+
private readonly onError;
|
|
28
|
+
private buffer;
|
|
29
|
+
private timer;
|
|
30
|
+
private inFlight;
|
|
31
|
+
private closed;
|
|
32
|
+
constructor(options: BatcherOptions);
|
|
33
|
+
enqueue(event: IngestRequestEvent): void;
|
|
34
|
+
/** Sends whatever is currently buffered. Safe to call concurrently — flushes serialize via inFlight. */
|
|
35
|
+
flush(): Promise<void>;
|
|
36
|
+
private send;
|
|
37
|
+
/**
|
|
38
|
+
* Stops the background timer and flushes any remaining buffered events.
|
|
39
|
+
* Call on process shutdown.
|
|
40
|
+
*
|
|
41
|
+
* Must wait on `inFlight` explicitly, not just call `flush()` — if a
|
|
42
|
+
* different caller (the interval timer, or an enqueue() that just hit
|
|
43
|
+
* maxBatchSize) already claimed the buffer into its own in-progress
|
|
44
|
+
* send() moments earlier, flush() here sees an empty buffer and returns
|
|
45
|
+
* immediately without waiting for that still-pending request. Without
|
|
46
|
+
* this, shutdown() could resolve while a real network request is still
|
|
47
|
+
* in flight, and an immediately-following process.exit() would silently
|
|
48
|
+
* drop that batch.
|
|
49
|
+
*/
|
|
50
|
+
close(): Promise<void>;
|
|
51
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const DEFAULT_MAX_BATCH_SIZE = 50;
|
|
2
|
+
const DEFAULT_FLUSH_INTERVAL_MS = 5000;
|
|
3
|
+
/**
|
|
4
|
+
* Buffers ingest events in memory and flushes them to POST /api/v1/ingest
|
|
5
|
+
* in the background — instrumentation calls (trace/span/generation) never
|
|
6
|
+
* block on network I/O. Flushes are fire-and-forget from the caller's
|
|
7
|
+
* perspective; failures are reported via onError, not thrown, since a
|
|
8
|
+
* trace SDK must never be the reason an application request fails.
|
|
9
|
+
*/
|
|
10
|
+
export class EventBatcher {
|
|
11
|
+
apiKey;
|
|
12
|
+
host;
|
|
13
|
+
maxBatchSize;
|
|
14
|
+
flushIntervalMs;
|
|
15
|
+
fetchImpl;
|
|
16
|
+
onError;
|
|
17
|
+
buffer = [];
|
|
18
|
+
timer = null;
|
|
19
|
+
inFlight = Promise.resolve();
|
|
20
|
+
closed = false;
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.apiKey = options.apiKey;
|
|
23
|
+
this.host = options.host.replace(/\/$/, "");
|
|
24
|
+
this.maxBatchSize = options.maxBatchSize ?? DEFAULT_MAX_BATCH_SIZE;
|
|
25
|
+
this.flushIntervalMs = options.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;
|
|
26
|
+
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
27
|
+
this.onError =
|
|
28
|
+
options.onError ??
|
|
29
|
+
((error) => console.error("[ironside] failed to send trace events:", error));
|
|
30
|
+
this.timer = setInterval(() => void this.flush(), this.flushIntervalMs);
|
|
31
|
+
// Don't let the flush timer keep the process alive on its own.
|
|
32
|
+
this.timer.unref?.();
|
|
33
|
+
}
|
|
34
|
+
enqueue(event) {
|
|
35
|
+
if (this.closed)
|
|
36
|
+
return;
|
|
37
|
+
this.buffer.push(event);
|
|
38
|
+
if (this.buffer.length >= this.maxBatchSize) {
|
|
39
|
+
void this.flush();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Sends whatever is currently buffered. Safe to call concurrently — flushes serialize via inFlight. */
|
|
43
|
+
async flush() {
|
|
44
|
+
if (this.buffer.length === 0)
|
|
45
|
+
return;
|
|
46
|
+
const events = this.buffer;
|
|
47
|
+
this.buffer = [];
|
|
48
|
+
this.inFlight = this.inFlight.then(() => this.send(events));
|
|
49
|
+
await this.inFlight;
|
|
50
|
+
}
|
|
51
|
+
async send(events) {
|
|
52
|
+
try {
|
|
53
|
+
const res = await this.fetchImpl(`${this.host}/api/v1/ingest`, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers: {
|
|
56
|
+
"content-type": "application/json",
|
|
57
|
+
authorization: `Bearer ${this.apiKey}`
|
|
58
|
+
},
|
|
59
|
+
body: JSON.stringify({ events })
|
|
60
|
+
});
|
|
61
|
+
if (!res.ok) {
|
|
62
|
+
this.onError(new Error(`ingest request failed: HTTP ${res.status}`), events);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
this.onError(error, events);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Stops the background timer and flushes any remaining buffered events.
|
|
71
|
+
* Call on process shutdown.
|
|
72
|
+
*
|
|
73
|
+
* Must wait on `inFlight` explicitly, not just call `flush()` — if a
|
|
74
|
+
* different caller (the interval timer, or an enqueue() that just hit
|
|
75
|
+
* maxBatchSize) already claimed the buffer into its own in-progress
|
|
76
|
+
* send() moments earlier, flush() here sees an empty buffer and returns
|
|
77
|
+
* immediately without waiting for that still-pending request. Without
|
|
78
|
+
* this, shutdown() could resolve while a real network request is still
|
|
79
|
+
* in flight, and an immediately-following process.exit() would silently
|
|
80
|
+
* drop that batch.
|
|
81
|
+
*/
|
|
82
|
+
async close() {
|
|
83
|
+
this.closed = true;
|
|
84
|
+
if (this.timer)
|
|
85
|
+
clearInterval(this.timer);
|
|
86
|
+
await this.flush();
|
|
87
|
+
await this.inFlight;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=batcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batcher.js","sourceRoot":"","sources":["../../src/batcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type BatcherOptions } from "./batcher.js";
|
|
2
|
+
import type { EndObservationOptions, ScoreOptions, StartGenerationOptions, StartSpanOptions, StartTraceOptions, UpdateTraceOptions } from "./types.js";
|
|
3
|
+
export interface IronsideClientOptions {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
/** Ironside API host, e.g. "https://ironside.example.com" or "http://localhost:8788". */
|
|
6
|
+
host: string;
|
|
7
|
+
maxBatchSize?: number;
|
|
8
|
+
flushIntervalMs?: number;
|
|
9
|
+
fetchImpl?: BatcherOptions["fetchImpl"];
|
|
10
|
+
onError?: BatcherOptions["onError"];
|
|
11
|
+
}
|
|
12
|
+
export interface ObservationHandle {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
/** Starts a child span nested under this observation. */
|
|
15
|
+
span(options?: StartSpanOptions): ObservationHandle;
|
|
16
|
+
/** Starts a child generation nested under this observation. */
|
|
17
|
+
generation(options?: StartGenerationOptions): ObservationHandle;
|
|
18
|
+
/** Marks this observation complete. Safe to call at most once meaningfully; a second call overwrites endTime. */
|
|
19
|
+
end(options?: EndObservationOptions): void;
|
|
20
|
+
/** Records a score (user feedback, eval result, ...) attached to this observation. */
|
|
21
|
+
score(options: ScoreOptions): void;
|
|
22
|
+
}
|
|
23
|
+
export interface TraceHandle {
|
|
24
|
+
readonly id: string;
|
|
25
|
+
span(options?: StartSpanOptions): ObservationHandle;
|
|
26
|
+
generation(options?: StartGenerationOptions): ObservationHandle;
|
|
27
|
+
update(options: UpdateTraceOptions): void;
|
|
28
|
+
/** Records a score (user feedback, eval result, ...) attached to this trace. */
|
|
29
|
+
score(options: ScoreOptions): void;
|
|
30
|
+
}
|
|
31
|
+
export interface UploadMediaOptions {
|
|
32
|
+
/** The raw bytes to store. */
|
|
33
|
+
data: Uint8Array | ArrayBuffer;
|
|
34
|
+
/** Real content type of the bytes, e.g. "image/png". */
|
|
35
|
+
contentType: string;
|
|
36
|
+
}
|
|
37
|
+
export interface UploadedMedia {
|
|
38
|
+
id: string;
|
|
39
|
+
/** Compact ref string ("ironside://media/<id>") to embed in trace input/output/metadata. */
|
|
40
|
+
ref: string;
|
|
41
|
+
contentType: string;
|
|
42
|
+
sizeBytes: number;
|
|
43
|
+
sha256: string;
|
|
44
|
+
}
|
|
45
|
+
export interface IronsideClient {
|
|
46
|
+
trace(options?: StartTraceOptions): TraceHandle;
|
|
47
|
+
/**
|
|
48
|
+
* Uploads a media blob (image, audio, document, ...) and returns a
|
|
49
|
+
* compact ref string to embed in trace input/output instead of the
|
|
50
|
+
* bytes themselves — base64 payloads inside trace JSON bloat the
|
|
51
|
+
* columnar store. Content-addressed: uploading identical bytes twice
|
|
52
|
+
* returns the same asset. Unlike instrumentation calls this awaits the
|
|
53
|
+
* network (the ref doesn't exist until the server has the bytes).
|
|
54
|
+
*/
|
|
55
|
+
uploadMedia(options: UploadMediaOptions): Promise<UploadedMedia>;
|
|
56
|
+
/** Sends buffered events immediately instead of waiting for the next automatic flush. */
|
|
57
|
+
flush(): Promise<void>;
|
|
58
|
+
/** Stops background flushing and sends any remaining buffered events. Call before process exit. */
|
|
59
|
+
shutdown(): Promise<void>;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Creates an Ironside client. Instrumentation calls (trace/span/generation)
|
|
63
|
+
* never block on network I/O — events are buffered and flushed in the
|
|
64
|
+
* background. Deliberately does NOT auto-register a process-exit handler:
|
|
65
|
+
* doing that inside a library is a footgun (can't be un-registered,
|
|
66
|
+
* surprising under multiple init() calls or in serverless runtimes with
|
|
67
|
+
* their own lifecycle hooks). Call `shutdown()` explicitly wherever your
|
|
68
|
+
* app already handles graceful shutdown.
|
|
69
|
+
*/
|
|
70
|
+
export declare function init(options: IronsideClientOptions): IronsideClient;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { ulid } from "ulid";
|
|
2
|
+
import { EventBatcher } from "./batcher.js";
|
|
3
|
+
/**
|
|
4
|
+
* Creates an Ironside client. Instrumentation calls (trace/span/generation)
|
|
5
|
+
* never block on network I/O — events are buffered and flushed in the
|
|
6
|
+
* background. Deliberately does NOT auto-register a process-exit handler:
|
|
7
|
+
* doing that inside a library is a footgun (can't be un-registered,
|
|
8
|
+
* surprising under multiple init() calls or in serverless runtimes with
|
|
9
|
+
* their own lifecycle hooks). Call `shutdown()` explicitly wherever your
|
|
10
|
+
* app already handles graceful shutdown.
|
|
11
|
+
*/
|
|
12
|
+
export function init(options) {
|
|
13
|
+
const batcher = new EventBatcher({
|
|
14
|
+
apiKey: options.apiKey,
|
|
15
|
+
host: options.host,
|
|
16
|
+
...(options.maxBatchSize !== undefined && { maxBatchSize: options.maxBatchSize }),
|
|
17
|
+
...(options.flushIntervalMs !== undefined && { flushIntervalMs: options.flushIntervalMs }),
|
|
18
|
+
...(options.fetchImpl !== undefined && { fetchImpl: options.fetchImpl }),
|
|
19
|
+
...(options.onError !== undefined && { onError: options.onError })
|
|
20
|
+
});
|
|
21
|
+
function enqueueScore(traceId, observationId, scoreOptions) {
|
|
22
|
+
batcher.enqueue({
|
|
23
|
+
type: "score-upsert",
|
|
24
|
+
body: {
|
|
25
|
+
id: scoreOptions.id ?? ulid(),
|
|
26
|
+
traceId,
|
|
27
|
+
...(observationId && { observationId }),
|
|
28
|
+
name: scoreOptions.name,
|
|
29
|
+
dataType: scoreOptions.value !== undefined ? "numeric" : "categorical",
|
|
30
|
+
source: scoreOptions.source ?? "api",
|
|
31
|
+
...(scoreOptions.value !== undefined && { value: scoreOptions.value }),
|
|
32
|
+
...(scoreOptions.stringValue !== undefined && { stringValue: scoreOptions.stringValue }),
|
|
33
|
+
...(scoreOptions.comment && { comment: scoreOptions.comment }),
|
|
34
|
+
timestamp: new Date().toISOString(),
|
|
35
|
+
metadata: scoreOptions.metadata ?? {}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function makeObservationHandle(id, traceId, type, parentObservationId, startOptions) {
|
|
40
|
+
const startTime = new Date().toISOString();
|
|
41
|
+
const model = "model" in startOptions ? startOptions.model : undefined;
|
|
42
|
+
const modelParameters = "modelParameters" in startOptions ? startOptions.modelParameters : undefined;
|
|
43
|
+
batcher.enqueue({
|
|
44
|
+
type: "observation-upsert",
|
|
45
|
+
body: {
|
|
46
|
+
id,
|
|
47
|
+
traceId,
|
|
48
|
+
...(parentObservationId && { parentObservationId }),
|
|
49
|
+
type,
|
|
50
|
+
...(startOptions.name && { name: startOptions.name }),
|
|
51
|
+
startTime,
|
|
52
|
+
...(model && { model }),
|
|
53
|
+
...(modelParameters && { modelParameters }),
|
|
54
|
+
...(startOptions.input !== undefined && { input: startOptions.input }),
|
|
55
|
+
metadata: startOptions.metadata ?? {}
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
function child(childType) {
|
|
59
|
+
return (options = {}) => makeObservationHandle(ulid(), traceId, childType, id, options);
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
id,
|
|
63
|
+
span: child("span"),
|
|
64
|
+
generation: child("generation"),
|
|
65
|
+
end(endOptions = {}) {
|
|
66
|
+
batcher.enqueue({
|
|
67
|
+
type: "observation-upsert",
|
|
68
|
+
body: {
|
|
69
|
+
id,
|
|
70
|
+
traceId,
|
|
71
|
+
...(parentObservationId && { parentObservationId }),
|
|
72
|
+
type,
|
|
73
|
+
...(startOptions.name && { name: startOptions.name }),
|
|
74
|
+
startTime,
|
|
75
|
+
endTime: new Date().toISOString(),
|
|
76
|
+
level: endOptions.level ?? "default",
|
|
77
|
+
...(model && { model }),
|
|
78
|
+
...(modelParameters && { modelParameters }),
|
|
79
|
+
...(startOptions.input !== undefined && { input: startOptions.input }),
|
|
80
|
+
...(endOptions.output !== undefined && { output: endOptions.output }),
|
|
81
|
+
...(endOptions.statusMessage && { statusMessage: endOptions.statusMessage }),
|
|
82
|
+
...(endOptions.usageDetails && { usageDetails: endOptions.usageDetails }),
|
|
83
|
+
...(endOptions.costDetails && { costDetails: endOptions.costDetails }),
|
|
84
|
+
metadata: { ...startOptions.metadata, ...endOptions.metadata }
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
score: (scoreOptions) => enqueueScore(traceId, id, scoreOptions)
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
92
|
+
const host = options.host.replace(/\/$/, "");
|
|
93
|
+
return {
|
|
94
|
+
async uploadMedia(uploadOptions) {
|
|
95
|
+
const body = uploadOptions.data instanceof ArrayBuffer
|
|
96
|
+
? new Uint8Array(uploadOptions.data)
|
|
97
|
+
: uploadOptions.data;
|
|
98
|
+
const res = await fetchImpl(`${host}/api/v1/media`, {
|
|
99
|
+
method: "POST",
|
|
100
|
+
headers: {
|
|
101
|
+
authorization: `Bearer ${options.apiKey}`,
|
|
102
|
+
"content-type": uploadOptions.contentType
|
|
103
|
+
},
|
|
104
|
+
// DOM's BodyInit type isn't in the SDK's lib set; Uint8Array is a
|
|
105
|
+
// valid fetch body in Node 18+ and browsers alike.
|
|
106
|
+
body: body
|
|
107
|
+
});
|
|
108
|
+
if (!res.ok) {
|
|
109
|
+
const text = await res.text().catch(() => "");
|
|
110
|
+
throw new Error(`media upload failed: ${res.status}${text ? ` ${text}` : ""}`);
|
|
111
|
+
}
|
|
112
|
+
return (await res.json());
|
|
113
|
+
},
|
|
114
|
+
trace(startOptions = {}) {
|
|
115
|
+
const id = startOptions.id ?? ulid();
|
|
116
|
+
// Fixed at trace-start time and reused by update() below — the trace's
|
|
117
|
+
// timestamp must not drift to "whenever update() happened to be
|
|
118
|
+
// called" (e.g. re-stamping it at completion time would corrupt the
|
|
119
|
+
// recorded start time on every partial update).
|
|
120
|
+
const timestamp = new Date().toISOString();
|
|
121
|
+
batcher.enqueue({
|
|
122
|
+
type: "trace-upsert",
|
|
123
|
+
body: {
|
|
124
|
+
id,
|
|
125
|
+
timestamp,
|
|
126
|
+
...(startOptions.name && { name: startOptions.name }),
|
|
127
|
+
...(startOptions.userId && { userId: startOptions.userId }),
|
|
128
|
+
...(startOptions.sessionId && { sessionId: startOptions.sessionId }),
|
|
129
|
+
...(startOptions.environment && { environment: startOptions.environment }),
|
|
130
|
+
...(startOptions.release && { release: startOptions.release }),
|
|
131
|
+
...(startOptions.version && { version: startOptions.version }),
|
|
132
|
+
tags: startOptions.tags ?? [],
|
|
133
|
+
metadata: startOptions.metadata ?? {},
|
|
134
|
+
...(startOptions.input !== undefined && { input: startOptions.input })
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
return {
|
|
138
|
+
id,
|
|
139
|
+
span: (options = {}) => makeObservationHandle(ulid(), id, "span", undefined, options),
|
|
140
|
+
generation: (options = {}) => makeObservationHandle(ulid(), id, "generation", undefined, options),
|
|
141
|
+
update(updateOptions) {
|
|
142
|
+
// A trace-upsert replaces the whole row (ClickHouse
|
|
143
|
+
// ReplacingMergeTree has no field-level merge) — every field set
|
|
144
|
+
// by trace() must be carried forward here too, or update() would
|
|
145
|
+
// silently wipe name/userId/sessionId/input back to absent.
|
|
146
|
+
batcher.enqueue({
|
|
147
|
+
type: "trace-upsert",
|
|
148
|
+
body: {
|
|
149
|
+
id,
|
|
150
|
+
timestamp,
|
|
151
|
+
...(startOptions.name && { name: startOptions.name }),
|
|
152
|
+
...(startOptions.userId && { userId: startOptions.userId }),
|
|
153
|
+
...(startOptions.sessionId && { sessionId: startOptions.sessionId }),
|
|
154
|
+
...(startOptions.environment && { environment: startOptions.environment }),
|
|
155
|
+
...(startOptions.release && { release: startOptions.release }),
|
|
156
|
+
...(startOptions.version && { version: startOptions.version }),
|
|
157
|
+
tags: startOptions.tags ?? [],
|
|
158
|
+
...(startOptions.input !== undefined && { input: startOptions.input }),
|
|
159
|
+
...(updateOptions.output !== undefined && { output: updateOptions.output }),
|
|
160
|
+
metadata: { ...startOptions.metadata, ...updateOptions.metadata }
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
},
|
|
164
|
+
score: (scoreOptions) => enqueueScore(id, undefined, scoreOptions)
|
|
165
|
+
};
|
|
166
|
+
},
|
|
167
|
+
flush: () => batcher.flush(),
|
|
168
|
+
shutdown: () => batcher.close()
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { init } from "./client.js";
|
|
2
|
+
export type { IronsideClient, IronsideClientOptions, TraceHandle, ObservationHandle, UploadMediaOptions, UploadedMedia } from "./client.js";
|
|
3
|
+
export type { StartTraceOptions, UpdateTraceOptions, StartSpanOptions, StartGenerationOptions, EndObservationOptions, ScoreOptions } from "./types.js";
|
|
4
|
+
export { wrapOpenAI } from "./wrappers/openai.js";
|
|
5
|
+
export type { WrapOpenAIOptions } from "./wrappers/openai.js";
|
|
6
|
+
export { wrapAnthropic } from "./wrappers/anthropic.js";
|
|
7
|
+
export type { WrapAnthropicOptions } from "./wrappers/anthropic.js";
|
|
8
|
+
export { recordGenerateTextResult } from "./wrappers/vercel-ai.js";
|
|
9
|
+
export type { RecordGenerateTextOptions } from "./wrappers/vercel-ai.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAkBnC,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAExD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export interface StartTraceOptions {
|
|
2
|
+
id?: string;
|
|
3
|
+
name?: string;
|
|
4
|
+
userId?: string;
|
|
5
|
+
sessionId?: string;
|
|
6
|
+
environment?: string;
|
|
7
|
+
release?: string;
|
|
8
|
+
version?: string;
|
|
9
|
+
tags?: string[];
|
|
10
|
+
metadata?: Record<string, string>;
|
|
11
|
+
input?: unknown;
|
|
12
|
+
}
|
|
13
|
+
export interface UpdateTraceOptions {
|
|
14
|
+
output?: unknown;
|
|
15
|
+
metadata?: Record<string, string>;
|
|
16
|
+
}
|
|
17
|
+
interface ScoreOptionsBase {
|
|
18
|
+
id?: string;
|
|
19
|
+
/** Attaches the score to a specific observation instead of the trace as a whole. */
|
|
20
|
+
observationId?: string;
|
|
21
|
+
name: string;
|
|
22
|
+
source?: "api" | "eval" | "annotation";
|
|
23
|
+
comment?: string;
|
|
24
|
+
metadata?: Record<string, string>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Exactly one of value/stringValue — enforced at the type level (not just
|
|
28
|
+
* documented) so a caller can't produce a score with neither (dropped
|
|
29
|
+
* server-side against the domain schema's invariant, silently, since the
|
|
30
|
+
* SDK's ingest is fire-and-forget) or both (an internally inconsistent
|
|
31
|
+
* dataType/payload pairing).
|
|
32
|
+
*/
|
|
33
|
+
export type ScoreOptions = (ScoreOptionsBase & {
|
|
34
|
+
value: number;
|
|
35
|
+
stringValue?: undefined;
|
|
36
|
+
}) | (ScoreOptionsBase & {
|
|
37
|
+
stringValue: string;
|
|
38
|
+
value?: undefined;
|
|
39
|
+
});
|
|
40
|
+
export interface StartSpanOptions {
|
|
41
|
+
id?: string;
|
|
42
|
+
name?: string;
|
|
43
|
+
input?: unknown;
|
|
44
|
+
metadata?: Record<string, string>;
|
|
45
|
+
}
|
|
46
|
+
export interface StartGenerationOptions extends StartSpanOptions {
|
|
47
|
+
model?: string;
|
|
48
|
+
modelParameters?: Record<string, string | number | boolean | null>;
|
|
49
|
+
}
|
|
50
|
+
export interface EndObservationOptions {
|
|
51
|
+
output?: unknown;
|
|
52
|
+
statusMessage?: string;
|
|
53
|
+
level?: "debug" | "default" | "warning" | "error";
|
|
54
|
+
usageDetails?: Record<string, number>;
|
|
55
|
+
costDetails?: Record<string, number>;
|
|
56
|
+
metadata?: Record<string, string>;
|
|
57
|
+
}
|
|
58
|
+
export type IngestEventType = "trace-upsert" | "observation-upsert" | "score-upsert";
|
|
59
|
+
export interface IngestRequestEvent {
|
|
60
|
+
id?: string;
|
|
61
|
+
type: IngestEventType;
|
|
62
|
+
body: unknown;
|
|
63
|
+
}
|
|
64
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Wire-contract types, deliberately duplicated from (not imported from)
|
|
2
|
+
// @ironside/shared: this package ships standalone to npm and cannot depend
|
|
3
|
+
// on a private workspace package. Kept intentionally minimal — only the
|
|
4
|
+
// fields the SDK itself constructs.
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,2EAA2E;AAC3E,wEAAwE;AACxE,oCAAoC"}
|