@copilotkit/vue 1.69.3 → 1.70.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/dist/index.cjs +1 -1
- package/dist/index.mjs +2 -2
- package/dist/use-render-activity-message-h2NHCkBt.cjs +85 -0
- package/dist/use-render-activity-message-h2NHCkBt.cjs.map +1 -0
- package/dist/{use-render-activity-message-W2lbqLZH.js → use-render-activity-message-ytoSQi6V.js} +2226 -2204
- package/dist/use-render-activity-message-ytoSQi6V.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/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/v2/hooks/__tests__/use-threads.test.ts +24 -1
- 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,290 @@
|
|
|
1
|
+
import { cleanup, render, waitFor } from "@testing-library/vue";
|
|
2
|
+
import type {
|
|
3
|
+
RuntimeEntitlementResponse,
|
|
4
|
+
RuntimeInfo,
|
|
5
|
+
} from "@copilotkit/shared";
|
|
6
|
+
import { defineComponent, h, nextTick } from "vue";
|
|
7
|
+
import { expect, test, vi } from "vitest";
|
|
8
|
+
import CopilotKitProvider from "../CopilotKitProvider.vue";
|
|
9
|
+
import { useLicenseContext } from "../useLicenseContext";
|
|
10
|
+
|
|
11
|
+
const AuthorityProbe = defineComponent({
|
|
12
|
+
setup() {
|
|
13
|
+
const license = useLicenseContext();
|
|
14
|
+
return () =>
|
|
15
|
+
h(
|
|
16
|
+
"output",
|
|
17
|
+
{ "data-testid": "runtime-license-authority" },
|
|
18
|
+
[
|
|
19
|
+
`status:${license.value.status ?? "null"}`,
|
|
20
|
+
`chat:${license.value.checkFeature("chat")}`,
|
|
21
|
+
`sidebar:${license.value.checkFeature("sidebar")}`,
|
|
22
|
+
`popup:${license.value.checkFeature("popup")}`,
|
|
23
|
+
`threads:${license.value.checkFeature("threads")}`,
|
|
24
|
+
].join(" "),
|
|
25
|
+
);
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
function managedRuntimeInfo(
|
|
30
|
+
active: boolean,
|
|
31
|
+
licenseStatus: RuntimeInfo["licenseStatus"],
|
|
32
|
+
): RuntimeInfo {
|
|
33
|
+
return {
|
|
34
|
+
version: "1.0.0",
|
|
35
|
+
agents: {},
|
|
36
|
+
audioFileTranscriptionEnabled: false,
|
|
37
|
+
mode: "intelligence",
|
|
38
|
+
licenseStatus,
|
|
39
|
+
runtimeEntitlements: {
|
|
40
|
+
status: "ready",
|
|
41
|
+
entitlement: {
|
|
42
|
+
active,
|
|
43
|
+
source: "managedOrgSubscription",
|
|
44
|
+
// Mirrors the active/inactive free-plan payload emitted by Intelligence.
|
|
45
|
+
...(active
|
|
46
|
+
? {
|
|
47
|
+
planCode: "free",
|
|
48
|
+
entitlementSource: "clerk_free_default",
|
|
49
|
+
features: {
|
|
50
|
+
"sdk.angular": false,
|
|
51
|
+
deployment_via_helm_chart: false,
|
|
52
|
+
analytics: true,
|
|
53
|
+
self_learning: true,
|
|
54
|
+
msteams: false,
|
|
55
|
+
memory: false,
|
|
56
|
+
managed_channels: true,
|
|
57
|
+
"managed_channels.slack": true,
|
|
58
|
+
"managed_channels.teams": true,
|
|
59
|
+
},
|
|
60
|
+
limits: {
|
|
61
|
+
"threads.retention_hours": 72,
|
|
62
|
+
"threads.max_count": 200,
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
: { features: {}, limits: {} }),
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Build Runtime info mirroring the active self-hosted producer payload. */
|
|
72
|
+
function selfHostedRuntimeInfo(
|
|
73
|
+
licenseStatus: RuntimeInfo["licenseStatus"],
|
|
74
|
+
): RuntimeInfo {
|
|
75
|
+
return {
|
|
76
|
+
...managedRuntimeInfo(true, licenseStatus),
|
|
77
|
+
runtimeEntitlements: {
|
|
78
|
+
status: "ready",
|
|
79
|
+
entitlement: {
|
|
80
|
+
active: true,
|
|
81
|
+
source: "selfHostedDeploymentLicense",
|
|
82
|
+
features: { deployment_via_helm_chart: true, msteams: true },
|
|
83
|
+
limits: {
|
|
84
|
+
"threads.retention_hours": 336,
|
|
85
|
+
"threads.max_count": 25_000,
|
|
86
|
+
},
|
|
87
|
+
planCode: "team_self_hosted",
|
|
88
|
+
entitlementSource: "enterprise_override",
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function retryableRuntimeInfo(
|
|
95
|
+
licenseStatus: RuntimeInfo["licenseStatus"] = "unknown",
|
|
96
|
+
): RuntimeInfo {
|
|
97
|
+
const runtimeEntitlements: RuntimeEntitlementResponse = {
|
|
98
|
+
status: "unavailable",
|
|
99
|
+
error: {
|
|
100
|
+
code: "runtime_entitlements_unavailable",
|
|
101
|
+
message: "Runtime entitlement lookup failed",
|
|
102
|
+
retryable: true,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
return {
|
|
106
|
+
...managedRuntimeInfo(true, licenseStatus),
|
|
107
|
+
runtimeEntitlements,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
interface RuntimeAuthoritySetup {
|
|
112
|
+
dispose: () => void;
|
|
113
|
+
fetchMock: ReturnType<typeof vi.fn<typeof globalThis.fetch>>;
|
|
114
|
+
readAuthority: () => string;
|
|
115
|
+
view: ReturnType<typeof render>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Render the provider against ordered `/info` responses.
|
|
120
|
+
*/
|
|
121
|
+
function setupRuntimeAuthority(
|
|
122
|
+
...runtimeInfoResponses: [RuntimeInfo, ...RuntimeInfo[]]
|
|
123
|
+
): RuntimeAuthoritySetup {
|
|
124
|
+
const fetchMock = vi.fn<typeof globalThis.fetch>();
|
|
125
|
+
for (const runtimeInfo of runtimeInfoResponses) {
|
|
126
|
+
fetchMock.mockResolvedValueOnce(
|
|
127
|
+
new Response(JSON.stringify(runtimeInfo), {
|
|
128
|
+
status: 200,
|
|
129
|
+
headers: { "content-type": "application/json" },
|
|
130
|
+
}),
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
134
|
+
|
|
135
|
+
const view = render(CopilotKitProvider, {
|
|
136
|
+
props: { runtimeUrl: "/api" },
|
|
137
|
+
slots: { default: () => h(AuthorityProbe) },
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
dispose() {
|
|
142
|
+
view.unmount();
|
|
143
|
+
cleanup();
|
|
144
|
+
vi.unstubAllGlobals();
|
|
145
|
+
},
|
|
146
|
+
fetchMock,
|
|
147
|
+
readAuthority: () =>
|
|
148
|
+
view.getByTestId("runtime-license-authority").textContent ?? "",
|
|
149
|
+
view,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function flushPromiseUpdates(): Promise<void> {
|
|
154
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
155
|
+
await nextTick();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
test("a ready managed grant drives every Vue feature gate and overrides a stale invalid token", async () => {
|
|
159
|
+
const { dispose, readAuthority, view } = setupRuntimeAuthority(
|
|
160
|
+
managedRuntimeInfo(true, "invalid"),
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
await waitFor(() => {
|
|
165
|
+
expect(readAuthority()).toBe(
|
|
166
|
+
"status:valid chat:true sidebar:true popup:true threads:true",
|
|
167
|
+
);
|
|
168
|
+
});
|
|
169
|
+
expect(view.queryByText(/Invalid CopilotKit license token/i)).toBeNull();
|
|
170
|
+
} finally {
|
|
171
|
+
dispose();
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("a ready managed denial drives every Vue feature gate", async () => {
|
|
176
|
+
const { dispose, readAuthority } = setupRuntimeAuthority(
|
|
177
|
+
managedRuntimeInfo(false, "none"),
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
await waitFor(() => {
|
|
182
|
+
expect(readAuthority()).toBe(
|
|
183
|
+
"status:none chat:false sidebar:false popup:false threads:false",
|
|
184
|
+
);
|
|
185
|
+
});
|
|
186
|
+
} finally {
|
|
187
|
+
dispose();
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
test("an active self-hosted producer entitlement drives every Vue feature gate", async () => {
|
|
192
|
+
const { dispose, readAuthority } = setupRuntimeAuthority(
|
|
193
|
+
selfHostedRuntimeInfo("invalid"),
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
await waitFor(() => {
|
|
198
|
+
expect(readAuthority()).toBe(
|
|
199
|
+
"status:valid chat:true sidebar:true popup:true threads:true",
|
|
200
|
+
);
|
|
201
|
+
});
|
|
202
|
+
} finally {
|
|
203
|
+
dispose();
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test("a retryable managed lookup keeps every Vue gate pending and hides stale warnings until recovery", async () => {
|
|
208
|
+
vi.useFakeTimers();
|
|
209
|
+
const { dispose, fetchMock, readAuthority, view } = setupRuntimeAuthority(
|
|
210
|
+
retryableRuntimeInfo("invalid"),
|
|
211
|
+
managedRuntimeInfo(true, "invalid"),
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
await flushPromiseUpdates();
|
|
216
|
+
|
|
217
|
+
expect(fetchMock).toHaveBeenCalledOnce();
|
|
218
|
+
expect(readAuthority()).toBe(
|
|
219
|
+
"status:null chat:true sidebar:true popup:true threads:true",
|
|
220
|
+
);
|
|
221
|
+
expect(view.queryByText(/Invalid CopilotKit license token/i)).toBeNull();
|
|
222
|
+
|
|
223
|
+
await vi.advanceTimersByTimeAsync(5_000);
|
|
224
|
+
await nextTick();
|
|
225
|
+
|
|
226
|
+
expect(fetchMock).toHaveBeenCalledTimes(2);
|
|
227
|
+
expect(readAuthority()).toBe(
|
|
228
|
+
"status:valid chat:true sidebar:true popup:true threads:true",
|
|
229
|
+
);
|
|
230
|
+
} finally {
|
|
231
|
+
dispose();
|
|
232
|
+
vi.useRealTimers();
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
test("a persistent retryable lookup denies every Vue gate after Core's bounded retry settles", async () => {
|
|
237
|
+
vi.useFakeTimers();
|
|
238
|
+
const { dispose, fetchMock, readAuthority } = setupRuntimeAuthority(
|
|
239
|
+
retryableRuntimeInfo(),
|
|
240
|
+
retryableRuntimeInfo(),
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
await flushPromiseUpdates();
|
|
245
|
+
|
|
246
|
+
expect(readAuthority()).toBe(
|
|
247
|
+
"status:null chat:true sidebar:true popup:true threads:true",
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
await vi.advanceTimersByTimeAsync(5_000);
|
|
251
|
+
await nextTick();
|
|
252
|
+
|
|
253
|
+
expect(fetchMock).toHaveBeenCalledTimes(2);
|
|
254
|
+
expect(readAuthority()).toBe(
|
|
255
|
+
"status:unknown chat:false sidebar:false popup:false threads:false",
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
await vi.advanceTimersByTimeAsync(30_000);
|
|
259
|
+
expect(fetchMock).toHaveBeenCalledTimes(2);
|
|
260
|
+
} finally {
|
|
261
|
+
dispose();
|
|
262
|
+
vi.useRealTimers();
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
test("an inactive self-hosted entitlement keeps Vue's valid legacy fallback", async () => {
|
|
267
|
+
const runtimeInfo: RuntimeInfo = {
|
|
268
|
+
...managedRuntimeInfo(false, "valid"),
|
|
269
|
+
runtimeEntitlements: {
|
|
270
|
+
status: "ready",
|
|
271
|
+
entitlement: {
|
|
272
|
+
active: false,
|
|
273
|
+
source: "selfHostedDeploymentLicense",
|
|
274
|
+
features: {},
|
|
275
|
+
limits: {},
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
const { dispose, readAuthority } = setupRuntimeAuthority(runtimeInfo);
|
|
280
|
+
|
|
281
|
+
try {
|
|
282
|
+
await waitFor(() => {
|
|
283
|
+
expect(readAuthority()).toBe(
|
|
284
|
+
"status:valid chat:true sidebar:true popup:true threads:true",
|
|
285
|
+
);
|
|
286
|
+
});
|
|
287
|
+
} finally {
|
|
288
|
+
dispose();
|
|
289
|
+
}
|
|
290
|
+
});
|