@kernl-sdk/ai 0.4.2 → 0.4.4
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +24 -0
- package/dist/__tests__/integration.test.js +10 -11
- package/dist/__tests__/language-model.test.js +15 -20
- package/dist/convert/__tests__/response.test.js +18 -16
- package/dist/convert/__tests__/stream.test.js +21 -20
- package/dist/convert/__tests__/tools.test.js +5 -5
- package/dist/convert/__tests__/ui-stream.test.js +11 -5
- package/dist/convert/response.d.ts +4 -4
- package/dist/convert/response.d.ts.map +1 -1
- package/dist/convert/response.js +1 -20
- package/dist/convert/stream.d.ts.map +1 -1
- package/dist/convert/stream.js +1 -7
- package/dist/convert/tools.d.ts +2 -2
- package/dist/convert/tools.d.ts.map +1 -1
- package/dist/convert/tools.js +2 -2
- package/dist/embedding-model.d.ts +3 -3
- package/dist/embedding-model.d.ts.map +1 -1
- package/dist/oauth/anthropic.d.ts +8 -0
- package/dist/oauth/anthropic.d.ts.map +1 -0
- package/dist/oauth/anthropic.js +65 -0
- package/dist/oauth/openai.d.ts +8 -0
- package/dist/oauth/openai.d.ts.map +1 -0
- package/dist/oauth/openai.js +97 -0
- package/dist/oauth/types.d.ts +25 -0
- package/dist/oauth/types.d.ts.map +1 -0
- package/dist/oauth/types.js +1 -0
- package/dist/providers/anthropic.d.ts +46 -2
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +35 -2
- package/dist/providers/google.d.ts +7 -2
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/google.js +2 -2
- package/dist/providers/openai.d.ts +47 -2
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +37 -3
- package/package.json +9 -9
- package/src/__tests__/integration.test.ts +10 -11
- package/src/__tests__/language-model.test.ts +15 -20
- package/src/convert/__tests__/response.test.ts +23 -21
- package/src/convert/__tests__/stream.test.ts +21 -20
- package/src/convert/__tests__/tools.test.ts +6 -6
- package/src/convert/__tests__/ui-stream.test.ts +11 -5
- package/src/convert/response.ts +9 -30
- package/src/convert/stream.ts +1 -7
- package/src/convert/tools.ts +5 -5
- package/src/embedding-model.ts +3 -5
- package/src/oauth/anthropic.ts +87 -0
- package/src/oauth/openai.ts +129 -0
- package/src/oauth/types.ts +25 -0
- package/src/providers/anthropic.ts +65 -3
- package/src/providers/google.ts +8 -3
- package/src/providers/openai.ts +67 -4
package/.turbo/turbo-build.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @kernl/ai
|
|
2
2
|
|
|
3
|
+
## 0.4.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 884e513: Align with @ai-sdk/provider v3 stable release
|
|
8
|
+
- Update LanguageModelUsage to nested structure (inputTokens.total, outputTokens.total, etc.)
|
|
9
|
+
- Update LanguageModelFinishReason to object with unified and raw properties
|
|
10
|
+
- Rename LanguageModelWarning to SharedWarning with updated structure
|
|
11
|
+
- Update tool type from "provider-defined" to "provider"
|
|
12
|
+
- Bump @ai-sdk peer dependencies from beta to stable (^3.0.3)
|
|
13
|
+
|
|
14
|
+
- 0040d4c: Add OAuth authentication support for OpenAI (Codex) and Anthropic providers
|
|
15
|
+
- Updated dependencies [884e513]
|
|
16
|
+
- Updated dependencies [0576a77]
|
|
17
|
+
- @kernl-sdk/protocol@0.5.1
|
|
18
|
+
- kernl@0.12.3
|
|
19
|
+
- @kernl-sdk/retrieval@0.1.10
|
|
20
|
+
|
|
21
|
+
## 0.4.3
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- 933998e: Add model ID types for autocomplete support in provider functions (anthropic, openai, google).
|
|
26
|
+
|
|
3
27
|
## 0.4.2
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
|
@@ -56,9 +56,8 @@ describe.skipIf(SKIP_OPENAI_TESTS)("AISDKLanguageModel - OpenAI", () => {
|
|
|
56
56
|
expect(response.content).toBeDefined();
|
|
57
57
|
expect(response.content.length).toBeGreaterThan(0);
|
|
58
58
|
expect(response.usage).toBeDefined();
|
|
59
|
-
expect(response.usage.
|
|
60
|
-
expect(response.usage.
|
|
61
|
-
expect(response.usage.outputTokens).toBeGreaterThan(0);
|
|
59
|
+
expect(response.usage.inputTokens.total).toBeGreaterThan(0);
|
|
60
|
+
expect(response.usage.outputTokens.total).toBeGreaterThan(0);
|
|
62
61
|
// Should have at least one message
|
|
63
62
|
const messages = response.content.filter((item) => item.kind === "message");
|
|
64
63
|
expect(messages.length).toBeGreaterThan(0);
|
|
@@ -90,7 +89,7 @@ describe.skipIf(SKIP_OPENAI_TESTS)("AISDKLanguageModel - OpenAI", () => {
|
|
|
90
89
|
},
|
|
91
90
|
});
|
|
92
91
|
expect(response.content).toBeDefined();
|
|
93
|
-
expect(response.usage.
|
|
92
|
+
expect(response.usage.inputTokens.total).toBeGreaterThan(0);
|
|
94
93
|
});
|
|
95
94
|
it("should handle multi-turn conversations", async () => {
|
|
96
95
|
const response = await gpt41.generate({
|
|
@@ -120,7 +119,7 @@ describe.skipIf(SKIP_OPENAI_TESTS)("AISDKLanguageModel - OpenAI", () => {
|
|
|
120
119
|
},
|
|
121
120
|
});
|
|
122
121
|
expect(response.content).toBeDefined();
|
|
123
|
-
expect(response.usage.
|
|
122
|
+
expect(response.usage.inputTokens.total).toBeGreaterThan(0);
|
|
124
123
|
// Check that it remembers the name (should mention Alice)
|
|
125
124
|
const assistantMessages = response.content.filter((item) => item.kind === "message" && item.role === "assistant");
|
|
126
125
|
expect(assistantMessages.length).toBeGreaterThan(0);
|
|
@@ -141,7 +140,7 @@ describe.skipIf(SKIP_OPENAI_TESTS)("AISDKLanguageModel - OpenAI", () => {
|
|
|
141
140
|
},
|
|
142
141
|
});
|
|
143
142
|
expect(response.content).toBeDefined();
|
|
144
|
-
expect(response.usage.
|
|
143
|
+
expect(response.usage.inputTokens.total).toBeGreaterThan(0);
|
|
145
144
|
});
|
|
146
145
|
it("should respect maxTokens setting", async () => {
|
|
147
146
|
const response = await gpt41.generate({
|
|
@@ -159,8 +158,8 @@ describe.skipIf(SKIP_OPENAI_TESTS)("AISDKLanguageModel - OpenAI", () => {
|
|
|
159
158
|
},
|
|
160
159
|
});
|
|
161
160
|
expect(response.content).toBeDefined();
|
|
162
|
-
expect(response.usage.outputTokens).toBeDefined();
|
|
163
|
-
expect(response.usage.outputTokens).toBeLessThanOrEqual(20);
|
|
161
|
+
expect(response.usage.outputTokens.total).toBeDefined();
|
|
162
|
+
expect(response.usage.outputTokens.total).toBeLessThanOrEqual(20);
|
|
164
163
|
});
|
|
165
164
|
});
|
|
166
165
|
describe("stream", () => {
|
|
@@ -189,7 +188,7 @@ describe.skipIf(SKIP_OPENAI_TESTS)("AISDKLanguageModel - OpenAI", () => {
|
|
|
189
188
|
// Should have usage information
|
|
190
189
|
const finishEvent = finishEvents[0];
|
|
191
190
|
expect(finishEvent.usage).toBeDefined();
|
|
192
|
-
expect(finishEvent.usage.
|
|
191
|
+
expect(finishEvent.usage.inputTokens.total).toBeGreaterThan(0);
|
|
193
192
|
});
|
|
194
193
|
it("should stream text deltas", async () => {
|
|
195
194
|
const events = [];
|
|
@@ -992,7 +991,7 @@ describe.skipIf(SKIP_GOOGLE_TESTS)("AISDKLanguageModel - Google", () => {
|
|
|
992
991
|
expect(response.content).toBeDefined();
|
|
993
992
|
expect(response.content.length).toBeGreaterThan(0);
|
|
994
993
|
expect(response.usage).toBeDefined();
|
|
995
|
-
expect(response.usage.
|
|
994
|
+
expect(response.usage.inputTokens.total).toBeGreaterThan(0);
|
|
996
995
|
const messages = response.content.filter((item) => item.kind === "message");
|
|
997
996
|
expect(messages.length).toBeGreaterThan(0);
|
|
998
997
|
});
|
|
@@ -1023,7 +1022,7 @@ describe.skipIf(SKIP_GOOGLE_TESTS)("AISDKLanguageModel - Google", () => {
|
|
|
1023
1022
|
// Should have usage information
|
|
1024
1023
|
const finishEvent = finishEvents[0];
|
|
1025
1024
|
expect(finishEvent.usage).toBeDefined();
|
|
1026
|
-
expect(finishEvent.usage.
|
|
1025
|
+
expect(finishEvent.usage.inputTokens.total).toBeGreaterThan(0);
|
|
1027
1026
|
});
|
|
1028
1027
|
});
|
|
1029
1028
|
describe("structured output", () => {
|
|
@@ -45,11 +45,10 @@ describe("AISDKLanguageModel", () => {
|
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
type: "finish",
|
|
48
|
-
finishReason: "stop",
|
|
48
|
+
finishReason: { unified: "stop", raw: "stop" },
|
|
49
49
|
usage: {
|
|
50
|
-
inputTokens: 5,
|
|
51
|
-
outputTokens: 10,
|
|
52
|
-
totalTokens: 15,
|
|
50
|
+
inputTokens: { total: 5, noCache: 5, cacheRead: undefined, cacheWrite: undefined },
|
|
51
|
+
outputTokens: { total: 10, text: 10, reasoning: undefined },
|
|
53
52
|
},
|
|
54
53
|
providerMetadata: undefined,
|
|
55
54
|
},
|
|
@@ -148,11 +147,10 @@ describe("AISDKLanguageModel", () => {
|
|
|
148
147
|
},
|
|
149
148
|
{
|
|
150
149
|
type: "finish",
|
|
151
|
-
finishReason: "stop",
|
|
150
|
+
finishReason: { unified: "stop", raw: "stop" },
|
|
152
151
|
usage: {
|
|
153
|
-
inputTokens: 5,
|
|
154
|
-
outputTokens: 20,
|
|
155
|
-
totalTokens: 25,
|
|
152
|
+
inputTokens: { total: 5, noCache: 5, cacheRead: undefined, cacheWrite: undefined },
|
|
153
|
+
outputTokens: { total: 20, text: 20, reasoning: undefined },
|
|
156
154
|
},
|
|
157
155
|
providerMetadata: undefined,
|
|
158
156
|
},
|
|
@@ -248,11 +246,10 @@ describe("AISDKLanguageModel", () => {
|
|
|
248
246
|
},
|
|
249
247
|
{
|
|
250
248
|
type: "finish",
|
|
251
|
-
finishReason: "stop",
|
|
249
|
+
finishReason: { unified: "stop", raw: "stop" },
|
|
252
250
|
usage: {
|
|
253
|
-
inputTokens: 5,
|
|
254
|
-
outputTokens: 10,
|
|
255
|
-
totalTokens: 15,
|
|
251
|
+
inputTokens: { total: 5, noCache: 5, cacheRead: undefined, cacheWrite: undefined },
|
|
252
|
+
outputTokens: { total: 10, text: 10, reasoning: undefined },
|
|
256
253
|
},
|
|
257
254
|
providerMetadata: undefined,
|
|
258
255
|
},
|
|
@@ -322,11 +319,10 @@ describe("AISDKLanguageModel", () => {
|
|
|
322
319
|
},
|
|
323
320
|
{
|
|
324
321
|
type: "finish",
|
|
325
|
-
finishReason: "stop",
|
|
322
|
+
finishReason: { unified: "stop", raw: "stop" },
|
|
326
323
|
usage: {
|
|
327
|
-
inputTokens: 5,
|
|
328
|
-
outputTokens: 10,
|
|
329
|
-
totalTokens: 15,
|
|
324
|
+
inputTokens: { total: 5, noCache: 5, cacheRead: undefined, cacheWrite: undefined },
|
|
325
|
+
outputTokens: { total: 10, text: 10, reasoning: undefined },
|
|
330
326
|
},
|
|
331
327
|
providerMetadata: undefined,
|
|
332
328
|
},
|
|
@@ -377,11 +373,10 @@ describe("AISDKLanguageModel", () => {
|
|
|
377
373
|
},
|
|
378
374
|
{
|
|
379
375
|
type: "finish",
|
|
380
|
-
finishReason: "tool-calls",
|
|
376
|
+
finishReason: { unified: "tool-calls", raw: "tool_calls" },
|
|
381
377
|
usage: {
|
|
382
|
-
inputTokens: 5,
|
|
383
|
-
outputTokens: 10,
|
|
384
|
-
totalTokens: 15,
|
|
378
|
+
inputTokens: { total: 5, noCache: 5, cacheRead: undefined, cacheWrite: undefined },
|
|
379
|
+
outputTokens: { total: 10, text: 10, reasoning: undefined },
|
|
385
380
|
},
|
|
386
381
|
providerMetadata: undefined,
|
|
387
382
|
},
|
|
@@ -2,39 +2,41 @@ import { describe, it, expect } from "vitest";
|
|
|
2
2
|
import { WARNING } from "../response.js";
|
|
3
3
|
describe("WARNING codec", () => {
|
|
4
4
|
describe("decode", () => {
|
|
5
|
-
it("should decode unsupported
|
|
5
|
+
it("should decode unsupported warning", () => {
|
|
6
6
|
const aiWarning = {
|
|
7
|
-
type: "unsupported
|
|
8
|
-
|
|
9
|
-
details: "This
|
|
7
|
+
type: "unsupported",
|
|
8
|
+
feature: "someUnsupportedFeature",
|
|
9
|
+
details: "This feature is not supported by the provider",
|
|
10
10
|
};
|
|
11
11
|
const result = WARNING.decode(aiWarning);
|
|
12
12
|
expect(result).toEqual({
|
|
13
|
-
type: "unsupported
|
|
14
|
-
|
|
15
|
-
details: "This
|
|
13
|
+
type: "unsupported",
|
|
14
|
+
feature: "someUnsupportedFeature",
|
|
15
|
+
details: "This feature is not supported by the provider",
|
|
16
16
|
});
|
|
17
17
|
});
|
|
18
|
-
it("should decode
|
|
18
|
+
it("should decode compatibility warning", () => {
|
|
19
19
|
const aiWarning = {
|
|
20
|
-
type: "
|
|
21
|
-
|
|
20
|
+
type: "compatibility",
|
|
21
|
+
feature: "someFeature",
|
|
22
|
+
details: "Running in compatibility mode",
|
|
22
23
|
};
|
|
23
24
|
const result = WARNING.decode(aiWarning);
|
|
24
25
|
expect(result).toEqual({
|
|
25
|
-
type: "
|
|
26
|
-
|
|
26
|
+
type: "compatibility",
|
|
27
|
+
feature: "someFeature",
|
|
28
|
+
details: "Running in compatibility mode",
|
|
27
29
|
});
|
|
28
30
|
});
|
|
29
|
-
it("should
|
|
31
|
+
it("should decode other warning", () => {
|
|
30
32
|
const aiWarning = {
|
|
31
|
-
type: "
|
|
32
|
-
|
|
33
|
+
type: "other",
|
|
34
|
+
message: "Some custom warning message",
|
|
33
35
|
};
|
|
34
36
|
const result = WARNING.decode(aiWarning);
|
|
35
37
|
expect(result).toEqual({
|
|
36
38
|
type: "other",
|
|
37
|
-
message: "
|
|
39
|
+
message: "Some custom warning message",
|
|
38
40
|
});
|
|
39
41
|
});
|
|
40
42
|
});
|
|
@@ -217,8 +217,8 @@ describe("STREAM_PART codec", () => {
|
|
|
217
217
|
type: "stream-start",
|
|
218
218
|
warnings: [
|
|
219
219
|
{
|
|
220
|
-
type: "unsupported
|
|
221
|
-
|
|
220
|
+
type: "unsupported",
|
|
221
|
+
feature: "topK",
|
|
222
222
|
},
|
|
223
223
|
],
|
|
224
224
|
};
|
|
@@ -227,9 +227,8 @@ describe("STREAM_PART codec", () => {
|
|
|
227
227
|
kind: "stream.start",
|
|
228
228
|
warnings: [
|
|
229
229
|
{
|
|
230
|
-
type: "unsupported
|
|
231
|
-
|
|
232
|
-
details: undefined,
|
|
230
|
+
type: "unsupported",
|
|
231
|
+
feature: "topK",
|
|
233
232
|
},
|
|
234
233
|
],
|
|
235
234
|
});
|
|
@@ -237,24 +236,20 @@ describe("STREAM_PART codec", () => {
|
|
|
237
236
|
it("should decode finish event", () => {
|
|
238
237
|
const part = {
|
|
239
238
|
type: "finish",
|
|
240
|
-
finishReason: "stop",
|
|
239
|
+
finishReason: { unified: "stop", raw: "stop" },
|
|
241
240
|
usage: {
|
|
242
|
-
inputTokens: 10,
|
|
243
|
-
outputTokens: 20,
|
|
244
|
-
totalTokens: 30,
|
|
241
|
+
inputTokens: { total: 10, noCache: 8, cacheRead: 2, cacheWrite: undefined },
|
|
242
|
+
outputTokens: { total: 20, text: 18, reasoning: 2 },
|
|
245
243
|
},
|
|
246
244
|
providerMetadata: undefined,
|
|
247
245
|
};
|
|
248
246
|
const result = STREAM_PART.decode(part);
|
|
249
247
|
expect(result).toEqual({
|
|
250
248
|
kind: "finish",
|
|
251
|
-
finishReason: "stop",
|
|
249
|
+
finishReason: { unified: "stop", raw: "stop" },
|
|
252
250
|
usage: {
|
|
253
|
-
inputTokens: 10,
|
|
254
|
-
outputTokens: 20,
|
|
255
|
-
totalTokens: 30,
|
|
256
|
-
reasoningTokens: undefined,
|
|
257
|
-
cachedInputTokens: undefined,
|
|
251
|
+
inputTokens: { total: 10, noCache: 8, cacheRead: 2, cacheWrite: undefined },
|
|
252
|
+
outputTokens: { total: 20, text: 18, reasoning: 2 },
|
|
258
253
|
},
|
|
259
254
|
providerMetadata: undefined,
|
|
260
255
|
});
|
|
@@ -341,8 +336,11 @@ describe("convertStream", () => {
|
|
|
341
336
|
{ type: "text-end", id: "text-1", providerMetadata: undefined },
|
|
342
337
|
{
|
|
343
338
|
type: "finish",
|
|
344
|
-
finishReason: "stop",
|
|
345
|
-
usage: {
|
|
339
|
+
finishReason: { unified: "stop", raw: "stop" },
|
|
340
|
+
usage: {
|
|
341
|
+
inputTokens: { total: 5, noCache: 5, cacheRead: undefined, cacheWrite: undefined },
|
|
342
|
+
outputTokens: { total: 10, text: 10, reasoning: undefined },
|
|
343
|
+
},
|
|
346
344
|
providerMetadata: undefined,
|
|
347
345
|
},
|
|
348
346
|
];
|
|
@@ -362,7 +360,7 @@ describe("convertStream", () => {
|
|
|
362
360
|
expect(events[0]).toMatchObject({ kind: "text.start" });
|
|
363
361
|
expect(events[1]).toMatchObject({ kind: "text.delta", text: "Hello" });
|
|
364
362
|
expect(events[2]).toMatchObject({ kind: "text.end" });
|
|
365
|
-
expect(events[3]).toMatchObject({ kind: "finish", finishReason: "stop" });
|
|
363
|
+
expect(events[3]).toMatchObject({ kind: "finish", finishReason: { unified: "stop", raw: "stop" } });
|
|
366
364
|
});
|
|
367
365
|
it("should filter out null events", async () => {
|
|
368
366
|
const parts = [
|
|
@@ -377,8 +375,11 @@ describe("convertStream", () => {
|
|
|
377
375
|
}, // This should be filtered out (returns null from default case)
|
|
378
376
|
{
|
|
379
377
|
type: "finish",
|
|
380
|
-
finishReason: "stop",
|
|
381
|
-
usage: {
|
|
378
|
+
finishReason: { unified: "stop", raw: "stop" },
|
|
379
|
+
usage: {
|
|
380
|
+
inputTokens: { total: 5, noCache: 5, cacheRead: undefined, cacheWrite: undefined },
|
|
381
|
+
outputTokens: { total: 10, text: 10, reasoning: undefined },
|
|
382
|
+
},
|
|
382
383
|
providerMetadata: undefined,
|
|
383
384
|
},
|
|
384
385
|
];
|
|
@@ -83,8 +83,8 @@ describe("TOOL codec", () => {
|
|
|
83
83
|
}
|
|
84
84
|
});
|
|
85
85
|
});
|
|
86
|
-
describe("encode - provider
|
|
87
|
-
it("should encode provider
|
|
86
|
+
describe("encode - provider tools", () => {
|
|
87
|
+
it("should encode provider tool", () => {
|
|
88
88
|
const result = TOOL.encode({
|
|
89
89
|
kind: "provider-defined",
|
|
90
90
|
id: "mcp.tool-123",
|
|
@@ -92,13 +92,13 @@ describe("TOOL codec", () => {
|
|
|
92
92
|
args: { param1: "value1" },
|
|
93
93
|
});
|
|
94
94
|
expect(result).toEqual({
|
|
95
|
-
type: "provider
|
|
95
|
+
type: "provider",
|
|
96
96
|
id: "mcp.tool-123",
|
|
97
97
|
name: "custom_mcp_tool",
|
|
98
98
|
args: { param1: "value1" },
|
|
99
99
|
});
|
|
100
100
|
});
|
|
101
|
-
it("should encode provider
|
|
101
|
+
it("should encode provider tool without args", () => {
|
|
102
102
|
const result = TOOL.encode({
|
|
103
103
|
kind: "provider-defined",
|
|
104
104
|
id: "mcp.tool-id",
|
|
@@ -106,7 +106,7 @@ describe("TOOL codec", () => {
|
|
|
106
106
|
args: {},
|
|
107
107
|
});
|
|
108
108
|
expect(result).toEqual({
|
|
109
|
-
type: "provider
|
|
109
|
+
type: "provider",
|
|
110
110
|
id: "mcp.tool-id",
|
|
111
111
|
name: "tool_name",
|
|
112
112
|
args: {},
|
|
@@ -222,11 +222,10 @@ describe("STREAM_UI_PART codec", () => {
|
|
|
222
222
|
it("should encode finish event", () => {
|
|
223
223
|
const event = {
|
|
224
224
|
kind: "finish",
|
|
225
|
-
finishReason: "stop",
|
|
225
|
+
finishReason: { unified: "stop", raw: "stop" },
|
|
226
226
|
usage: {
|
|
227
|
-
inputTokens: 100,
|
|
228
|
-
outputTokens: 50,
|
|
229
|
-
totalTokens: 150,
|
|
227
|
+
inputTokens: { total: 100, noCache: 100, cacheRead: undefined, cacheWrite: undefined },
|
|
228
|
+
outputTokens: { total: 50, text: 50, reasoning: undefined },
|
|
230
229
|
},
|
|
231
230
|
};
|
|
232
231
|
const result = STREAM_UI_PART.encode(event);
|
|
@@ -341,7 +340,14 @@ describe("toUIMessageStream", () => {
|
|
|
341
340
|
{ kind: "text.delta", id: "text-1", text: "Hello" },
|
|
342
341
|
{ kind: "text.delta", id: "text-1", text: " world" },
|
|
343
342
|
{ kind: "text.end", id: "text-1" },
|
|
344
|
-
{
|
|
343
|
+
{
|
|
344
|
+
kind: "finish",
|
|
345
|
+
finishReason: { unified: "stop", raw: "stop" },
|
|
346
|
+
usage: {
|
|
347
|
+
inputTokens: { total: 10, noCache: 10, cacheRead: undefined, cacheWrite: undefined },
|
|
348
|
+
outputTokens: { total: 5, text: 5, reasoning: undefined },
|
|
349
|
+
},
|
|
350
|
+
},
|
|
345
351
|
];
|
|
346
352
|
async function* generateEvents() {
|
|
347
353
|
for (const event of events) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Codec } from "@kernl-sdk/shared/lib";
|
|
2
|
-
import { type LanguageModelResponse, type LanguageModelResponseType, type
|
|
3
|
-
import type { LanguageModelV3Content, LanguageModelV3FinishReason, LanguageModelV3Usage,
|
|
2
|
+
import { type LanguageModelResponse, type LanguageModelResponseType, type SharedWarning } from "@kernl-sdk/protocol";
|
|
3
|
+
import type { LanguageModelV3Content, LanguageModelV3FinishReason, LanguageModelV3Usage, SharedV3Warning, JSONSchema7 } from "@ai-sdk/provider";
|
|
4
4
|
/**
|
|
5
5
|
* AI SDK generate result structure
|
|
6
6
|
*/
|
|
@@ -9,10 +9,10 @@ export interface AISdkGenerateResult {
|
|
|
9
9
|
finishReason: LanguageModelV3FinishReason;
|
|
10
10
|
usage: LanguageModelV3Usage;
|
|
11
11
|
providerMetadata?: Record<string, unknown>;
|
|
12
|
-
warnings: Array<
|
|
12
|
+
warnings: Array<SharedV3Warning>;
|
|
13
13
|
}
|
|
14
14
|
export declare const MODEL_RESPONSE: Codec<LanguageModelResponse, AISdkGenerateResult>;
|
|
15
|
-
export declare const WARNING: Codec<
|
|
15
|
+
export declare const WARNING: Codec<SharedWarning, SharedV3Warning>;
|
|
16
16
|
/**
|
|
17
17
|
* AI SDK response format type.
|
|
18
18
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../src/convert/response.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAIL,KAAK,qBAAqB,EAE1B,KAAK,yBAAyB,EAG9B,KAAK,
|
|
1
|
+
{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../src/convert/response.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAIL,KAAK,qBAAqB,EAE1B,KAAK,yBAAyB,EAG9B,KAAK,aAAa,EAEnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EACV,sBAAsB,EACtB,2BAA2B,EAC3B,oBAAoB,EACpB,eAAe,EACf,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAE1B;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACvC,YAAY,EAAE,2BAA2B,CAAC;IAC1C,KAAK,EAAE,oBAAoB,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,QAAQ,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;CAClC;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,qBAAqB,EAAE,mBAAmB,CAiG1E,CAAC;AAmBJ,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,aAAa,EAAE,eAAe,CAKzD,CAAC;AAEF;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CACjC,yBAAyB,GAAG,SAAS,EACrC,mBAAmB,GAAG,SAAS,CAiBhC,CAAC"}
|
package/dist/convert/response.js
CHANGED
|
@@ -102,26 +102,7 @@ export const WARNING = {
|
|
|
102
102
|
encode: () => {
|
|
103
103
|
throw new Error("codec:unimplemented");
|
|
104
104
|
},
|
|
105
|
-
decode: (warning) =>
|
|
106
|
-
switch (warning.type) {
|
|
107
|
-
case "unsupported-setting":
|
|
108
|
-
return {
|
|
109
|
-
type: "unsupported-setting",
|
|
110
|
-
setting: warning.setting,
|
|
111
|
-
details: warning.details,
|
|
112
|
-
};
|
|
113
|
-
case "other":
|
|
114
|
-
return {
|
|
115
|
-
type: "other",
|
|
116
|
-
message: warning.message,
|
|
117
|
-
};
|
|
118
|
-
default:
|
|
119
|
-
return {
|
|
120
|
-
type: "other",
|
|
121
|
-
message: "Unknown warning type",
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
},
|
|
105
|
+
decode: (warning) => warning,
|
|
125
106
|
};
|
|
126
107
|
/**
|
|
127
108
|
* Codec for converting protocol responseType to AI SDK responseFormat.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/convert/stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EACL,KAAK,wBAAwB,EAI9B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAIlE;;GAEG;AACH,wBAAuB,aAAa,CAClC,MAAM,EAAE,cAAc,CAAC,yBAAyB,CAAC,GAChD,aAAa,CAAC,wBAAwB,CAAC,CAgBzC;AAED;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,KAAK,CAC7B,wBAAwB,GAAG,IAAI,EAC/B,yBAAyB,
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/convert/stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EACL,KAAK,wBAAwB,EAI9B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAIlE;;GAEG;AACH,wBAAuB,aAAa,CAClC,MAAM,EAAE,cAAc,CAAC,yBAAyB,CAAC,GAChD,aAAa,CAAC,wBAAwB,CAAC,CAgBzC;AAED;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,KAAK,CAC7B,wBAAwB,GAAG,IAAI,EAC/B,yBAAyB,CA8I1B,CAAC"}
|
package/dist/convert/stream.js
CHANGED
|
@@ -117,13 +117,7 @@ export const STREAM_PART = {
|
|
|
117
117
|
return {
|
|
118
118
|
kind: "finish",
|
|
119
119
|
finishReason: part.finishReason, // Types should match
|
|
120
|
-
usage:
|
|
121
|
-
inputTokens: part.usage.inputTokens,
|
|
122
|
-
outputTokens: part.usage.outputTokens,
|
|
123
|
-
totalTokens: part.usage.totalTokens,
|
|
124
|
-
reasoningTokens: part.usage.reasoningTokens,
|
|
125
|
-
cachedInputTokens: part.usage.cachedInputTokens,
|
|
126
|
-
},
|
|
120
|
+
usage: part.usage,
|
|
127
121
|
providerMetadata: part.providerMetadata,
|
|
128
122
|
};
|
|
129
123
|
case "error":
|
package/dist/convert/tools.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Codec } from "@kernl-sdk/shared/lib";
|
|
2
2
|
import type { LanguageModelTool, LanguageModelToolChoice } from "@kernl-sdk/protocol";
|
|
3
|
-
import type { LanguageModelV3FunctionTool,
|
|
4
|
-
export declare const TOOL: Codec<LanguageModelTool, LanguageModelV3FunctionTool |
|
|
3
|
+
import type { LanguageModelV3FunctionTool, LanguageModelV3ProviderTool, LanguageModelV3ToolChoice } from "@ai-sdk/provider";
|
|
4
|
+
export declare const TOOL: Codec<LanguageModelTool, LanguageModelV3FunctionTool | LanguageModelV3ProviderTool>;
|
|
5
5
|
export declare const TOOL_CHOICE: Codec<LanguageModelToolChoice, LanguageModelV3ToolChoice>;
|
|
6
6
|
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/convert/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EACV,iBAAiB,EACjB,uBAAuB,EACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EACV,2BAA2B,EAC3B,
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/convert/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EACV,iBAAiB,EACjB,uBAAuB,EACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EACV,2BAA2B,EAC3B,2BAA2B,EAC3B,yBAAyB,EAC1B,MAAM,kBAAkB,CAAC;AAE1B,eAAO,MAAM,IAAI,EAAE,KAAK,CACtB,iBAAiB,EACjB,2BAA2B,GAAG,2BAA2B,CAwB1D,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAAK,CAC7B,uBAAuB,EACvB,yBAAyB,CAiB1B,CAAC"}
|
package/dist/convert/tools.js
CHANGED
|
@@ -3,14 +3,14 @@ import type { EmbeddingModel, EmbeddingModelRequest, EmbeddingModelResponse } fr
|
|
|
3
3
|
/**
|
|
4
4
|
* EmbeddingModel adapter for the AI SDK EmbeddingModelV3.
|
|
5
5
|
*/
|
|
6
|
-
export declare class AISDKEmbeddingModel
|
|
6
|
+
export declare class AISDKEmbeddingModel implements EmbeddingModel<string> {
|
|
7
7
|
private model;
|
|
8
8
|
readonly spec: "1.0";
|
|
9
9
|
readonly provider: string;
|
|
10
10
|
readonly modelId: string;
|
|
11
11
|
readonly maxEmbeddingsPerCall?: number;
|
|
12
12
|
readonly supportsParallelCalls?: boolean;
|
|
13
|
-
constructor(model: EmbeddingModelV3
|
|
14
|
-
embed(request: EmbeddingModelRequest<
|
|
13
|
+
constructor(model: EmbeddingModelV3);
|
|
14
|
+
embed(request: EmbeddingModelRequest<string>): Promise<EmbeddingModelResponse>;
|
|
15
15
|
}
|
|
16
16
|
//# sourceMappingURL=embedding-model.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embedding-model.d.ts","sourceRoot":"","sources":["../src/embedding-model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,qBAAqB,CAAC;AAI7B;;GAEG;AACH,qBAAa,
|
|
1
|
+
{"version":3,"file":"embedding-model.d.ts","sourceRoot":"","sources":["../src/embedding-model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,qBAAqB,CAAC;AAI7B;;GAEG;AACH,qBAAa,mBAAoB,YAAW,cAAc,CAAC,MAAM,CAAC;IAOpD,OAAO,CAAC,KAAK;IANzB,QAAQ,CAAC,IAAI,EAAG,KAAK,CAAU;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IACvC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;gBAErB,KAAK,EAAE,gBAAgB;IAarC,KAAK,CACT,OAAO,EAAE,qBAAqB,CAAC,MAAM,CAAC,GACrC,OAAO,CAAC,sBAAsB,CAAC;CAiBnC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { OAuthCredentials } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Create a fetch wrapper for Anthropic OAuth.
|
|
4
|
+
*
|
|
5
|
+
* Uses the standard Anthropic API with OAuth bearer token.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createOAuthFetch(creds: OAuthCredentials): (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
8
|
+
//# sourceMappingURL=anthropic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/oauth/anthropic.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAoDhD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,IAEpD,OAAO,MAAM,GAAG,GAAG,GAAG,OAAO,EAC7B,OAAO,WAAW,KACjB,OAAO,CAAC,QAAQ,CAAC,CAwBrB"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { appendFileSync } from "node:fs";
|
|
2
|
+
const TOKEN_URL = "https://console.anthropic.com/v1/oauth/token";
|
|
3
|
+
const CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
|
|
4
|
+
function debug(msg) {
|
|
5
|
+
try {
|
|
6
|
+
appendFileSync("/tmp/popcorn-debug.log", `${new Date().toISOString()} [oauth/anthropic] ${msg}\n`);
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
// ignore
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Refresh Anthropic OAuth tokens.
|
|
14
|
+
*/
|
|
15
|
+
async function refresh(creds) {
|
|
16
|
+
debug(`Refreshing token...`);
|
|
17
|
+
const res = await fetch(TOKEN_URL, {
|
|
18
|
+
method: "POST",
|
|
19
|
+
headers: { "Content-Type": "application/json" },
|
|
20
|
+
body: JSON.stringify({
|
|
21
|
+
grant_type: "refresh_token",
|
|
22
|
+
refresh_token: creds.refreshToken,
|
|
23
|
+
client_id: CLIENT_ID,
|
|
24
|
+
}),
|
|
25
|
+
});
|
|
26
|
+
if (!res.ok) {
|
|
27
|
+
throw new Error(`Token refresh failed: ${res.status}`);
|
|
28
|
+
}
|
|
29
|
+
const data = (await res.json());
|
|
30
|
+
creds.accessToken = data.access_token;
|
|
31
|
+
creds.refreshToken = data.refresh_token;
|
|
32
|
+
creds.expiresAt = Date.now() + data.expires_in * 1000;
|
|
33
|
+
creds.onRefresh?.({
|
|
34
|
+
accessToken: creds.accessToken,
|
|
35
|
+
refreshToken: creds.refreshToken,
|
|
36
|
+
expiresAt: creds.expiresAt,
|
|
37
|
+
});
|
|
38
|
+
debug(`Token refreshed successfully`);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Create a fetch wrapper for Anthropic OAuth.
|
|
42
|
+
*
|
|
43
|
+
* Uses the standard Anthropic API with OAuth bearer token.
|
|
44
|
+
*/
|
|
45
|
+
export function createOAuthFetch(creds) {
|
|
46
|
+
return async (input, init) => {
|
|
47
|
+
// Refresh if expired (with 30s buffer)
|
|
48
|
+
if (Date.now() >= creds.expiresAt - 30_000) {
|
|
49
|
+
await refresh(creds);
|
|
50
|
+
}
|
|
51
|
+
const headers = new Headers(init?.headers);
|
|
52
|
+
headers.set("Authorization", `Bearer ${creds.accessToken}`);
|
|
53
|
+
// Required beta header for OAuth
|
|
54
|
+
headers.set("anthropic-beta", "oauth-2025-04-20");
|
|
55
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
56
|
+
debug(`Request to: ${url}`);
|
|
57
|
+
const response = await fetch(input, { ...init, headers });
|
|
58
|
+
debug(`Response status: ${response.status}`);
|
|
59
|
+
if (!response.ok) {
|
|
60
|
+
const text = await response.clone().text();
|
|
61
|
+
debug(`Error response: ${text.slice(0, 1000)}`);
|
|
62
|
+
}
|
|
63
|
+
return response;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { OpenAIOAuthCredentials } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Create a fetch wrapper for OpenAI Codex OAuth.
|
|
4
|
+
*
|
|
5
|
+
* Redirects all requests to the Codex endpoint and adds OAuth headers.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createOAuthFetch(creds: OpenAIOAuthCredentials): (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
8
|
+
//# sourceMappingURL=openai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/oauth/openai.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAsDtD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,sBAAsB,IAE1D,OAAO,MAAM,GAAG,GAAG,GAAG,OAAO,EAC7B,OAAO,WAAW,KACjB,OAAO,CAAC,QAAQ,CAAC,CAgErB"}
|