@langinsight/ai-sdk 0.0.1 → 0.0.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @langinsight/ai-sdk
2
2
 
3
- LangInsight callback handler for Vercel AI SDK.
3
+ LangInsight callback handler for Vercel AI SDK. Sends input/output traces to LangInsight in parallel and supports feedback (thumbs up/down) via `score()`.
4
4
 
5
5
  ## Usage
6
6
 
@@ -26,8 +26,8 @@ const result = await generateText({
26
26
  prompt,
27
27
  });
28
28
 
29
- // Report the result to LangInsight
30
- await handler.report(result, { input: prompt });
29
+ // Report the result to LangInsight (returns output trace id or undefined)
30
+ const traceId = await handler.report(result, { input: prompt });
31
31
  ```
32
32
 
33
33
  ### streamText
@@ -43,6 +43,8 @@ const handler = new LangInsight.CallbackHandler({
43
43
  apiKey: LANGINSIGHT_API_KEY,
44
44
  endpoint: LANGINSIGHT_ENDPOINT,
45
45
  metadata: { userId: "admin", sessionId: "admin" },
46
+ onSuccess: (trace) => console.log("Trace sent:", trace.id),
47
+ onFailure: (err) => console.error("Trace failed:", err),
46
48
  });
47
49
 
48
50
  const prompt = "Hello!";
@@ -50,7 +52,6 @@ const prompt = "Hello!";
50
52
  const result = streamText({
51
53
  model: openai("gpt-4o"),
52
54
  prompt,
53
- // Specify callback handler as onFinish
54
55
  onFinish: handler.onFinish({ input: prompt }),
55
56
  });
56
57
 
@@ -59,11 +60,36 @@ for await (const chunk of result.textStream) {
59
60
  }
60
61
  ```
61
62
 
63
+ ### Feedback (score)
64
+
65
+ After sending traces, you can submit feedback for the last output trace using `score()` or the trace id from `onSuccess` / `report()`.
66
+
67
+ ```typescript
68
+ // Using lastTraceId (set after report() or onFinish)
69
+ await handler.score({ traceId: handler.lastTraceId, value: 1 }); // 👍
70
+ await handler.score({ traceId: handler.lastTraceId, value: -1 }); // 👎
71
+
72
+ // Or using the trace id from report() / onSuccess
73
+ await handler.score({ traceId, value: 1 });
74
+ ```
75
+
62
76
  ## Options
63
77
 
64
- - `apiKey`: LangInsight API key (required)
65
- - `endpoint`: LangInsight API endpoint (required)
66
- - `metadata`: Metadata to attach to trace information (required)
67
- - `userId`: User ID
68
- - `sessionId`: Session ID
69
- - Any other key-value pairs
78
+ | Option | Type | Required | Description |
79
+ | ----------- | --------------------------------- | -------- | --------------------------------------------------------------------------- |
80
+ | `apiKey` | `string` | Yes | LangInsight API key |
81
+ | `endpoint` | `string` | Yes | LangInsight API endpoint (e.g. `https://api.langinsight.example.com`) |
82
+ | `metadata` | `object` | Yes | Metadata attached to traces |
83
+ | `metadata.userId` | `string` | Yes | User ID |
84
+ | `metadata.sessionId`| `string` | Yes | Session ID (e.g. conversation id) |
85
+ | `metadata.modelName` | `string` | No | Model name (defaults to result response when not set) |
86
+ | `metadata.*` | `any` | No | Additional key-value pairs |
87
+ | `onSuccess` | `(trace: Trace) => void` | No | Callback invoked with the output trace when trace submission succeeds |
88
+ | `onFailure` | `(error: Error) => void` | No | Callback invoked with the error when trace submission fails |
89
+
90
+ ## API
91
+
92
+ - **`report(result, { input })`** — Sends traces for a `generateText` result. Returns the output trace id, or `undefined` on failure.
93
+ - **`onFinish({ input })`** — Returns a function suitable for `streamText`’s `onFinish`. Sends traces when the stream finishes.
94
+ - **`score({ traceId, value })`** — Submits feedback (1 = thumbs up, -1 = thumbs down) for the given trace.
95
+ - **`lastTraceId`** — The id of the last output trace sent by this handler (set after `report()` or `onFinish()`).
package/dist/index.cjs CHANGED
@@ -323,6 +323,8 @@ var LangInsight;
323
323
  this.client = hc(options.endpoint, { fetch });
324
324
  }
325
325
  client;
326
+ /** 最後に送信した output trace の ID */
327
+ lastTraceId;
326
328
  /**
327
329
  * streamText の onFinish コールバックとして使用
328
330
  *
@@ -348,6 +350,8 @@ var LangInsight;
348
350
  /**
349
351
  * generateText の結果を送信
350
352
  *
353
+ * @returns output trace の traceId(送信失敗時は undefined)
354
+ *
351
355
  * @example
352
356
  * ```ts
353
357
  * const handler = new LangInsight.CallbackHandler(options);
@@ -357,61 +361,96 @@ var LangInsight;
357
361
  * prompt: "Hello!",
358
362
  * });
359
363
  *
360
- * await handler.report(result, { input: "Hello!" });
364
+ * const traceId = await handler.report(result, { input: "Hello!" });
361
365
  * ```
362
366
  */
363
367
  // biome-ignore lint/suspicious/noExplicitAny: should accept any output
364
368
  async report(result, params) {
365
- await this.sendTraces({
369
+ return await this.sendTraces({
366
370
  input: params.input,
367
371
  result
368
372
  });
369
373
  }
370
- async sendTraces(params) {
371
- const { input, result } = params;
372
- const { userId, sessionId, ...rest } = this.options.metadata;
373
- const model = result.response.modelId ?? "unknown";
374
- const startedAt = result.response.timestamp;
375
- const endedAt = /* @__PURE__ */ new Date();
376
- const inputRes = await this.client.traces.external.$post({
374
+ /**
375
+ * フィードバック(👍/👎)を送信
376
+ *
377
+ * @example
378
+ * ```ts
379
+ * await handler.score({ traceId, value: 1 }); // 👍
380
+ * await handler.score({ traceId, value: -1 }); // 👎
381
+ * ```
382
+ */
383
+ async score(params) {
384
+ const { userId, sessionId } = this.options.metadata;
385
+ const res = await this.client.feedbacks.external.$post({
377
386
  header: {
378
387
  "x-api-key": this.options.apiKey
379
388
  },
380
389
  json: {
381
- userId,
390
+ traceId: params.traceId,
382
391
  sessionId,
383
- model,
384
- token: result.usage.inputTokens ?? 0,
385
- content: input,
386
- type: "input",
387
- meta: { ...rest },
388
- startedAt: startedAt.toISOString(),
389
- endedAt: endedAt.toISOString()
392
+ userId,
393
+ value: params.value
390
394
  }
391
395
  });
392
- if (!inputRes.ok) {
393
- console.error(await inputRes.text());
394
- return;
396
+ if (!res.ok) {
397
+ console.error(await res.text());
395
398
  }
396
- const outputRes = await this.client.traces.external.$post({
397
- header: {
398
- "x-api-key": this.options.apiKey
399
- },
400
- json: {
401
- userId,
402
- sessionId,
403
- model,
404
- token: result.usage.outputTokens ?? 0,
405
- content: result.text,
406
- type: "output",
407
- meta: { ...rest },
408
- startedAt: startedAt.toISOString(),
409
- endedAt: endedAt.toISOString()
399
+ }
400
+ async sendTraces(params) {
401
+ const { input, result } = params;
402
+ const { userId, sessionId, ...rest } = this.options.metadata;
403
+ const model = result.response.modelId ?? "unknown";
404
+ const startedAt = result.response.timestamp;
405
+ const endedAt = /* @__PURE__ */ new Date();
406
+ try {
407
+ const res = await Promise.all([
408
+ this.client.traces.external.$post({
409
+ header: {
410
+ "x-api-key": this.options.apiKey
411
+ },
412
+ json: {
413
+ userId,
414
+ sessionId,
415
+ model,
416
+ token: result.usage.inputTokens ?? 0,
417
+ content: input,
418
+ type: "input",
419
+ meta: { ...rest },
420
+ startedAt: startedAt.toISOString(),
421
+ endedAt: endedAt.toISOString()
422
+ }
423
+ }),
424
+ this.client.traces.external.$post({
425
+ header: {
426
+ "x-api-key": this.options.apiKey
427
+ },
428
+ json: {
429
+ userId,
430
+ sessionId,
431
+ model,
432
+ token: result.usage.outputTokens ?? 0,
433
+ content: result.text,
434
+ type: "output",
435
+ meta: { ...rest },
436
+ startedAt: startedAt.toISOString(),
437
+ endedAt: endedAt.toISOString()
438
+ }
439
+ })
440
+ ]);
441
+ if (!res.every((r) => r.ok)) {
442
+ console.error(await Promise.all(res.map((r) => r.text())));
443
+ throw new Error("Failed to send traces");
410
444
  }
411
- });
412
- if (!outputRes.ok) {
413
- console.error(await outputRes.text());
414
- return;
445
+ const outputTrace = await res[1].json();
446
+ const traceId = outputTrace.id;
447
+ this.lastTraceId = traceId;
448
+ this.options.onSuccess?.(outputTrace);
449
+ return traceId;
450
+ } catch (error) {
451
+ console.error(error);
452
+ this.options.onFailure?.(error instanceof Error ? error : new Error(String(error)));
453
+ return void 0;
415
454
  }
416
455
  }
417
456
  }
package/dist/index.d.cts CHANGED
@@ -1,4 +1,118 @@
1
1
  import { StepResult, ToolSet, LanguageModelUsage, GenerateTextResult } from 'ai';
2
+ import { InferOutput, ObjectSchema, SchemaWithPipe, StringSchema, UuidAction, NumberSchema, PicklistSchema, RecordSchema, AnySchema, CustomSchema, StandardProps, UnknownDataset, Config, BaseIssue, OutputDataset, ObjectIssue, NumberIssue, StringIssue, PicklistIssue, RecordIssue, CustomIssue } from 'valibot';
3
+
4
+ declare const vTraceEntity: ObjectSchema<{
5
+ readonly id: SchemaWithPipe<readonly [StringSchema<undefined>, UuidAction<string, undefined>]>;
6
+ readonly userId: StringSchema<undefined>;
7
+ readonly sessionId: StringSchema<undefined>;
8
+ readonly model: StringSchema<undefined>;
9
+ readonly token: NumberSchema<undefined>;
10
+ readonly content: StringSchema<undefined>;
11
+ readonly type: PicklistSchema<["input", "output", "error"], undefined>;
12
+ readonly meta: RecordSchema<StringSchema<undefined>, AnySchema, undefined>;
13
+ readonly createdAt: SchemaWithPipe<readonly [CustomSchema<unknown, undefined>, StringSchema<undefined>]>;
14
+ readonly startedAt: SchemaWithPipe<readonly [CustomSchema<unknown, undefined>, StringSchema<undefined>]>;
15
+ readonly endedAt: SchemaWithPipe<readonly [CustomSchema<unknown, undefined>, StringSchema<undefined>]>;
16
+ }, undefined> & {
17
+ create: Omit<ObjectSchema<{
18
+ readonly id: SchemaWithPipe<readonly [StringSchema<undefined>, UuidAction<string, undefined>]>;
19
+ readonly userId: StringSchema<undefined>;
20
+ readonly sessionId: StringSchema<undefined>;
21
+ readonly model: StringSchema<undefined>;
22
+ readonly token: NumberSchema<undefined>;
23
+ readonly content: StringSchema<undefined>;
24
+ readonly type: PicklistSchema<["input", "output", "error"], undefined>;
25
+ readonly meta: RecordSchema<StringSchema<undefined>, AnySchema, undefined>;
26
+ readonly createdAt: SchemaWithPipe<readonly [CustomSchema<unknown, undefined>, StringSchema<undefined>]>;
27
+ readonly startedAt: SchemaWithPipe<readonly [CustomSchema<unknown, undefined>, StringSchema<undefined>]>;
28
+ readonly endedAt: SchemaWithPipe<readonly [CustomSchema<unknown, undefined>, StringSchema<undefined>]>;
29
+ }, undefined>, "~types" | "~run" | "~standard" | "entries"> & {
30
+ readonly entries: Omit<{
31
+ readonly id: SchemaWithPipe<readonly [StringSchema<undefined>, UuidAction<string, undefined>]>;
32
+ readonly userId: StringSchema<undefined>;
33
+ readonly sessionId: StringSchema<undefined>;
34
+ readonly model: StringSchema<undefined>;
35
+ readonly token: NumberSchema<undefined>;
36
+ readonly content: StringSchema<undefined>;
37
+ readonly type: PicklistSchema<["input", "output", "error"], undefined>;
38
+ readonly meta: RecordSchema<StringSchema<undefined>, AnySchema, undefined>;
39
+ readonly createdAt: SchemaWithPipe<readonly [CustomSchema<unknown, undefined>, StringSchema<undefined>]>;
40
+ readonly startedAt: SchemaWithPipe<readonly [CustomSchema<unknown, undefined>, StringSchema<undefined>]>;
41
+ readonly endedAt: SchemaWithPipe<readonly [CustomSchema<unknown, undefined>, StringSchema<undefined>]>;
42
+ }, "id" | "createdAt">;
43
+ readonly "~standard": StandardProps<{
44
+ type: "output" | "input" | "error";
45
+ token: number;
46
+ content: string;
47
+ userId: string;
48
+ model: string;
49
+ meta: {
50
+ [x: string]: any;
51
+ };
52
+ sessionId: string;
53
+ startedAt: unknown;
54
+ endedAt: unknown;
55
+ }, {
56
+ type: "output" | "input" | "error";
57
+ token: number;
58
+ content: string;
59
+ userId: string;
60
+ model: string;
61
+ meta: {
62
+ [x: string]: any;
63
+ };
64
+ sessionId: string;
65
+ startedAt: string;
66
+ endedAt: string;
67
+ }>;
68
+ readonly "~run": (dataset: UnknownDataset, config: Config<BaseIssue<unknown>>) => OutputDataset<{
69
+ type: "output" | "input" | "error";
70
+ token: number;
71
+ content: string;
72
+ userId: string;
73
+ model: string;
74
+ meta: {
75
+ [x: string]: any;
76
+ };
77
+ sessionId: string;
78
+ startedAt: string;
79
+ endedAt: string;
80
+ }, ObjectIssue | NumberIssue | StringIssue | PicklistIssue | RecordIssue | CustomIssue>;
81
+ readonly "~types"?: {
82
+ readonly input: {
83
+ type: "output" | "input" | "error";
84
+ token: number;
85
+ content: string;
86
+ userId: string;
87
+ model: string;
88
+ meta: {
89
+ [x: string]: any;
90
+ };
91
+ sessionId: string;
92
+ startedAt: unknown;
93
+ endedAt: unknown;
94
+ };
95
+ readonly output: {
96
+ type: "output" | "input" | "error";
97
+ token: number;
98
+ content: string;
99
+ userId: string;
100
+ model: string;
101
+ meta: {
102
+ [x: string]: any;
103
+ };
104
+ sessionId: string;
105
+ startedAt: string;
106
+ endedAt: string;
107
+ };
108
+ readonly issue: ObjectIssue | NumberIssue | StringIssue | PicklistIssue | RecordIssue | CustomIssue;
109
+ } | undefined;
110
+ };
111
+ };
112
+ type TraceEntity = InferOutput<typeof vTraceEntity>;
113
+ declare namespace TraceEntity {
114
+ type Create = InferOutput<typeof vTraceEntity.create>;
115
+ }
2
116
 
3
117
  declare namespace LangInsight {
4
118
  interface Options {
@@ -9,10 +123,14 @@ declare namespace LangInsight {
9
123
  sessionId: string;
10
124
  [key: string]: any;
11
125
  };
126
+ onSuccess?: (trace: TraceEntity) => void;
127
+ onFailure?: (error: Error) => void;
12
128
  }
13
129
  class CallbackHandler {
14
130
  private readonly options;
15
131
  private readonly client;
132
+ /** 最後に送信した output trace の ID */
133
+ lastTraceId: string | undefined;
16
134
  constructor(options: Options);
17
135
  /**
18
136
  * streamText の onFinish コールバックとして使用
@@ -37,6 +155,8 @@ declare namespace LangInsight {
37
155
  /**
38
156
  * generateText の結果を送信
39
157
  *
158
+ * @returns output trace の traceId(送信失敗時は undefined)
159
+ *
40
160
  * @example
41
161
  * ```ts
42
162
  * const handler = new LangInsight.CallbackHandler(options);
@@ -46,11 +166,24 @@ declare namespace LangInsight {
46
166
  * prompt: "Hello!",
47
167
  * });
48
168
  *
49
- * await handler.report(result, { input: "Hello!" });
169
+ * const traceId = await handler.report(result, { input: "Hello!" });
50
170
  * ```
51
171
  */
52
172
  report(result: GenerateTextResult<ToolSet, any>, params: {
53
173
  input: string;
174
+ }): Promise<string | undefined>;
175
+ /**
176
+ * フィードバック(👍/👎)を送信
177
+ *
178
+ * @example
179
+ * ```ts
180
+ * await handler.score({ traceId, value: 1 }); // 👍
181
+ * await handler.score({ traceId, value: -1 }); // 👎
182
+ * ```
183
+ */
184
+ score(params: {
185
+ traceId: string;
186
+ value: 1 | -1;
54
187
  }): Promise<void>;
55
188
  private sendTraces;
56
189
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@langinsight/ai-sdk",
3
3
  "module": "dist/index.js",
4
4
  "types": "dist/index.d.ts",
5
- "version": "0.0.1",
5
+ "version": "0.0.2",
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },