@copilotkit/runtime 1.52.0-next.8 → 1.52.1-next.0
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/CHANGELOG.md +28 -0
- package/dist/index.cjs +2 -0
- package/dist/index.d.cts +2 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +2 -1
- package/dist/lib/runtime/copilot-runtime.cjs +4 -1
- package/dist/lib/runtime/copilot-runtime.cjs.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.cts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.mts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.mjs +4 -1
- package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
- package/dist/package.cjs +4 -1
- package/dist/package.mjs +4 -1
- package/dist/service-adapters/anthropic/anthropic-adapter.cjs +12 -0
- package/dist/service-adapters/anthropic/anthropic-adapter.cjs.map +1 -1
- package/dist/service-adapters/anthropic/anthropic-adapter.d.cts +2 -0
- package/dist/service-adapters/anthropic/anthropic-adapter.d.cts.map +1 -1
- package/dist/service-adapters/anthropic/anthropic-adapter.d.mts +2 -0
- package/dist/service-adapters/anthropic/anthropic-adapter.d.mts.map +1 -1
- package/dist/service-adapters/anthropic/anthropic-adapter.mjs +12 -0
- package/dist/service-adapters/anthropic/anthropic-adapter.mjs.map +1 -1
- package/dist/service-adapters/groq/groq-adapter.cjs +13 -0
- package/dist/service-adapters/groq/groq-adapter.cjs.map +1 -1
- package/dist/service-adapters/groq/groq-adapter.d.cts +2 -0
- package/dist/service-adapters/groq/groq-adapter.d.cts.map +1 -1
- package/dist/service-adapters/groq/groq-adapter.d.mts +2 -0
- package/dist/service-adapters/groq/groq-adapter.d.mts.map +1 -1
- package/dist/service-adapters/groq/groq-adapter.mjs +13 -0
- package/dist/service-adapters/groq/groq-adapter.mjs.map +1 -1
- package/dist/service-adapters/index.d.cts +1 -0
- package/dist/service-adapters/index.d.mts +1 -0
- package/dist/service-adapters/openai/openai-adapter.cjs +14 -0
- package/dist/service-adapters/openai/openai-adapter.cjs.map +1 -1
- package/dist/service-adapters/openai/openai-adapter.d.cts +2 -0
- package/dist/service-adapters/openai/openai-adapter.d.cts.map +1 -1
- package/dist/service-adapters/openai/openai-adapter.d.mts +2 -0
- package/dist/service-adapters/openai/openai-adapter.d.mts.map +1 -1
- package/dist/service-adapters/openai/openai-adapter.mjs +14 -0
- package/dist/service-adapters/openai/openai-adapter.mjs.map +1 -1
- package/dist/service-adapters/service-adapter.d.cts +8 -0
- package/dist/service-adapters/service-adapter.d.cts.map +1 -1
- package/dist/service-adapters/service-adapter.d.mts +8 -0
- package/dist/service-adapters/service-adapter.d.mts.map +1 -1
- package/dist/service-adapters/shared/index.d.mts +2 -1
- package/dist/service-adapters/shared/sdk-client-utils.cjs +17 -0
- package/dist/service-adapters/shared/sdk-client-utils.cjs.map +1 -0
- package/dist/service-adapters/shared/sdk-client-utils.d.cts +14 -0
- package/dist/service-adapters/shared/sdk-client-utils.d.cts.map +1 -0
- package/dist/service-adapters/shared/sdk-client-utils.d.mts +14 -0
- package/dist/service-adapters/shared/sdk-client-utils.d.mts.map +1 -0
- package/dist/service-adapters/shared/sdk-client-utils.mjs +16 -0
- package/dist/service-adapters/shared/sdk-client-utils.mjs.map +1 -0
- package/package.json +9 -6
- package/src/lib/runtime/copilot-runtime.ts +4 -3
- package/src/service-adapters/anthropic/anthropic-adapter.ts +15 -1
- package/src/service-adapters/groq/groq-adapter.ts +16 -1
- package/src/service-adapters/openai/openai-adapter.ts +17 -1
- package/src/service-adapters/service-adapter.ts +9 -0
- package/src/service-adapters/shared/index.ts +1 -0
- package/src/service-adapters/shared/sdk-client-utils.ts +19 -0
- package/tests/service-adapters/anthropic/anthropic-adapter-language-model.test.ts +101 -0
- package/tests/service-adapters/groq/groq-adapter-language-model.test.ts +102 -0
- package/tests/service-adapters/openai/openai-adapter-language-model.test.ts +122 -0
- package/tests/service-adapters/shared/sdk-client-utils.test.ts +36 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import type { OpenAIProviderSettings } from "@ai-sdk/openai";
|
|
3
|
+
import { GroqAdapter } from "../../../src/service-adapters/groq/groq-adapter";
|
|
4
|
+
import { Groq } from "groq-sdk";
|
|
5
|
+
|
|
6
|
+
// Groq uses createOpenAI (OpenAI-compatible API), so we check against
|
|
7
|
+
// OpenAIProviderSettings. Same exhaustiveness guard as the OpenAI test.
|
|
8
|
+
type ForwardedGroqKeys = "baseURL" | "apiKey" | "headers" | "fetch";
|
|
9
|
+
|
|
10
|
+
// Keys we set ourselves or that don't apply to Groq.
|
|
11
|
+
type ControlledGroqKeys = "name" | "organization" | "project";
|
|
12
|
+
|
|
13
|
+
type _exhaustive =
|
|
14
|
+
Exclude<
|
|
15
|
+
keyof OpenAIProviderSettings,
|
|
16
|
+
ForwardedGroqKeys | ControlledGroqKeys
|
|
17
|
+
> extends never
|
|
18
|
+
? true
|
|
19
|
+
: {
|
|
20
|
+
error: "OpenAIProviderSettings has unhandled keys";
|
|
21
|
+
unhandled: Exclude<
|
|
22
|
+
keyof OpenAIProviderSettings,
|
|
23
|
+
ForwardedGroqKeys | ControlledGroqKeys
|
|
24
|
+
>;
|
|
25
|
+
};
|
|
26
|
+
const _check: _exhaustive = true;
|
|
27
|
+
|
|
28
|
+
const { mockProviderFn, mockCreateOpenAI } = vi.hoisted(() => {
|
|
29
|
+
const mockProviderFn = vi.fn().mockReturnValue({ modelId: "test-model" });
|
|
30
|
+
const mockCreateOpenAI = vi.fn().mockReturnValue(mockProviderFn);
|
|
31
|
+
return { mockProviderFn, mockCreateOpenAI };
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
vi.mock("@ai-sdk/openai", async (importOriginal) => {
|
|
35
|
+
const actual = await importOriginal<typeof import("@ai-sdk/openai")>();
|
|
36
|
+
return { ...actual, createOpenAI: mockCreateOpenAI };
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
vi.mock("groq-sdk", () => {
|
|
40
|
+
return {
|
|
41
|
+
Groq: class MockGroq {
|
|
42
|
+
baseURL: string;
|
|
43
|
+
apiKey: string;
|
|
44
|
+
_options: Record<string, any>;
|
|
45
|
+
chat = { completions: { create: vi.fn() } };
|
|
46
|
+
|
|
47
|
+
constructor(opts: any = {}) {
|
|
48
|
+
this.baseURL = opts.baseURL ?? "https://api.groq.com";
|
|
49
|
+
this.apiKey = opts.apiKey ?? "default-key";
|
|
50
|
+
this._options = {
|
|
51
|
+
defaultHeaders: opts.defaultHeaders,
|
|
52
|
+
fetch: opts.fetch,
|
|
53
|
+
...opts,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe("GroqAdapter.getLanguageModel()", () => {
|
|
61
|
+
beforeEach(() => {
|
|
62
|
+
vi.clearAllMocks();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("forwards all provider-relevant options from the Groq SDK client", () => {
|
|
66
|
+
const customFetch = vi.fn();
|
|
67
|
+
const groq = new Groq({
|
|
68
|
+
apiKey: "gsk-test",
|
|
69
|
+
baseURL: "https://custom-groq.example.com",
|
|
70
|
+
defaultHeaders: { "x-groq": "value" },
|
|
71
|
+
fetch: customFetch,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const adapter = new GroqAdapter({
|
|
75
|
+
groq,
|
|
76
|
+
model: "llama-3.3-70b-versatile",
|
|
77
|
+
});
|
|
78
|
+
adapter.getLanguageModel();
|
|
79
|
+
|
|
80
|
+
expect(mockCreateOpenAI).toHaveBeenCalledOnce();
|
|
81
|
+
const settings = mockCreateOpenAI.mock.calls[0][0];
|
|
82
|
+
|
|
83
|
+
expect(settings.baseURL).toBe("https://custom-groq.example.com");
|
|
84
|
+
expect(settings.apiKey).toBe("gsk-test");
|
|
85
|
+
expect(settings.headers).toEqual({ "x-groq": "value" });
|
|
86
|
+
expect(settings.fetch).toBe(customFetch);
|
|
87
|
+
expect(settings.name).toBe("groq");
|
|
88
|
+
|
|
89
|
+
expect(mockProviderFn).toHaveBeenCalledWith("llama-3.3-70b-versatile");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("works with default Groq config (no custom options)", () => {
|
|
93
|
+
const groq = new Groq({ apiKey: "gsk-default" });
|
|
94
|
+
const adapter = new GroqAdapter({ groq });
|
|
95
|
+
adapter.getLanguageModel();
|
|
96
|
+
|
|
97
|
+
const settings = mockCreateOpenAI.mock.calls[0][0];
|
|
98
|
+
expect(settings.baseURL).toBe("https://api.groq.com");
|
|
99
|
+
expect(settings.apiKey).toBe("gsk-default");
|
|
100
|
+
expect(settings.name).toBe("groq");
|
|
101
|
+
});
|
|
102
|
+
});
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import type { OpenAIProviderSettings } from "@ai-sdk/openai";
|
|
3
|
+
import { OpenAIAdapter } from "../../../src/service-adapters/openai/openai-adapter";
|
|
4
|
+
import OpenAI from "openai";
|
|
5
|
+
|
|
6
|
+
// Keys from OpenAIProviderSettings that we forward from the OpenAI SDK client.
|
|
7
|
+
// If @ai-sdk/openai adds new keys, the type assertion below will fail at
|
|
8
|
+
// compile time, forcing us to decide whether to forward them.
|
|
9
|
+
type ForwardedOpenAIKeys =
|
|
10
|
+
| "baseURL"
|
|
11
|
+
| "apiKey"
|
|
12
|
+
| "organization"
|
|
13
|
+
| "project"
|
|
14
|
+
| "headers"
|
|
15
|
+
| "fetch";
|
|
16
|
+
|
|
17
|
+
// We set `name` ourselves (not forwarded from the SDK client).
|
|
18
|
+
type ControlledOpenAIKeys = "name";
|
|
19
|
+
|
|
20
|
+
// Compile-time exhaustiveness check: every key in OpenAIProviderSettings must
|
|
21
|
+
// be accounted for in either ForwardedOpenAIKeys or ControlledOpenAIKeys.
|
|
22
|
+
// If this line errors, a new key was added to OpenAIProviderSettings that
|
|
23
|
+
// needs to be handled.
|
|
24
|
+
type _exhaustive =
|
|
25
|
+
Exclude<
|
|
26
|
+
keyof OpenAIProviderSettings,
|
|
27
|
+
ForwardedOpenAIKeys | ControlledOpenAIKeys
|
|
28
|
+
> extends never
|
|
29
|
+
? true
|
|
30
|
+
: {
|
|
31
|
+
error: "OpenAIProviderSettings has unhandled keys";
|
|
32
|
+
unhandled: Exclude<
|
|
33
|
+
keyof OpenAIProviderSettings,
|
|
34
|
+
ForwardedOpenAIKeys | ControlledOpenAIKeys
|
|
35
|
+
>;
|
|
36
|
+
};
|
|
37
|
+
const _check: _exhaustive = true;
|
|
38
|
+
|
|
39
|
+
const { mockProviderFn, mockCreateOpenAI } = vi.hoisted(() => {
|
|
40
|
+
const mockProviderFn = vi.fn().mockReturnValue({ modelId: "test-model" });
|
|
41
|
+
const mockCreateOpenAI = vi.fn().mockReturnValue(mockProviderFn);
|
|
42
|
+
return { mockProviderFn, mockCreateOpenAI };
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
vi.mock("@ai-sdk/openai", async (importOriginal) => {
|
|
46
|
+
const actual = await importOriginal<typeof import("@ai-sdk/openai")>();
|
|
47
|
+
return { ...actual, createOpenAI: mockCreateOpenAI };
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
vi.mock("openai", () => {
|
|
51
|
+
return {
|
|
52
|
+
default: class MockOpenAI {
|
|
53
|
+
baseURL: string;
|
|
54
|
+
apiKey: string;
|
|
55
|
+
organization: string | null;
|
|
56
|
+
project: string | null;
|
|
57
|
+
_options: Record<string, any>;
|
|
58
|
+
beta = { chat: { completions: { stream: vi.fn() } } };
|
|
59
|
+
|
|
60
|
+
constructor(opts: any = {}) {
|
|
61
|
+
this.baseURL = opts.baseURL ?? "https://api.openai.com/v1";
|
|
62
|
+
this.apiKey = opts.apiKey ?? "default-key";
|
|
63
|
+
this.organization = opts.organization ?? null;
|
|
64
|
+
this.project = opts.project ?? null;
|
|
65
|
+
this._options = {
|
|
66
|
+
defaultHeaders: opts.defaultHeaders,
|
|
67
|
+
defaultQuery: opts.defaultQuery,
|
|
68
|
+
fetch: opts.fetch,
|
|
69
|
+
...opts,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe("OpenAIAdapter.getLanguageModel()", () => {
|
|
77
|
+
beforeEach(() => {
|
|
78
|
+
vi.clearAllMocks();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("forwards all provider-relevant options from the OpenAI SDK client", () => {
|
|
82
|
+
const customFetch = vi.fn();
|
|
83
|
+
const openai = new OpenAI({
|
|
84
|
+
apiKey: "azure-key",
|
|
85
|
+
baseURL: "https://myinstance.openai.azure.com/openai/deployments/gpt-4o",
|
|
86
|
+
organization: "org-123",
|
|
87
|
+
project: "proj-456",
|
|
88
|
+
defaultHeaders: { "api-key": "azure-key" },
|
|
89
|
+
defaultQuery: { "api-version": "2024-04-01-preview" },
|
|
90
|
+
fetch: customFetch,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const adapter = new OpenAIAdapter({ openai, model: "gpt-4o" });
|
|
94
|
+
adapter.getLanguageModel();
|
|
95
|
+
|
|
96
|
+
expect(mockCreateOpenAI).toHaveBeenCalledOnce();
|
|
97
|
+
const settings = mockCreateOpenAI.mock.calls[0][0];
|
|
98
|
+
|
|
99
|
+
expect(settings.baseURL).toBe(
|
|
100
|
+
"https://myinstance.openai.azure.com/openai/deployments/gpt-4o",
|
|
101
|
+
);
|
|
102
|
+
expect(settings.apiKey).toBe("azure-key");
|
|
103
|
+
expect(settings.organization).toBe("org-123");
|
|
104
|
+
expect(settings.project).toBe("proj-456");
|
|
105
|
+
expect(settings.headers).toEqual({ "api-key": "azure-key" });
|
|
106
|
+
expect(settings.fetch).toBe(customFetch);
|
|
107
|
+
|
|
108
|
+
expect(mockProviderFn).toHaveBeenCalledWith("gpt-4o");
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("works with default OpenAI config (no custom options)", () => {
|
|
112
|
+
const openai = new OpenAI({ apiKey: "sk-test" });
|
|
113
|
+
const adapter = new OpenAIAdapter({ openai });
|
|
114
|
+
adapter.getLanguageModel();
|
|
115
|
+
|
|
116
|
+
const settings = mockCreateOpenAI.mock.calls[0][0];
|
|
117
|
+
expect(settings.baseURL).toBe("https://api.openai.com/v1");
|
|
118
|
+
expect(settings.apiKey).toBe("sk-test");
|
|
119
|
+
expect(settings.organization).toBeUndefined();
|
|
120
|
+
expect(settings.project).toBeUndefined();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { getSdkClientOptions } from "../../../src/service-adapters/shared/sdk-client-utils";
|
|
3
|
+
|
|
4
|
+
describe("getSdkClientOptions()", () => {
|
|
5
|
+
it("extracts defaultHeaders and fetch from _options", () => {
|
|
6
|
+
const customFetch = vi.fn();
|
|
7
|
+
const client = {
|
|
8
|
+
_options: {
|
|
9
|
+
defaultHeaders: { "x-api-key": "secret" },
|
|
10
|
+
fetch: customFetch,
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const result = getSdkClientOptions(client);
|
|
15
|
+
expect(result.defaultHeaders).toEqual({ "x-api-key": "secret" });
|
|
16
|
+
expect(result.fetch).toBe(customFetch);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("returns empty object when _options is missing", () => {
|
|
20
|
+
const client = { baseURL: "https://api.example.com" };
|
|
21
|
+
const result = getSdkClientOptions(client);
|
|
22
|
+
expect(result).toEqual({});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("returns empty object when _options is null", () => {
|
|
26
|
+
const client = { _options: null };
|
|
27
|
+
const result = getSdkClientOptions(client);
|
|
28
|
+
expect(result).toEqual({});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("returns empty object when _options is a primitive", () => {
|
|
32
|
+
const client = { _options: "not-an-object" };
|
|
33
|
+
const result = getSdkClientOptions(client);
|
|
34
|
+
expect(result).toEqual({});
|
|
35
|
+
});
|
|
36
|
+
});
|