Skip to content

Commit 3930fc5

Browse files
committed
fix: bun lock
2 parents 63dc9b3 + a8c7917 commit 3930fc5

File tree

7 files changed

+464
-370
lines changed

7 files changed

+464
-370
lines changed

apps/docs/app/robots.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ export default function robots(): MetadataRoute.Robots {
2020
disallow: '/',
2121
},
2222
],
23-
sitemap: `${SITE_URL}/sitemap.xml`,
24-
host: SITE_URL,
23+
sitemap: `${SITE_URL}/sitemap.xml`
2524
};
2625
}

bun.lock

Lines changed: 320 additions & 364 deletions
Large diffs are not rendered by default.

packages/sdk/package.json

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111
"test": "bun test"
1212
},
1313
"dependencies": {
14-
"jotai": ">=2.0.0"
15-
},
16-
"optionalDependencies": {
17-
"pino": "^9.0.0"
14+
"@ai-sdk/provider": "^2.0.0",
15+
"ai": "^5.0.51",
16+
"jotai": ">=2.0.0",
17+
"tokenlens": "^2.0.0-alpha.3"
1818
},
1919
"devDependencies": {
2020
"@types/node": "^20.0.0",
@@ -50,6 +50,10 @@
5050
"./node": {
5151
"types": "./dist/node/index.d.ts",
5252
"import": "./dist/node/index.mjs"
53+
},
54+
"./ai/vercel": {
55+
"types": "./dist/ai/vercel/index.d.ts",
56+
"import": "./dist/ai/vercel/index.mjs"
5357
}
5458
},
5559
"files": [

packages/sdk/src/ai/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './vercel';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { wrapVercelLanguageModel as withBuddy } from './middleware';
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { expect, test } from 'bun:test';
2+
import { generateText } from 'ai';
3+
import { MockLanguageModelV2 } from 'ai/test';
4+
import { Databuddy } from '../../node';
5+
import { type TrackProperties, wrapVercelLanguageModel } from './middleware';
6+
7+
const mockModel = new MockLanguageModelV2({
8+
doGenerate: async () => ({
9+
finishReason: 'stop',
10+
usage: { inputTokens: 10, outputTokens: 20, totalTokens: 30 },
11+
content: [{ type: 'text', text: 'Hello, world!' }],
12+
warnings: [],
13+
}),
14+
});
15+
16+
test('wrapVercelLanguageModel', async () => {
17+
const buddy = new Databuddy({});
18+
const model = wrapVercelLanguageModel(mockModel, buddy);
19+
20+
const result = await generateText({
21+
model,
22+
prompt: 'Hello, how are you?',
23+
});
24+
25+
expect(result.text).toBe('Hello, world!');
26+
27+
const trackEntries = buddy.records.filter((r) => r.event === 'ai.generate');
28+
29+
expect(trackEntries.length).toBe(1);
30+
const { properties: payload } = trackEntries[0] as {
31+
event: string;
32+
properties: TrackProperties;
33+
};
34+
35+
expect(payload).toEqual({
36+
inputTokens: 10,
37+
outputTokens: 20,
38+
totalTokens: 30,
39+
cachedInputTokens: undefined,
40+
finishReason: 'stop',
41+
toolCallCount: 0,
42+
toolResultCount: 0,
43+
toolCallNames: [],
44+
});
45+
});
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import type {
2+
LanguageModelV2,
3+
LanguageModelV2Middleware,
4+
} from '@ai-sdk/provider';
5+
import { wrapLanguageModel } from 'ai';
6+
import { computeCostUSD } from 'tokenlens';
7+
import type { Databuddy } from '../../node';
8+
9+
export type TrackProperties = {
10+
inputTokens?: number;
11+
outputTokens?: number;
12+
totalTokens?: number;
13+
cachedInputTokens?: number;
14+
finishReason?: string;
15+
toolCallCount?: number;
16+
toolResultCount?: number;
17+
toolCallNames?: string[];
18+
inputTokenCostUSD?: number;
19+
outputTokenCostUSD?: number;
20+
totalTokenCostUSD?: number;
21+
};
22+
23+
const buddyWare = (buddy: Databuddy): LanguageModelV2Middleware => {
24+
return {
25+
wrapGenerate: async ({ doGenerate, model }) => {
26+
const result = await doGenerate();
27+
28+
const isToolCall = (
29+
part: (typeof result.content)[number]
30+
): part is Extract<
31+
(typeof result.content)[number],
32+
{ type: 'tool-call' }
33+
> => part.type === 'tool-call';
34+
35+
const isToolResult = (
36+
part: (typeof result.content)[number]
37+
): part is Extract<
38+
(typeof result.content)[number],
39+
{ type: 'tool-result' }
40+
> => part.type === 'tool-result';
41+
42+
const toolCalls = result.content.filter(isToolCall);
43+
const toolResults = result.content.filter(isToolResult);
44+
const toolCallNames = Array.from(
45+
new Set(toolCalls.map((c) => c.toolName))
46+
);
47+
48+
const costs = await computeCostUSD({
49+
modelId: model.modelId,
50+
provider: model.provider,
51+
usage: result.usage,
52+
});
53+
54+
const payload: TrackProperties = {
55+
inputTokens: result.usage.inputTokens,
56+
outputTokens: result.usage.outputTokens,
57+
totalTokens: result.usage.totalTokens,
58+
cachedInputTokens: result.usage.cachedInputTokens,
59+
finishReason: result.finishReason,
60+
toolCallCount: toolCalls.length,
61+
toolResultCount: toolResults.length,
62+
inputTokenCostUSD: costs.inputTokenCostUSD,
63+
outputTokenCostUSD: costs.outputTokenCostUSD,
64+
totalTokenCostUSD: costs.totalTokenCostUSD,
65+
toolCallNames,
66+
};
67+
buddy.track({name: 'ai.generate', properties: payload});
68+
69+
return result;
70+
},
71+
};
72+
};
73+
74+
/**
75+
* Wrap a Vercel language model with Databuddy middleware
76+
* @param model - The Vercel language model to wrap, if you are using the Vercel AI Gateway, please use the LanguageModelV2 type e.g. gateway('xai/grok-3') instead of the string type e.g. 'xai/grok-3'
77+
* @param buddy - The Databuddy instance to use
78+
* @returns The wrapped language model, can be used in e.g. generateText from the ai package
79+
*/
80+
export const wrapVercelLanguageModel = (
81+
model: LanguageModelV2,
82+
buddy: Databuddy
83+
) => {
84+
return wrapLanguageModel({
85+
model,
86+
middleware: buddyWare(buddy),
87+
});
88+
};

0 commit comments

Comments
 (0)