@copilotkit/vue 1.69.3 → 1.70.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/dist/hooks/use-copilot-action.d.ts +7 -0
- package/dist/hooks/use-copilot-action.d.ts.map +1 -1
- package/dist/hooks/use-frontend-tool.d.ts +7 -0
- package/dist/hooks/use-frontend-tool.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +35 -23
- package/dist/index.mjs.map +1 -1
- package/dist/use-render-activity-message-CyThomMH.cjs +85 -0
- package/dist/use-render-activity-message-CyThomMH.cjs.map +1 -0
- package/dist/{use-render-activity-message-W2lbqLZH.js → use-render-activity-message-WeN5iF5H.js} +2229 -2204
- package/dist/use-render-activity-message-WeN5iF5H.js.map +1 -0
- package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts +40 -16
- package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts.map +1 -1
- package/dist/v2/hooks/use-frontend-tool.d.ts.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.mjs +1 -1
- package/dist/v2/providers/CopilotKitProvider.vue.d.ts +2 -2
- package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/hooks/__tests__/use-frontend-tool-webmcp.test.ts +113 -0
- package/src/hooks/use-copilot-action.ts +13 -0
- package/src/hooks/use-frontend-tool.ts +13 -0
- package/src/v2/hooks/__tests__/use-frontend-tool-webmcp.test.ts +282 -0
- package/src/v2/hooks/__tests__/use-threads.test.ts +24 -1
- package/src/v2/hooks/use-frontend-tool.ts +3 -0
- package/src/v2/hooks/use-threads.ts +1 -1
- package/src/v2/providers/CopilotKitProvider.vue +69 -14
- package/src/v2/providers/__tests__/CopilotKitProvider.managedEntitlement.test.ts +290 -0
- package/dist/use-render-activity-message-DMY6Krn-.cjs +0 -85
- package/dist/use-render-activity-message-DMY6Krn-.cjs.map +0 -1
- package/dist/use-render-activity-message-W2lbqLZH.js.map +0 -1
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { defineComponent, ref, watch } from "vue";
|
|
2
|
+
import { screen, fireEvent, waitFor } from "@testing-library/vue";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { describe, it, expect } from "vitest";
|
|
5
|
+
import { useFrontendTool } from "../use-frontend-tool";
|
|
6
|
+
import { useCopilotKit } from "../../providers/useCopilotKit";
|
|
7
|
+
import type { VueFrontendTool } from "../../types";
|
|
8
|
+
import type { CopilotKitCoreVue } from "../../lib/vue-core";
|
|
9
|
+
import { renderWithCopilotKit } from "../../__tests__/utils/test-helpers";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Component that captures the copilotkit core ref for test assertions.
|
|
13
|
+
*/
|
|
14
|
+
const CoreCapture = defineComponent({
|
|
15
|
+
props: {
|
|
16
|
+
onCore: {
|
|
17
|
+
type: Function as () => (core: CopilotKitCoreVue) => void,
|
|
18
|
+
required: true,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
setup(props) {
|
|
22
|
+
const { copilotkit } = useCopilotKit();
|
|
23
|
+
watch(
|
|
24
|
+
copilotkit,
|
|
25
|
+
(core) => {
|
|
26
|
+
if (core) {
|
|
27
|
+
props.onCore(core);
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
{ immediate: true },
|
|
31
|
+
);
|
|
32
|
+
return {};
|
|
33
|
+
},
|
|
34
|
+
template: `<div />`,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe("useFrontendTool webmcp flag", () => {
|
|
38
|
+
it("registers tool with webmcp: true on the core", async () => {
|
|
39
|
+
let coreRef: CopilotKitCoreVue | null = null;
|
|
40
|
+
|
|
41
|
+
const ToolComponent = defineComponent({
|
|
42
|
+
setup() {
|
|
43
|
+
const tool: VueFrontendTool<{ msg: string }> = {
|
|
44
|
+
name: "webmcpTool",
|
|
45
|
+
description: "A WebMCP-exposed tool",
|
|
46
|
+
webmcp: true,
|
|
47
|
+
parameters: z.object({ msg: z.string() }),
|
|
48
|
+
handler: async () => ({ result: "ok" }),
|
|
49
|
+
};
|
|
50
|
+
useFrontendTool(tool);
|
|
51
|
+
return {};
|
|
52
|
+
},
|
|
53
|
+
template: `<div />`,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const Host = defineComponent({
|
|
57
|
+
components: { ToolComponent, CoreCapture },
|
|
58
|
+
setup() {
|
|
59
|
+
return {
|
|
60
|
+
setCore: (core: CopilotKitCoreVue) => {
|
|
61
|
+
coreRef = core;
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
template: `
|
|
66
|
+
<div>
|
|
67
|
+
<ToolComponent />
|
|
68
|
+
<CoreCapture :on-core="setCore" />
|
|
69
|
+
</div>
|
|
70
|
+
`,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const ui = renderWithCopilotKit({
|
|
74
|
+
children: Host,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
await waitFor(() => {
|
|
78
|
+
expect(coreRef).not.toBeNull();
|
|
79
|
+
const tool = coreRef!.tools.find((entry) => entry.name === "webmcpTool");
|
|
80
|
+
expect(tool).toBeDefined();
|
|
81
|
+
expect(tool!.webmcp).toBe(true);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
ui.unmount();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("registers tool with webmcp annotations on the core", async () => {
|
|
88
|
+
let coreRef: CopilotKitCoreVue | null = null;
|
|
89
|
+
|
|
90
|
+
const ToolComponent = defineComponent({
|
|
91
|
+
setup() {
|
|
92
|
+
const tool: VueFrontendTool<{ msg: string }> = {
|
|
93
|
+
name: "annotatedTool",
|
|
94
|
+
description: "A WebMCP-exposed tool with annotations",
|
|
95
|
+
webmcp: { annotations: { readOnlyHint: true } },
|
|
96
|
+
parameters: z.object({ msg: z.string() }),
|
|
97
|
+
handler: async () => ({ result: "ok" }),
|
|
98
|
+
};
|
|
99
|
+
useFrontendTool(tool);
|
|
100
|
+
return {};
|
|
101
|
+
},
|
|
102
|
+
template: `<div />`,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const Host = defineComponent({
|
|
106
|
+
components: { ToolComponent, CoreCapture },
|
|
107
|
+
setup() {
|
|
108
|
+
return {
|
|
109
|
+
setCore: (core: CopilotKitCoreVue) => {
|
|
110
|
+
coreRef = core;
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
},
|
|
114
|
+
template: `
|
|
115
|
+
<div>
|
|
116
|
+
<ToolComponent />
|
|
117
|
+
<CoreCapture :on-core="setCore" />
|
|
118
|
+
</div>
|
|
119
|
+
`,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const ui = renderWithCopilotKit({
|
|
123
|
+
children: Host,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
await waitFor(() => {
|
|
127
|
+
expect(coreRef).not.toBeNull();
|
|
128
|
+
const tool = coreRef!.tools.find(
|
|
129
|
+
(entry) => entry.name === "annotatedTool",
|
|
130
|
+
);
|
|
131
|
+
expect(tool).toBeDefined();
|
|
132
|
+
expect(tool!.webmcp).toEqual({ annotations: { readOnlyHint: true } });
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
ui.unmount();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("re-registers tool when the webmcp config changes", async () => {
|
|
139
|
+
let coreRef: CopilotKitCoreVue | null = null;
|
|
140
|
+
|
|
141
|
+
const ToolWithToggle = defineComponent({
|
|
142
|
+
setup() {
|
|
143
|
+
const readOnly = ref(false);
|
|
144
|
+
|
|
145
|
+
const tool: VueFrontendTool<{ data: string }> = {
|
|
146
|
+
name: "toggleWebmcpTool",
|
|
147
|
+
description: "A tool with a toggleable WebMCP config",
|
|
148
|
+
get webmcp() {
|
|
149
|
+
return { annotations: { readOnlyHint: readOnly.value } };
|
|
150
|
+
},
|
|
151
|
+
parameters: z.object({ data: z.string() }),
|
|
152
|
+
handler: async () => ({ ok: true }),
|
|
153
|
+
};
|
|
154
|
+
useFrontendTool(tool, [readOnly]);
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
readOnly,
|
|
158
|
+
toggle: () => {
|
|
159
|
+
readOnly.value = !readOnly.value;
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
},
|
|
163
|
+
template: `
|
|
164
|
+
<button data-testid="toggle-btn" @click="toggle">
|
|
165
|
+
{{ readOnly ? "Read-write" : "Read-only" }}
|
|
166
|
+
</button>
|
|
167
|
+
`,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const Host = defineComponent({
|
|
171
|
+
components: { ToolWithToggle, CoreCapture },
|
|
172
|
+
setup() {
|
|
173
|
+
return {
|
|
174
|
+
setCore: (core: CopilotKitCoreVue) => {
|
|
175
|
+
coreRef = core;
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
},
|
|
179
|
+
template: `
|
|
180
|
+
<div>
|
|
181
|
+
<ToolWithToggle />
|
|
182
|
+
<CoreCapture :on-core="setCore" />
|
|
183
|
+
</div>
|
|
184
|
+
`,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const ui = renderWithCopilotKit({
|
|
188
|
+
children: Host,
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
await waitFor(() => {
|
|
192
|
+
expect(coreRef).not.toBeNull();
|
|
193
|
+
const tool = coreRef!.tools.find(
|
|
194
|
+
(entry) => entry.name === "toggleWebmcpTool",
|
|
195
|
+
);
|
|
196
|
+
expect(tool).toBeDefined();
|
|
197
|
+
expect(tool!.webmcp).toEqual({ annotations: { readOnlyHint: false } });
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
await fireEvent.click(screen.getByTestId("toggle-btn"));
|
|
201
|
+
|
|
202
|
+
await waitFor(() => {
|
|
203
|
+
const tool = coreRef!.tools.find(
|
|
204
|
+
(entry) => entry.name === "toggleWebmcpTool",
|
|
205
|
+
);
|
|
206
|
+
expect(tool).toBeDefined();
|
|
207
|
+
expect(tool!.webmcp).toEqual({ annotations: { readOnlyHint: true } });
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
ui.unmount();
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it("registers and cleans up agent-scoped webmcp tools on the core", async () => {
|
|
214
|
+
let coreRef: CopilotKitCoreVue | null = null;
|
|
215
|
+
|
|
216
|
+
const ToolComponent = defineComponent({
|
|
217
|
+
setup() {
|
|
218
|
+
useFrontendTool({
|
|
219
|
+
name: "scopedTool",
|
|
220
|
+
description: "A WebMCP tool scoped to alpha",
|
|
221
|
+
agentId: "alpha",
|
|
222
|
+
webmcp: { annotations: { readOnlyHint: true } },
|
|
223
|
+
handler: async () => ({ ok: true }),
|
|
224
|
+
});
|
|
225
|
+
useFrontendTool({
|
|
226
|
+
name: "scopedTool",
|
|
227
|
+
description: "A WebMCP tool scoped to beta",
|
|
228
|
+
agentId: "beta",
|
|
229
|
+
webmcp: true,
|
|
230
|
+
handler: async () => ({ ok: true }),
|
|
231
|
+
});
|
|
232
|
+
return {};
|
|
233
|
+
},
|
|
234
|
+
template: `<div />`,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
const Host = defineComponent({
|
|
238
|
+
components: { ToolComponent, CoreCapture },
|
|
239
|
+
setup() {
|
|
240
|
+
return {
|
|
241
|
+
setCore: (core: CopilotKitCoreVue) => {
|
|
242
|
+
coreRef = core;
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
},
|
|
246
|
+
template: `
|
|
247
|
+
<div>
|
|
248
|
+
<ToolComponent />
|
|
249
|
+
<CoreCapture :on-core="setCore" />
|
|
250
|
+
</div>
|
|
251
|
+
`,
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
const ui = renderWithCopilotKit({
|
|
255
|
+
children: Host,
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
await waitFor(() => {
|
|
259
|
+
expect(coreRef).not.toBeNull();
|
|
260
|
+
const alphaTool = coreRef!.tools.find(
|
|
261
|
+
(entry) => entry.name === "scopedTool" && entry.agentId === "alpha",
|
|
262
|
+
);
|
|
263
|
+
expect(alphaTool).toBeDefined();
|
|
264
|
+
expect(alphaTool!.webmcp).toEqual({
|
|
265
|
+
annotations: { readOnlyHint: true },
|
|
266
|
+
});
|
|
267
|
+
const betaTool = coreRef!.tools.find(
|
|
268
|
+
(entry) => entry.name === "scopedTool" && entry.agentId === "beta",
|
|
269
|
+
);
|
|
270
|
+
expect(betaTool).toBeDefined();
|
|
271
|
+
expect(betaTool!.webmcp).toBe(true);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
ui.unmount();
|
|
275
|
+
|
|
276
|
+
await waitFor(() => {
|
|
277
|
+
expect(
|
|
278
|
+
coreRef!.tools.filter((entry) => entry.name === "scopedTool").length,
|
|
279
|
+
).toBe(0);
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
});
|
|
@@ -44,6 +44,8 @@ const mockUseCopilotKit = useCopilotKit as ReturnType<typeof vi.fn>;
|
|
|
44
44
|
const threadMocks = vi.hoisted(() => ({
|
|
45
45
|
sockets: [] as any[],
|
|
46
46
|
dispatchedContexts: [] as Array<ThreadState["context"]>,
|
|
47
|
+
/** Every environment `ɵcreateThreadStore` was constructed with. */
|
|
48
|
+
storeEnvironments: [] as Array<{ fetch?: unknown }>,
|
|
47
49
|
}));
|
|
48
50
|
|
|
49
51
|
function compareThreadsByActivity(left: ThreadRecord, right: ThreadRecord) {
|
|
@@ -344,7 +346,10 @@ vi.mock("@copilotkit/core", () => {
|
|
|
344
346
|
Connected: "connected",
|
|
345
347
|
Error: "error",
|
|
346
348
|
},
|
|
347
|
-
ɵcreateThreadStore: () =>
|
|
349
|
+
ɵcreateThreadStore: (environment: { fetch?: unknown }) => {
|
|
350
|
+
threadMocks.storeEnvironments.push(environment);
|
|
351
|
+
return new MockThreadStore();
|
|
352
|
+
},
|
|
348
353
|
ɵselectThreads: select((state) => state.threads),
|
|
349
354
|
ɵselectThreadsIsLoading: select((state) => state.isLoading),
|
|
350
355
|
ɵselectThreadsError: select((state) => state.error),
|
|
@@ -358,6 +363,10 @@ vi.mock("@copilotkit/core", () => {
|
|
|
358
363
|
const fetchMock = vi.fn();
|
|
359
364
|
globalThis.fetch = fetchMock;
|
|
360
365
|
|
|
366
|
+
const runtimeFetchMock = vi.fn((...args: unknown[]) =>
|
|
367
|
+
(fetchMock as (...a: unknown[]) => unknown)(...args),
|
|
368
|
+
);
|
|
369
|
+
|
|
361
370
|
const { CopilotKitCoreRuntimeConnectionStatus } =
|
|
362
371
|
await import("@copilotkit/core");
|
|
363
372
|
|
|
@@ -391,6 +400,7 @@ type MockCopilotKit = {
|
|
|
391
400
|
threadEndpoints: ThreadEndpointRuntimeInfo | undefined;
|
|
392
401
|
registerThreadStore: ReturnType<typeof vi.fn>;
|
|
393
402
|
unregisterThreadStore: ReturnType<typeof vi.fn>;
|
|
403
|
+
ɵruntimeFetch: typeof fetch;
|
|
394
404
|
};
|
|
395
405
|
|
|
396
406
|
function setupCopilotKit(
|
|
@@ -410,6 +420,7 @@ function setupCopilotKit(
|
|
|
410
420
|
threadEndpoints: supportedThreadEndpoints,
|
|
411
421
|
registerThreadStore: vi.fn(),
|
|
412
422
|
unregisterThreadStore: vi.fn(),
|
|
423
|
+
ɵruntimeFetch: runtimeFetchMock as unknown as typeof fetch,
|
|
413
424
|
...overrides,
|
|
414
425
|
});
|
|
415
426
|
mockUseCopilotKit.mockReturnValue({ copilotkit });
|
|
@@ -487,10 +498,22 @@ describe("useThreads", () => {
|
|
|
487
498
|
beforeEach(() => {
|
|
488
499
|
threadMocks.sockets.splice(0);
|
|
489
500
|
threadMocks.dispatchedContexts.splice(0);
|
|
501
|
+
threadMocks.storeEnvironments.splice(0);
|
|
490
502
|
fetchMock.mockReset();
|
|
491
503
|
setupCopilotKit();
|
|
492
504
|
});
|
|
493
505
|
|
|
506
|
+
it("builds the thread store with the core's instrumented fetch", () => {
|
|
507
|
+
const copilotkit = setupCopilotKit();
|
|
508
|
+
mountHook();
|
|
509
|
+
|
|
510
|
+
expect(threadMocks.storeEnvironments).toHaveLength(1);
|
|
511
|
+
expect(threadMocks.storeEnvironments[0]!.fetch).toBe(
|
|
512
|
+
copilotkit.value.ɵruntimeFetch,
|
|
513
|
+
);
|
|
514
|
+
expect(threadMocks.storeEnvironments[0]!.fetch).not.toBe(globalThis.fetch);
|
|
515
|
+
});
|
|
516
|
+
|
|
494
517
|
it("fetches threads and subscribes to the user metadata channel", async () => {
|
|
495
518
|
fetchMock
|
|
496
519
|
.mockReturnValueOnce(
|
|
@@ -32,6 +32,9 @@ export function useFrontendTool<T extends Record<string, unknown>>(
|
|
|
32
32
|
[
|
|
33
33
|
() => tool.name,
|
|
34
34
|
() => tool.available,
|
|
35
|
+
// webmcp is commonly an object literal, so compare it by value to avoid
|
|
36
|
+
// re-registering on identity churn while still reacting to real changes.
|
|
37
|
+
() => JSON.stringify(tool.webmcp ?? null),
|
|
35
38
|
() => extraDeps.length,
|
|
36
39
|
...extraDeps,
|
|
37
40
|
],
|
|
@@ -90,7 +90,7 @@ function bindThreadStoreSelector<T>(
|
|
|
90
90
|
export function useThreads(input: UseThreadsInput): UseThreadsResult {
|
|
91
91
|
const { copilotkit } = useCopilotKit();
|
|
92
92
|
const store = ɵcreateThreadStore({
|
|
93
|
-
fetch:
|
|
93
|
+
fetch: copilotkit.value.ɵruntimeFetch,
|
|
94
94
|
});
|
|
95
95
|
|
|
96
96
|
const resolvedAgentId = computed(() => toValue(input.agentId));
|
|
@@ -16,7 +16,10 @@ import type {
|
|
|
16
16
|
FrontendTool,
|
|
17
17
|
} from "@copilotkit/core";
|
|
18
18
|
import { schemaToJsonSchema, shouldEnableInspector } from "@copilotkit/shared";
|
|
19
|
-
import type {
|
|
19
|
+
import type {
|
|
20
|
+
RuntimeEntitlementResponse,
|
|
21
|
+
RuntimeLicenseStatus,
|
|
22
|
+
} from "@copilotkit/shared";
|
|
20
23
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
21
24
|
import { CopilotKitCoreVue } from "../lib/vue-core";
|
|
22
25
|
import { createA2UIMessageRenderer } from "../components/A2UIMessageRenderer";
|
|
@@ -48,7 +51,6 @@ import type {
|
|
|
48
51
|
SandboxFunction,
|
|
49
52
|
VueActivityMessageRenderer,
|
|
50
53
|
VueFrontendTool,
|
|
51
|
-
VueHumanInTheLoop,
|
|
52
54
|
VueToolCallRenderer,
|
|
53
55
|
} from "../types";
|
|
54
56
|
|
|
@@ -294,6 +296,10 @@ const allRenderCustomMessages = computed(
|
|
|
294
296
|
const runtimeA2UIEnabled = ref(false);
|
|
295
297
|
const runtimeOpenGenerativeUIEnabled = ref(false);
|
|
296
298
|
const runtimeLicenseStatus = ref<RuntimeLicenseStatus | undefined>(undefined);
|
|
299
|
+
const runtimeEntitlements = ref<RuntimeEntitlementResponse | undefined>(
|
|
300
|
+
undefined,
|
|
301
|
+
);
|
|
302
|
+
const runtimeEntitlementRetryPending = ref(false);
|
|
297
303
|
const openGenerativeUIActive = computed(
|
|
298
304
|
() => runtimeOpenGenerativeUIEnabled.value || !!props.openGenerativeUI,
|
|
299
305
|
);
|
|
@@ -460,15 +466,14 @@ watch(
|
|
|
460
466
|
runtimeA2UIEnabled.value = core.a2uiEnabled;
|
|
461
467
|
runtimeOpenGenerativeUIEnabled.value = core.openGenerativeUIEnabled;
|
|
462
468
|
runtimeLicenseStatus.value = core.licenseStatus;
|
|
469
|
+
runtimeEntitlements.value = core.runtimeEntitlements;
|
|
470
|
+
runtimeEntitlementRetryPending.value =
|
|
471
|
+
core.runtimeEntitlementRetryPending;
|
|
463
472
|
triggerRef(copilotkit);
|
|
464
473
|
},
|
|
465
474
|
});
|
|
466
475
|
const sub5 = core.subscribe({
|
|
467
|
-
onError: (event
|
|
468
|
-
error: Error;
|
|
469
|
-
code: CopilotKitCoreErrorCode;
|
|
470
|
-
context: Record<string, any>;
|
|
471
|
-
}) => {
|
|
476
|
+
onError: (event) => {
|
|
472
477
|
void props.onError?.({
|
|
473
478
|
error: event.error,
|
|
474
479
|
code: event.code,
|
|
@@ -557,6 +562,9 @@ onMounted(() => {
|
|
|
557
562
|
runtimeOpenGenerativeUIEnabled.value =
|
|
558
563
|
copilotkit.value.openGenerativeUIEnabled;
|
|
559
564
|
runtimeLicenseStatus.value = copilotkit.value.licenseStatus;
|
|
565
|
+
runtimeEntitlements.value = copilotkit.value.runtimeEntitlements;
|
|
566
|
+
runtimeEntitlementRetryPending.value =
|
|
567
|
+
copilotkit.value.runtimeEntitlementRetryPending;
|
|
560
568
|
didMountRef.value = true;
|
|
561
569
|
});
|
|
562
570
|
|
|
@@ -633,23 +641,70 @@ provide(CopilotKitKey, {
|
|
|
633
641
|
});
|
|
634
642
|
provide(SandboxFunctionsKey, sandboxFunctions);
|
|
635
643
|
|
|
636
|
-
// License context — driven by
|
|
637
|
-
const
|
|
638
|
-
|
|
644
|
+
// License context — driven by structured and legacy Runtime authority.
|
|
645
|
+
const retryableRuntimeEntitlementFailure = computed(
|
|
646
|
+
() =>
|
|
647
|
+
runtimeEntitlements.value?.status !== "ready" &&
|
|
648
|
+
runtimeEntitlements.value?.error.retryable === true,
|
|
649
|
+
);
|
|
650
|
+
const hasNonReadyRuntimeEntitlement = computed(
|
|
651
|
+
() =>
|
|
652
|
+
runtimeEntitlements.value !== undefined &&
|
|
653
|
+
runtimeEntitlements.value.status !== "ready",
|
|
654
|
+
);
|
|
655
|
+
const hasLegacyRuntimeEntitlementFallback = computed(
|
|
656
|
+
() =>
|
|
657
|
+
runtimeLicenseStatus.value === "valid" ||
|
|
658
|
+
runtimeLicenseStatus.value === "expiring",
|
|
659
|
+
);
|
|
660
|
+
const runtimeEntitlementRetryInProgress = computed(
|
|
661
|
+
() =>
|
|
662
|
+
retryableRuntimeEntitlementFailure.value &&
|
|
663
|
+
runtimeEntitlementRetryPending.value &&
|
|
664
|
+
!hasLegacyRuntimeEntitlementFallback.value,
|
|
639
665
|
);
|
|
666
|
+
const runtimeEntitlementFailureSettled = computed(
|
|
667
|
+
() =>
|
|
668
|
+
hasNonReadyRuntimeEntitlement.value &&
|
|
669
|
+
!runtimeEntitlementRetryInProgress.value &&
|
|
670
|
+
!hasLegacyRuntimeEntitlementFallback.value,
|
|
671
|
+
);
|
|
672
|
+
const licenseContextValue = computed<LicenseContextValue>(() => {
|
|
673
|
+
const runtimeLicenseContext = createLicenseContextValue(
|
|
674
|
+
runtimeEntitlementRetryInProgress.value
|
|
675
|
+
? undefined
|
|
676
|
+
: runtimeLicenseStatus.value,
|
|
677
|
+
runtimeEntitlements.value,
|
|
678
|
+
);
|
|
679
|
+
if (!runtimeEntitlementFailureSettled.value) {
|
|
680
|
+
return runtimeLicenseContext;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
return {
|
|
684
|
+
...runtimeLicenseContext,
|
|
685
|
+
checkFeature: () => false,
|
|
686
|
+
getLimit: () => null,
|
|
687
|
+
};
|
|
688
|
+
});
|
|
640
689
|
provide(LicenseContextKey, licenseContextValue);
|
|
641
690
|
|
|
691
|
+
const runtimeLicenseWarningStatus = computed(() =>
|
|
692
|
+
runtimeEntitlementRetryInProgress.value
|
|
693
|
+
? undefined
|
|
694
|
+
: (licenseContextValue.value.status ?? undefined),
|
|
695
|
+
);
|
|
642
696
|
const showNoLicenseBanner = computed(
|
|
643
|
-
() =>
|
|
697
|
+
() =>
|
|
698
|
+
runtimeLicenseWarningStatus.value === "none" && !resolvedPublicKey.value,
|
|
644
699
|
);
|
|
645
700
|
const showExpiredBanner = computed(
|
|
646
|
-
() =>
|
|
701
|
+
() => runtimeLicenseWarningStatus.value === "expired",
|
|
647
702
|
);
|
|
648
703
|
const showInvalidBanner = computed(
|
|
649
|
-
() =>
|
|
704
|
+
() => runtimeLicenseWarningStatus.value === "invalid",
|
|
650
705
|
);
|
|
651
706
|
const showExpiringBanner = computed(
|
|
652
|
-
() =>
|
|
707
|
+
() => runtimeLicenseWarningStatus.value === "expiring",
|
|
653
708
|
);
|
|
654
709
|
</script>
|
|
655
710
|
|