@langinsight/ai-sdk 0.0.1

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 ADDED
@@ -0,0 +1,69 @@
1
+ # @langinsight/ai-sdk
2
+
3
+ LangInsight callback handler for Vercel AI SDK.
4
+
5
+ ## Usage
6
+
7
+ ### generateText
8
+
9
+ ```typescript
10
+ import { generateText } from "ai";
11
+ import { openai } from "@ai-sdk/openai";
12
+ import { LangInsight } from "@langinsight/ai-sdk";
13
+
14
+ const { LANGINSIGHT_ENDPOINT, LANGINSIGHT_API_KEY } = process.env;
15
+
16
+ const handler = new LangInsight.CallbackHandler({
17
+ apiKey: LANGINSIGHT_API_KEY,
18
+ endpoint: LANGINSIGHT_ENDPOINT,
19
+ metadata: { userId: "admin", sessionId: "admin" },
20
+ });
21
+
22
+ const prompt = "Hello!";
23
+
24
+ const result = await generateText({
25
+ model: openai("gpt-4o"),
26
+ prompt,
27
+ });
28
+
29
+ // Report the result to LangInsight
30
+ await handler.report(result, { input: prompt });
31
+ ```
32
+
33
+ ### streamText
34
+
35
+ ```typescript
36
+ import { streamText } from "ai";
37
+ import { openai } from "@ai-sdk/openai";
38
+ import { LangInsight } from "@langinsight/ai-sdk";
39
+
40
+ const { LANGINSIGHT_ENDPOINT, LANGINSIGHT_API_KEY } = process.env;
41
+
42
+ const handler = new LangInsight.CallbackHandler({
43
+ apiKey: LANGINSIGHT_API_KEY,
44
+ endpoint: LANGINSIGHT_ENDPOINT,
45
+ metadata: { userId: "admin", sessionId: "admin" },
46
+ });
47
+
48
+ const prompt = "Hello!";
49
+
50
+ const result = streamText({
51
+ model: openai("gpt-4o"),
52
+ prompt,
53
+ // Specify callback handler as onFinish
54
+ onFinish: handler.onFinish({ input: prompt }),
55
+ });
56
+
57
+ for await (const chunk of result.textStream) {
58
+ process.stdout.write(chunk);
59
+ }
60
+ ```
61
+
62
+ ## Options
63
+
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
package/dist/index.cjs ADDED
@@ -0,0 +1,423 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ LangInsight: () => LangInsight
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // ../../../node_modules/hono/dist/utils/cookie.js
28
+ var _serialize = (name, value, opt = {}) => {
29
+ let cookie = `${name}=${value}`;
30
+ if (name.startsWith("__Secure-") && !opt.secure) {
31
+ throw new Error("__Secure- Cookie must have Secure attributes");
32
+ }
33
+ if (name.startsWith("__Host-")) {
34
+ if (!opt.secure) {
35
+ throw new Error("__Host- Cookie must have Secure attributes");
36
+ }
37
+ if (opt.path !== "/") {
38
+ throw new Error('__Host- Cookie must have Path attributes with "/"');
39
+ }
40
+ if (opt.domain) {
41
+ throw new Error("__Host- Cookie must not have Domain attributes");
42
+ }
43
+ }
44
+ if (opt && typeof opt.maxAge === "number" && opt.maxAge >= 0) {
45
+ if (opt.maxAge > 3456e4) {
46
+ throw new Error(
47
+ "Cookies Max-Age SHOULD NOT be greater than 400 days (34560000 seconds) in duration."
48
+ );
49
+ }
50
+ cookie += `; Max-Age=${opt.maxAge | 0}`;
51
+ }
52
+ if (opt.domain && opt.prefix !== "host") {
53
+ cookie += `; Domain=${opt.domain}`;
54
+ }
55
+ if (opt.path) {
56
+ cookie += `; Path=${opt.path}`;
57
+ }
58
+ if (opt.expires) {
59
+ if (opt.expires.getTime() - Date.now() > 3456e7) {
60
+ throw new Error(
61
+ "Cookies Expires SHOULD NOT be greater than 400 days (34560000 seconds) in the future."
62
+ );
63
+ }
64
+ cookie += `; Expires=${opt.expires.toUTCString()}`;
65
+ }
66
+ if (opt.httpOnly) {
67
+ cookie += "; HttpOnly";
68
+ }
69
+ if (opt.secure) {
70
+ cookie += "; Secure";
71
+ }
72
+ if (opt.sameSite) {
73
+ cookie += `; SameSite=${opt.sameSite.charAt(0).toUpperCase() + opt.sameSite.slice(1)}`;
74
+ }
75
+ if (opt.priority) {
76
+ cookie += `; Priority=${opt.priority.charAt(0).toUpperCase() + opt.priority.slice(1)}`;
77
+ }
78
+ if (opt.partitioned) {
79
+ if (!opt.secure) {
80
+ throw new Error("Partitioned Cookie must have Secure attributes");
81
+ }
82
+ cookie += "; Partitioned";
83
+ }
84
+ return cookie;
85
+ };
86
+ var serialize = (name, value, opt) => {
87
+ value = encodeURIComponent(value);
88
+ return _serialize(name, value, opt);
89
+ };
90
+
91
+ // ../../../node_modules/hono/dist/client/utils.js
92
+ var mergePath = (base, path) => {
93
+ base = base.replace(/\/+$/, "");
94
+ base = base + "/";
95
+ path = path.replace(/^\/+/, "");
96
+ return base + path;
97
+ };
98
+ var replaceUrlParam = (urlString, params) => {
99
+ for (const [k, v] of Object.entries(params)) {
100
+ const reg = new RegExp("/:" + k + "(?:{[^/]+})?\\??");
101
+ urlString = urlString.replace(reg, v ? `/${v}` : "");
102
+ }
103
+ return urlString;
104
+ };
105
+ var buildSearchParams = (query) => {
106
+ const searchParams = new URLSearchParams();
107
+ for (const [k, v] of Object.entries(query)) {
108
+ if (v === void 0) {
109
+ continue;
110
+ }
111
+ if (Array.isArray(v)) {
112
+ for (const v2 of v) {
113
+ searchParams.append(k, v2);
114
+ }
115
+ } else {
116
+ searchParams.set(k, v);
117
+ }
118
+ }
119
+ return searchParams;
120
+ };
121
+ var replaceUrlProtocol = (urlString, protocol) => {
122
+ switch (protocol) {
123
+ case "ws":
124
+ return urlString.replace(/^http/, "ws");
125
+ case "http":
126
+ return urlString.replace(/^ws/, "http");
127
+ }
128
+ };
129
+ var removeIndexString = (urlString) => {
130
+ if (/^https?:\/\/[^\/]+?\/index(?=\?|$)/.test(urlString)) {
131
+ return urlString.replace(/\/index(?=\?|$)/, "/");
132
+ }
133
+ return urlString.replace(/\/index(?=\?|$)/, "");
134
+ };
135
+ function isObject(item) {
136
+ return typeof item === "object" && item !== null && !Array.isArray(item);
137
+ }
138
+ function deepMerge(target, source) {
139
+ if (!isObject(target) && !isObject(source)) {
140
+ return source;
141
+ }
142
+ const merged = { ...target };
143
+ for (const key in source) {
144
+ const value = source[key];
145
+ if (isObject(merged[key]) && isObject(value)) {
146
+ merged[key] = deepMerge(merged[key], value);
147
+ } else {
148
+ merged[key] = value;
149
+ }
150
+ }
151
+ return merged;
152
+ }
153
+
154
+ // ../../../node_modules/hono/dist/client/client.js
155
+ var createProxy = (callback, path) => {
156
+ const proxy = new Proxy(() => {
157
+ }, {
158
+ get(_obj, key) {
159
+ if (typeof key !== "string" || key === "then") {
160
+ return void 0;
161
+ }
162
+ return createProxy(callback, [...path, key]);
163
+ },
164
+ apply(_1, _2, args) {
165
+ return callback({
166
+ path,
167
+ args
168
+ });
169
+ }
170
+ });
171
+ return proxy;
172
+ };
173
+ var ClientRequestImpl = class {
174
+ url;
175
+ method;
176
+ buildSearchParams;
177
+ queryParams = void 0;
178
+ pathParams = {};
179
+ rBody;
180
+ cType = void 0;
181
+ constructor(url, method, options) {
182
+ this.url = url;
183
+ this.method = method;
184
+ this.buildSearchParams = options.buildSearchParams;
185
+ }
186
+ fetch = async (args, opt) => {
187
+ if (args) {
188
+ if (args.query) {
189
+ this.queryParams = this.buildSearchParams(args.query);
190
+ }
191
+ if (args.form) {
192
+ const form = new FormData();
193
+ for (const [k, v] of Object.entries(args.form)) {
194
+ if (Array.isArray(v)) {
195
+ for (const v2 of v) {
196
+ form.append(k, v2);
197
+ }
198
+ } else {
199
+ form.append(k, v);
200
+ }
201
+ }
202
+ this.rBody = form;
203
+ }
204
+ if (args.json) {
205
+ this.rBody = JSON.stringify(args.json);
206
+ this.cType = "application/json";
207
+ }
208
+ if (args.param) {
209
+ this.pathParams = args.param;
210
+ }
211
+ }
212
+ let methodUpperCase = this.method.toUpperCase();
213
+ const headerValues = {
214
+ ...args?.header,
215
+ ...typeof opt?.headers === "function" ? await opt.headers() : opt?.headers
216
+ };
217
+ if (args?.cookie) {
218
+ const cookies = [];
219
+ for (const [key, value] of Object.entries(args.cookie)) {
220
+ cookies.push(serialize(key, value, { path: "/" }));
221
+ }
222
+ headerValues["Cookie"] = cookies.join(",");
223
+ }
224
+ if (this.cType) {
225
+ headerValues["Content-Type"] = this.cType;
226
+ }
227
+ const headers = new Headers(headerValues ?? void 0);
228
+ let url = this.url;
229
+ url = removeIndexString(url);
230
+ url = replaceUrlParam(url, this.pathParams);
231
+ if (this.queryParams) {
232
+ url = url + "?" + this.queryParams.toString();
233
+ }
234
+ methodUpperCase = this.method.toUpperCase();
235
+ const setBody = !(methodUpperCase === "GET" || methodUpperCase === "HEAD");
236
+ return (opt?.fetch || fetch)(url, {
237
+ body: setBody ? this.rBody : void 0,
238
+ method: methodUpperCase,
239
+ headers,
240
+ ...opt?.init
241
+ });
242
+ };
243
+ };
244
+ var hc = (baseUrl, options) => createProxy(function proxyCallback(opts) {
245
+ const buildSearchParamsOption = options?.buildSearchParams ?? buildSearchParams;
246
+ const parts = [...opts.path];
247
+ const lastParts = parts.slice(-3).reverse();
248
+ if (lastParts[0] === "toString") {
249
+ if (lastParts[1] === "name") {
250
+ return lastParts[2] || "";
251
+ }
252
+ return proxyCallback.toString();
253
+ }
254
+ if (lastParts[0] === "valueOf") {
255
+ if (lastParts[1] === "name") {
256
+ return lastParts[2] || "";
257
+ }
258
+ return proxyCallback;
259
+ }
260
+ let method = "";
261
+ if (/^\$/.test(lastParts[0])) {
262
+ const last = parts.pop();
263
+ if (last) {
264
+ method = last.replace(/^\$/, "");
265
+ }
266
+ }
267
+ const path = parts.join("/");
268
+ const url = mergePath(baseUrl, path);
269
+ if (method === "url") {
270
+ let result = url;
271
+ if (opts.args[0]) {
272
+ if (opts.args[0].param) {
273
+ result = replaceUrlParam(url, opts.args[0].param);
274
+ }
275
+ if (opts.args[0].query) {
276
+ result = result + "?" + buildSearchParamsOption(opts.args[0].query).toString();
277
+ }
278
+ }
279
+ result = removeIndexString(result);
280
+ return new URL(result);
281
+ }
282
+ if (method === "ws") {
283
+ const webSocketUrl = replaceUrlProtocol(
284
+ opts.args[0] && opts.args[0].param ? replaceUrlParam(url, opts.args[0].param) : url,
285
+ "ws"
286
+ );
287
+ const targetUrl = new URL(webSocketUrl);
288
+ const queryParams = opts.args[0]?.query;
289
+ if (queryParams) {
290
+ Object.entries(queryParams).forEach(([key, value]) => {
291
+ if (Array.isArray(value)) {
292
+ value.forEach((item) => targetUrl.searchParams.append(key, item));
293
+ } else {
294
+ targetUrl.searchParams.set(key, value);
295
+ }
296
+ });
297
+ }
298
+ const establishWebSocket = (...args) => {
299
+ if (options?.webSocket !== void 0 && typeof options.webSocket === "function") {
300
+ return options.webSocket(...args);
301
+ }
302
+ return new WebSocket(...args);
303
+ };
304
+ return establishWebSocket(targetUrl.toString());
305
+ }
306
+ const req = new ClientRequestImpl(url, method, {
307
+ buildSearchParams: buildSearchParamsOption
308
+ });
309
+ if (method) {
310
+ options ??= {};
311
+ const args = deepMerge(options, { ...opts.args[1] });
312
+ return req.fetch(opts.args[0], args);
313
+ }
314
+ return req;
315
+ }, []);
316
+
317
+ // src/index.ts
318
+ var LangInsight;
319
+ ((LangInsight2) => {
320
+ class CallbackHandler {
321
+ constructor(options) {
322
+ this.options = options;
323
+ this.client = hc(options.endpoint, { fetch });
324
+ }
325
+ client;
326
+ /**
327
+ * streamText の onFinish コールバックとして使用
328
+ *
329
+ * @example
330
+ * ```ts
331
+ * const handler = new LangInsight.CallbackHandler(options);
332
+ *
333
+ * const result = streamText({
334
+ * model: openai("gpt-4o"),
335
+ * prompt: "Hello!",
336
+ * onFinish: handler.onFinish({ input: "Hello!" }),
337
+ * });
338
+ * ```
339
+ */
340
+ onFinish(params) {
341
+ return async (event) => {
342
+ await this.sendTraces({
343
+ input: params.input,
344
+ result: event
345
+ });
346
+ };
347
+ }
348
+ /**
349
+ * generateText の結果を送信
350
+ *
351
+ * @example
352
+ * ```ts
353
+ * const handler = new LangInsight.CallbackHandler(options);
354
+ *
355
+ * const result = await generateText({
356
+ * model: openai("gpt-4o"),
357
+ * prompt: "Hello!",
358
+ * });
359
+ *
360
+ * await handler.report(result, { input: "Hello!" });
361
+ * ```
362
+ */
363
+ // biome-ignore lint/suspicious/noExplicitAny: should accept any output
364
+ async report(result, params) {
365
+ await this.sendTraces({
366
+ input: params.input,
367
+ result
368
+ });
369
+ }
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({
377
+ header: {
378
+ "x-api-key": this.options.apiKey
379
+ },
380
+ json: {
381
+ userId,
382
+ 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()
390
+ }
391
+ });
392
+ if (!inputRes.ok) {
393
+ console.error(await inputRes.text());
394
+ return;
395
+ }
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()
410
+ }
411
+ });
412
+ if (!outputRes.ok) {
413
+ console.error(await outputRes.text());
414
+ return;
415
+ }
416
+ }
417
+ }
418
+ LangInsight2.CallbackHandler = CallbackHandler;
419
+ })(LangInsight || (LangInsight = {}));
420
+ // Annotate the CommonJS export names for ESM import in node:
421
+ 0 && (module.exports = {
422
+ LangInsight
423
+ });
@@ -0,0 +1,59 @@
1
+ import { StepResult, ToolSet, LanguageModelUsage, GenerateTextResult } from 'ai';
2
+
3
+ declare namespace LangInsight {
4
+ interface Options {
5
+ apiKey: string;
6
+ endpoint: string;
7
+ metadata: {
8
+ userId: string;
9
+ sessionId: string;
10
+ [key: string]: any;
11
+ };
12
+ }
13
+ class CallbackHandler {
14
+ private readonly options;
15
+ private readonly client;
16
+ constructor(options: Options);
17
+ /**
18
+ * streamText の onFinish コールバックとして使用
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const handler = new LangInsight.CallbackHandler(options);
23
+ *
24
+ * const result = streamText({
25
+ * model: openai("gpt-4o"),
26
+ * prompt: "Hello!",
27
+ * onFinish: handler.onFinish({ input: "Hello!" }),
28
+ * });
29
+ * ```
30
+ */
31
+ onFinish(params: {
32
+ input: string;
33
+ }): (event: StepResult<ToolSet> & {
34
+ readonly steps: StepResult<ToolSet>[];
35
+ readonly totalUsage: LanguageModelUsage;
36
+ }) => Promise<void>;
37
+ /**
38
+ * generateText の結果を送信
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * const handler = new LangInsight.CallbackHandler(options);
43
+ *
44
+ * const result = await generateText({
45
+ * model: openai("gpt-4o"),
46
+ * prompt: "Hello!",
47
+ * });
48
+ *
49
+ * await handler.report(result, { input: "Hello!" });
50
+ * ```
51
+ */
52
+ report(result: GenerateTextResult<ToolSet, any>, params: {
53
+ input: string;
54
+ }): Promise<void>;
55
+ private sendTraces;
56
+ }
57
+ }
58
+
59
+ export { LangInsight };
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@langinsight/ai-sdk",
3
+ "module": "dist/index.js",
4
+ "types": "dist/index.d.ts",
5
+ "version": "0.0.1",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "author": "iZ.Inc",
13
+ "license": "MIT",
14
+ "type": "module",
15
+ "scripts": {
16
+ "build": "tsup src/index.ts --dts --out-dir dist"
17
+ },
18
+ "dependencies": {
19
+ "@hono/client": "^0.0.3"
20
+ },
21
+ "peerDependencies": {
22
+ "ai": ">=5.0.0"
23
+ },
24
+ "devDependencies": {
25
+ "@types/bun": "1.3.8",
26
+ "ai": "^6.0.73",
27
+ "tsup": "^8.5.1",
28
+ "typescript": "^5.9.3"
29
+ }
30
+ }