@langinsight/ai-sdk 0.0.1 → 0.0.3

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
 
@@ -17,6 +17,10 @@ const handler = new LangInsight.CallbackHandler({
17
17
  apiKey: LANGINSIGHT_API_KEY,
18
18
  endpoint: LANGINSIGHT_ENDPOINT,
19
19
  metadata: { userId: "admin", sessionId: "admin" },
20
+ onSuccess: (trace) => {
21
+ // traceId の取得・DB永続化はここで
22
+ console.log("Trace sent:", trace.id);
23
+ },
20
24
  });
21
25
 
22
26
  const prompt = "Hello!";
@@ -26,7 +30,6 @@ const result = await generateText({
26
30
  prompt,
27
31
  });
28
32
 
29
- // Report the result to LangInsight
30
33
  await handler.report(result, { input: prompt });
31
34
  ```
32
35
 
@@ -43,6 +46,8 @@ const handler = new LangInsight.CallbackHandler({
43
46
  apiKey: LANGINSIGHT_API_KEY,
44
47
  endpoint: LANGINSIGHT_ENDPOINT,
45
48
  metadata: { userId: "admin", sessionId: "admin" },
49
+ onSuccess: (trace) => console.log("Trace sent:", trace.id),
50
+ onFailure: (err) => console.error("Trace failed:", err),
46
51
  });
47
52
 
48
53
  const prompt = "Hello!";
@@ -50,7 +55,6 @@ const prompt = "Hello!";
50
55
  const result = streamText({
51
56
  model: openai("gpt-4o"),
52
57
  prompt,
53
- // Specify callback handler as onFinish
54
58
  onFinish: handler.onFinish({ input: prompt }),
55
59
  });
56
60
 
@@ -59,11 +63,41 @@ for await (const chunk of result.textStream) {
59
63
  }
60
64
  ```
61
65
 
66
+ ### Feedback (score)
67
+
68
+ Trace ID の取得や DB 永続化は `onSuccess` コールバックで受け取った `trace` を使って行い、その `trace.id` を `score()` に渡してフィードバックを送信する。
69
+
70
+ ```typescript
71
+ let lastOutputTraceId: string | undefined;
72
+
73
+ const handler = new LangInsight.CallbackHandler({
74
+ ...options,
75
+ onSuccess: (trace) => {
76
+ lastOutputTraceId = trace.id; // DB 永続化などもここで
77
+ },
78
+ });
79
+
80
+ // report() または onFinish の後
81
+ await handler.score({ traceId: lastOutputTraceId!, value: 1 }); // 👍
82
+ await handler.score({ traceId: lastOutputTraceId!, value: -1 }); // 👎
83
+ ```
84
+
62
85
  ## Options
63
86
 
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
87
+ | Option | Type | Required | Description |
88
+ | ----------- | --------------------------------- | -------- | --------------------------------------------------------------------------- |
89
+ | `apiKey` | `string` | Yes | LangInsight API key |
90
+ | `endpoint` | `string` | Yes | LangInsight API endpoint (e.g. `https://api.langinsight.example.com`) |
91
+ | `metadata` | `object` | Yes | Metadata attached to traces |
92
+ | `metadata.userId` | `string` | Yes | User ID |
93
+ | `metadata.sessionId`| `string` | Yes | Session ID (e.g. conversation id) |
94
+ | `metadata.modelName` | `string` | No | Model name (defaults to result response when not set) |
95
+ | `metadata.*` | `any` | No | Additional key-value pairs |
96
+ | `onSuccess` | `(trace: Trace) => void` | No | Callback invoked with the output trace when trace submission succeeds. Use this to get `trace.id` and persist to DB. |
97
+ | `onFailure` | `(error: Error) => void` | No | Callback invoked with the error when trace submission fails |
98
+
99
+ ## API
100
+
101
+ - **`report(result, { input })`** — Sends traces for a `generateText` result. Trace is passed to `onSuccess` on success.
102
+ - **`onFinish({ input })`** — Returns a function suitable for `streamText`’s `onFinish`. Sends traces when the stream finishes; trace is passed to `onSuccess`.
103
+ - **`score({ traceId, value })`** — Submits feedback (1 = thumbs up, -1 = thumbs down) for the given trace. Use the `trace.id` received in `onSuccess` as `traceId`.
package/dist/index.cjs CHANGED
@@ -347,16 +347,17 @@ var LangInsight;
347
347
  }
348
348
  /**
349
349
  * generateText の結果を送信
350
+ * traceId の取得・DB永続化は onSuccess コールバックで trace を受け取り行う。
350
351
  *
351
352
  * @example
352
353
  * ```ts
353
- * const handler = new LangInsight.CallbackHandler(options);
354
- *
355
- * const result = await generateText({
356
- * model: openai("gpt-4o"),
357
- * prompt: "Hello!",
354
+ * const handler = new LangInsight.CallbackHandler({
355
+ * ...options,
356
+ * onSuccess: (trace) => {
357
+ * saveTraceToDb(trace); // traceId = trace.id
358
+ * },
358
359
  * });
359
- *
360
+ * const result = await generateText({ model: openai("gpt-4o"), prompt: "Hello!" });
360
361
  * await handler.report(result, { input: "Hello!" });
361
362
  * ```
362
363
  */
@@ -367,51 +368,84 @@ var LangInsight;
367
368
  result
368
369
  });
369
370
  }
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({
371
+ /**
372
+ * フィードバック(👍/👎)を送信
373
+ * traceId onSuccess コールバックで受け取った trace.id を使用する。
374
+ *
375
+ * @example
376
+ * ```ts
377
+ * onSuccess: (trace) => { lastOutputTraceId = trace.id; },
378
+ * // ...
379
+ * await handler.score({ traceId: lastOutputTraceId, value: 1 }); // 👍
380
+ * ```
381
+ */
382
+ async score(params) {
383
+ const { userId, sessionId } = this.options.metadata;
384
+ const res = await this.client.feedbacks.external.$post({
377
385
  header: {
378
386
  "x-api-key": this.options.apiKey
379
387
  },
380
388
  json: {
381
- userId,
389
+ traceId: params.traceId,
382
390
  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()
391
+ userId,
392
+ value: params.value
390
393
  }
391
394
  });
392
- if (!inputRes.ok) {
393
- console.error(await inputRes.text());
394
- return;
395
+ if (!res.ok) {
396
+ console.error(await res.text());
395
397
  }
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()
398
+ }
399
+ async sendTraces(params) {
400
+ const { input, result } = params;
401
+ const { userId, sessionId, ...rest } = this.options.metadata;
402
+ const model = result.response.modelId ?? "unknown";
403
+ const startedAt = result.response.timestamp;
404
+ const endedAt = /* @__PURE__ */ new Date();
405
+ try {
406
+ const res = await Promise.all([
407
+ this.client.traces.external.$post({
408
+ header: {
409
+ "x-api-key": this.options.apiKey
410
+ },
411
+ json: {
412
+ userId,
413
+ sessionId,
414
+ model,
415
+ token: result.usage.inputTokens ?? 0,
416
+ content: input,
417
+ type: "input",
418
+ meta: { ...rest },
419
+ startedAt: startedAt.toISOString(),
420
+ endedAt: endedAt.toISOString()
421
+ }
422
+ }),
423
+ this.client.traces.external.$post({
424
+ header: {
425
+ "x-api-key": this.options.apiKey
426
+ },
427
+ json: {
428
+ userId,
429
+ sessionId,
430
+ model,
431
+ token: result.usage.outputTokens ?? 0,
432
+ content: result.text,
433
+ type: "output",
434
+ meta: { ...rest },
435
+ startedAt: startedAt.toISOString(),
436
+ endedAt: endedAt.toISOString()
437
+ }
438
+ })
439
+ ]);
440
+ if (!res.every((r) => r.ok)) {
441
+ console.error(await Promise.all(res.map((r) => r.text())));
442
+ throw new Error("Failed to send traces");
410
443
  }
411
- });
412
- if (!outputRes.ok) {
413
- console.error(await outputRes.text());
414
- return;
444
+ const outputTrace = await res[1].json();
445
+ this.options.onSuccess?.(outputTrace);
446
+ } catch (error) {
447
+ console.error(error);
448
+ this.options.onFailure?.(error instanceof Error ? error : new Error(String(error)));
415
449
  }
416
450
  }
417
451
  }
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,6 +123,8 @@ 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;
@@ -36,22 +152,38 @@ declare namespace LangInsight {
36
152
  }) => Promise<void>;
37
153
  /**
38
154
  * generateText の結果を送信
155
+ * traceId の取得・DB永続化は onSuccess コールバックで trace を受け取り行う。
39
156
  *
40
157
  * @example
41
158
  * ```ts
42
- * const handler = new LangInsight.CallbackHandler(options);
43
- *
44
- * const result = await generateText({
45
- * model: openai("gpt-4o"),
46
- * prompt: "Hello!",
159
+ * const handler = new LangInsight.CallbackHandler({
160
+ * ...options,
161
+ * onSuccess: (trace) => {
162
+ * saveTraceToDb(trace); // traceId = trace.id
163
+ * },
47
164
  * });
48
- *
165
+ * const result = await generateText({ model: openai("gpt-4o"), prompt: "Hello!" });
49
166
  * await handler.report(result, { input: "Hello!" });
50
167
  * ```
51
168
  */
52
169
  report(result: GenerateTextResult<ToolSet, any>, params: {
53
170
  input: string;
54
171
  }): Promise<void>;
172
+ /**
173
+ * フィードバック(👍/👎)を送信
174
+ * traceId は onSuccess コールバックで受け取った trace.id を使用する。
175
+ *
176
+ * @example
177
+ * ```ts
178
+ * onSuccess: (trace) => { lastOutputTraceId = trace.id; },
179
+ * // ...
180
+ * await handler.score({ traceId: lastOutputTraceId, value: 1 }); // 👍
181
+ * ```
182
+ */
183
+ score(params: {
184
+ traceId: string;
185
+ value: 1 | -1;
186
+ }): Promise<void>;
55
187
  private sendTraces;
56
188
  }
57
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.3",
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },
@@ -23,7 +23,7 @@
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/bun": "1.3.8",
26
- "ai": "^6.0.73",
26
+ "ai": "^6.0.77",
27
27
  "tsup": "^8.5.1",
28
28
  "typescript": "^5.9.3"
29
29
  }