@copilotkit/shared 1.55.2 → 1.55.3-canary.1776243725

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.
Files changed (49) hide show
  1. package/dist/index.cjs +2 -0
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +2 -1
  4. package/dist/index.d.cts.map +1 -1
  5. package/dist/index.d.mts +2 -1
  6. package/dist/index.d.mts.map +1 -1
  7. package/dist/index.mjs +2 -1
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/index.umd.js +65 -6
  10. package/dist/index.umd.js.map +1 -1
  11. package/dist/package.cjs +1 -1
  12. package/dist/package.mjs +1 -1
  13. package/dist/utils/clipboard.cjs +28 -0
  14. package/dist/utils/clipboard.cjs.map +1 -0
  15. package/dist/utils/clipboard.d.cts +14 -0
  16. package/dist/utils/clipboard.d.cts.map +1 -0
  17. package/dist/utils/clipboard.d.mts +14 -0
  18. package/dist/utils/clipboard.d.mts.map +1 -0
  19. package/dist/utils/clipboard.mjs +27 -0
  20. package/dist/utils/clipboard.mjs.map +1 -0
  21. package/dist/utils/index.cjs +1 -0
  22. package/dist/utils/index.cjs.map +1 -1
  23. package/dist/utils/index.d.cts +1 -0
  24. package/dist/utils/index.d.cts.map +1 -1
  25. package/dist/utils/index.d.mts +1 -0
  26. package/dist/utils/index.d.mts.map +1 -1
  27. package/dist/utils/index.mjs +1 -0
  28. package/dist/utils/index.mjs.map +1 -1
  29. package/dist/utils/json-schema.cjs +36 -5
  30. package/dist/utils/json-schema.cjs.map +1 -1
  31. package/dist/utils/json-schema.d.cts +1 -1
  32. package/dist/utils/json-schema.d.cts.map +1 -1
  33. package/dist/utils/json-schema.d.mts +1 -1
  34. package/dist/utils/json-schema.d.mts.map +1 -1
  35. package/dist/utils/json-schema.mjs +36 -5
  36. package/dist/utils/json-schema.mjs.map +1 -1
  37. package/dist/utils/types.cjs.map +1 -1
  38. package/dist/utils/types.d.cts +3 -0
  39. package/dist/utils/types.d.cts.map +1 -1
  40. package/dist/utils/types.d.mts +3 -0
  41. package/dist/utils/types.d.mts.map +1 -1
  42. package/dist/utils/types.mjs.map +1 -1
  43. package/package.json +1 -1
  44. package/src/utils/__tests__/clipboard.test.ts +87 -0
  45. package/src/utils/__tests__/json-schema.test.ts +250 -1
  46. package/src/utils/clipboard.ts +23 -0
  47. package/src/utils/index.ts +1 -0
  48. package/src/utils/json-schema.ts +84 -3
  49. package/src/utils/types.ts +3 -0
@@ -1,4 +1,4 @@
1
- import { describe, it, expect } from "vitest";
1
+ import { describe, it, expect, vi } from "vitest";
2
2
  import { z } from "zod";
3
3
  import {
4
4
  convertJsonSchemaToZodSchema,
@@ -191,6 +191,255 @@ describe("convertJsonSchemaToZodSchema", () => {
191
191
 
192
192
  expect(resultSchemaJson).toStrictEqual(expectedSchemaJson);
193
193
  });
194
+
195
+ it("should resolve non-circular $ref definitions correctly", () => {
196
+ const jsonSchema = {
197
+ type: "object",
198
+ properties: {
199
+ address: { $ref: "#/$defs/Address" },
200
+ },
201
+ required: ["address"],
202
+ $defs: {
203
+ Address: {
204
+ type: "object",
205
+ properties: {
206
+ street: { type: "string", description: "Street name" },
207
+ city: { type: "string", description: "City name" },
208
+ },
209
+ required: ["street", "city"],
210
+ description: "A postal address",
211
+ },
212
+ },
213
+ };
214
+
215
+ const result = convertJsonSchemaToZodSchema(jsonSchema, true);
216
+ const resultJson = zodToJsonSchema(result);
217
+
218
+ const expectedSchema = z.object({
219
+ address: z
220
+ .object({
221
+ street: z.string().describe("Street name"),
222
+ city: z.string().describe("City name"),
223
+ })
224
+ .describe("A postal address"),
225
+ });
226
+ const expectedJson = zodToJsonSchema(expectedSchema);
227
+
228
+ expect(resultJson).toStrictEqual(expectedJson);
229
+ });
230
+
231
+ it("should handle circular $ref without crashing and return z.any()", () => {
232
+ // A schema where Node references itself — this would cause infinite
233
+ // recursion without cycle detection.
234
+ const jsonSchema = {
235
+ type: "object",
236
+ properties: {
237
+ root: { $ref: "#/$defs/Node" },
238
+ },
239
+ required: ["root"],
240
+ $defs: {
241
+ Node: {
242
+ type: "object",
243
+ properties: {
244
+ value: { type: "string", description: "Node value" },
245
+ child: { $ref: "#/$defs/Node" },
246
+ },
247
+ required: ["value"],
248
+ description: "A tree node",
249
+ },
250
+ },
251
+ };
252
+
253
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
254
+
255
+ // Must not throw or hang
256
+ const result = convertJsonSchemaToZodSchema(jsonSchema, true);
257
+ expect(result).toBeDefined();
258
+
259
+ // The circular ref should have produced a console.warn
260
+ expect(warnSpy).toHaveBeenCalledWith(
261
+ expect.stringContaining("Circular $ref detected"),
262
+ );
263
+
264
+ // The top-level shape should still have a "root" key that is an object
265
+ const shape = (result as z.ZodObject<any>).shape;
266
+ expect(shape.root).toBeDefined();
267
+
268
+ // Inside root, "value" should be a string and "child" should be z.any()
269
+ // (child is optional since it's not in required[], so unwrap ZodOptional)
270
+ const rootShape = (shape.root as z.ZodObject<any>).shape;
271
+ expect(rootShape.value._def.typeName).toBe("ZodString");
272
+ const childDef = rootShape.child._def;
273
+ if (childDef.typeName === "ZodOptional") {
274
+ expect(childDef.innerType._def.typeName).toBe("ZodAny");
275
+ } else {
276
+ expect(childDef.typeName).toBe("ZodAny");
277
+ }
278
+
279
+ warnSpy.mockRestore();
280
+ });
281
+
282
+ it("should resolve the same $ref used by multiple sibling properties", () => {
283
+ // Two properties reference the same $def — the visited set must NOT
284
+ // mark the second usage as circular.
285
+ const jsonSchema = {
286
+ type: "object",
287
+ properties: {
288
+ billing: { $ref: "#/$defs/Address" },
289
+ shipping: { $ref: "#/$defs/Address" },
290
+ },
291
+ required: ["billing", "shipping"],
292
+ $defs: {
293
+ Address: {
294
+ type: "object",
295
+ properties: {
296
+ street: { type: "string", description: "Street" },
297
+ city: { type: "string", description: "City" },
298
+ },
299
+ required: ["street", "city"],
300
+ description: "An address",
301
+ },
302
+ },
303
+ };
304
+
305
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
306
+
307
+ const result = convertJsonSchemaToZodSchema(jsonSchema, true);
308
+ const shape = (result as z.ZodObject<any>).shape;
309
+
310
+ // Both should be fully resolved objects, NOT z.any()
311
+ expect(shape.billing._def.typeName).toBe("ZodObject");
312
+ expect(shape.shipping._def.typeName).toBe("ZodObject");
313
+
314
+ // No circular-ref warning should have been emitted
315
+ expect(warnSpy).not.toHaveBeenCalled();
316
+
317
+ warnSpy.mockRestore();
318
+ });
319
+
320
+ it("should resolve a shared $ref used in different branches of a $ref chain", () => {
321
+ // Wrapper -> Container (via $ref) which has two children both using $ref to Leaf.
322
+ // Without set cloning, the second Leaf ref in Container would be wrongly flagged
323
+ // as circular because the first Leaf resolution already added it to the set.
324
+ const jsonSchema = {
325
+ type: "object",
326
+ properties: {
327
+ wrapper: { $ref: "#/$defs/Container" },
328
+ },
329
+ required: ["wrapper"],
330
+ $defs: {
331
+ Container: {
332
+ type: "object",
333
+ properties: {
334
+ first: { $ref: "#/$defs/Leaf" },
335
+ second: { $ref: "#/$defs/Leaf" },
336
+ },
337
+ required: ["first", "second"],
338
+ description: "A container with two leaves",
339
+ },
340
+ Leaf: {
341
+ type: "object",
342
+ properties: {
343
+ label: { type: "string", description: "Leaf label" },
344
+ },
345
+ required: ["label"],
346
+ description: "A leaf node",
347
+ },
348
+ },
349
+ };
350
+
351
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
352
+
353
+ const result = convertJsonSchemaToZodSchema(jsonSchema, true);
354
+ const wrapperShape = (
355
+ (result as z.ZodObject<any>).shape.wrapper as z.ZodObject<any>
356
+ ).shape;
357
+
358
+ // Both first and second should be fully resolved Leaf objects
359
+ expect(wrapperShape.first._def.typeName).toBe("ZodObject");
360
+ expect(wrapperShape.second._def.typeName).toBe("ZodObject");
361
+
362
+ // No circular-ref warning should have been emitted
363
+ expect(warnSpy).not.toHaveBeenCalled();
364
+
365
+ warnSpy.mockRestore();
366
+ });
367
+
368
+ it("should handle anyOf with $ref variants", () => {
369
+ const jsonSchema = {
370
+ type: "object",
371
+ properties: {
372
+ pet: {
373
+ anyOf: [{ $ref: "#/$defs/Cat" }, { $ref: "#/$defs/Dog" }],
374
+ description: "A pet",
375
+ },
376
+ },
377
+ required: ["pet"],
378
+ $defs: {
379
+ Cat: {
380
+ type: "object",
381
+ properties: { meow: { type: "boolean" } },
382
+ required: ["meow"],
383
+ },
384
+ Dog: {
385
+ type: "object",
386
+ properties: { bark: { type: "boolean" } },
387
+ required: ["bark"],
388
+ },
389
+ },
390
+ };
391
+
392
+ const result = convertJsonSchemaToZodSchema(jsonSchema, true);
393
+ expect(result).toBeDefined();
394
+
395
+ // Should produce a union inside the "pet" property
396
+ const petSchema = (result as z.ZodObject<any>).shape.pet;
397
+ expect(petSchema._def.typeName).toBe("ZodUnion");
398
+ });
399
+
400
+ it("should handle integer type as z.number()", () => {
401
+ const jsonSchema = {
402
+ type: "object",
403
+ properties: {
404
+ count: { type: "integer", description: "A count" },
405
+ },
406
+ required: ["count"],
407
+ };
408
+
409
+ const result = convertJsonSchemaToZodSchema(jsonSchema, true);
410
+ const shape = (result as z.ZodObject<any>).shape;
411
+ expect(shape.count._def.typeName).toBe("ZodNumber");
412
+ });
413
+
414
+ it("should handle null type", () => {
415
+ const jsonSchema = {
416
+ type: "object",
417
+ properties: {
418
+ empty: { type: "null", description: "Always null" },
419
+ },
420
+ required: ["empty"],
421
+ };
422
+
423
+ const result = convertJsonSchemaToZodSchema(jsonSchema, true);
424
+ const shape = (result as z.ZodObject<any>).shape;
425
+ expect(shape.empty._def.typeName).toBe("ZodNull");
426
+ });
427
+
428
+ it("should warn and return z.any() for unsupported schema types", () => {
429
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
430
+
431
+ const jsonSchema = { type: "custom_unsupported" };
432
+ const result = convertJsonSchemaToZodSchema(jsonSchema, true);
433
+
434
+ expect(result._def.typeName).toBe("ZodAny");
435
+ expect(warnSpy).toHaveBeenCalledWith(
436
+ expect.stringContaining(
437
+ 'Unsupported JSON schema type "custom_unsupported"',
438
+ ),
439
+ );
440
+
441
+ warnSpy.mockRestore();
442
+ });
194
443
  });
195
444
 
196
445
  describe("jsonSchemaToActionParameters", () => {
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Safely copies text to the clipboard.
3
+ *
4
+ * Checks that the Clipboard API is available before attempting the write,
5
+ * and catches any errors (e.g. permission denied, insecure context).
6
+ *
7
+ * @param text - The text to copy to the clipboard.
8
+ * @returns `true` if the text was successfully copied, `false` otherwise.
9
+ */
10
+ export async function copyToClipboard(text: string): Promise<boolean> {
11
+ if (!navigator.clipboard?.writeText) {
12
+ console.error("Clipboard API is not available");
13
+ return false;
14
+ }
15
+
16
+ try {
17
+ await navigator.clipboard.writeText(text);
18
+ return true;
19
+ } catch (err) {
20
+ console.error("Failed to copy to clipboard:", err);
21
+ return false;
22
+ }
23
+ }
@@ -1,3 +1,4 @@
1
+ export * from "./clipboard";
1
2
  export * from "./conditions";
2
3
  export * from "./console-styling";
3
4
  export * from "./errors";
@@ -241,7 +241,69 @@ function convertAttribute(attribute: Parameter): JSONSchema {
241
241
  export function convertJsonSchemaToZodSchema(
242
242
  jsonSchema: any,
243
243
  required: boolean,
244
+ definitions?: Record<string, any>,
245
+ visitedRefs?: Set<string>,
244
246
  ): z.ZodSchema {
247
+ // Resolve $ref references
248
+ if (jsonSchema.$ref && definitions) {
249
+ const refPath = jsonSchema.$ref.replace(
250
+ /^#\/\$defs\/|^#\/definitions\//,
251
+ "",
252
+ );
253
+
254
+ // Detect circular $ref cycles
255
+ const refs = visitedRefs ?? new Set<string>();
256
+ if (refs.has(refPath)) {
257
+ console.warn(
258
+ `[CopilotKit] Circular $ref detected for "${refPath}" — falling back to z.any()`,
259
+ );
260
+ let schema = z.any();
261
+ if (jsonSchema.description) {
262
+ schema = schema.describe(jsonSchema.description);
263
+ }
264
+ return required ? schema : schema.optional();
265
+ }
266
+
267
+ const resolved = definitions[refPath];
268
+ if (resolved) {
269
+ // Clone the set so sibling branches don't see each other's visited refs
270
+ const nextRefs = new Set(refs);
271
+ nextRefs.add(refPath);
272
+ return convertJsonSchemaToZodSchema(
273
+ resolved,
274
+ required,
275
+ definitions,
276
+ nextRefs,
277
+ );
278
+ }
279
+ }
280
+
281
+ // Collect top-level definitions for $ref resolution
282
+ const defs = definitions ?? jsonSchema.$defs ?? jsonSchema.definitions;
283
+
284
+ // Handle anyOf / oneOf as z.union
285
+ const unionVariants = jsonSchema.anyOf ?? jsonSchema.oneOf;
286
+ if (Array.isArray(unionVariants) && unionVariants.length > 0) {
287
+ if (unionVariants.length === 1) {
288
+ return convertJsonSchemaToZodSchema(
289
+ unionVariants[0],
290
+ required,
291
+ defs,
292
+ visitedRefs,
293
+ );
294
+ }
295
+ const schemas = unionVariants.map((v: any) =>
296
+ convertJsonSchemaToZodSchema(v, true, defs, visitedRefs),
297
+ );
298
+ let schema = z.union(
299
+ schemas as [z.ZodSchema, z.ZodSchema, ...z.ZodSchema[]],
300
+ );
301
+ if (jsonSchema.description) {
302
+ schema = schema.describe(jsonSchema.description);
303
+ }
304
+ return required ? schema : schema.optional();
305
+ }
306
+
245
307
  if (jsonSchema.type === "object") {
246
308
  const spec: { [key: string]: z.ZodSchema } = {};
247
309
 
@@ -253,6 +315,8 @@ export function convertJsonSchemaToZodSchema(
253
315
  spec[key] = convertJsonSchemaToZodSchema(
254
316
  value,
255
317
  jsonSchema.required ? jsonSchema.required.includes(key) : false,
318
+ defs,
319
+ visitedRefs,
256
320
  );
257
321
  }
258
322
  let schema = z.object(spec).describe(jsonSchema.description);
@@ -266,18 +330,35 @@ export function convertJsonSchemaToZodSchema(
266
330
  }
267
331
  let schema = z.string().describe(jsonSchema.description);
268
332
  return required ? schema : schema.optional();
269
- } else if (jsonSchema.type === "number") {
333
+ } else if (jsonSchema.type === "number" || jsonSchema.type === "integer") {
270
334
  let schema = z.number().describe(jsonSchema.description);
271
335
  return required ? schema : schema.optional();
272
336
  } else if (jsonSchema.type === "boolean") {
273
337
  let schema = z.boolean().describe(jsonSchema.description);
274
338
  return required ? schema : schema.optional();
275
339
  } else if (jsonSchema.type === "array") {
276
- let itemSchema = convertJsonSchemaToZodSchema(jsonSchema.items, true);
340
+ let itemSchema = convertJsonSchemaToZodSchema(
341
+ jsonSchema.items,
342
+ true,
343
+ defs,
344
+ visitedRefs,
345
+ );
277
346
  let schema = z.array(itemSchema).describe(jsonSchema.description);
278
347
  return required ? schema : schema.optional();
348
+ } else if (jsonSchema.type === "null") {
349
+ let schema = z.null().describe(jsonSchema.description);
350
+ return required ? schema : schema.optional();
351
+ }
352
+
353
+ // Fallback: accept any value rather than throwing
354
+ console.warn(
355
+ `[CopilotKit] Unsupported JSON schema type "${jsonSchema.type ?? "unknown"}" — falling back to z.any()`,
356
+ );
357
+ let schema = z.any();
358
+ if (jsonSchema.description) {
359
+ schema = schema.describe(jsonSchema.description);
279
360
  }
280
- throw new Error("Invalid JSON schema");
361
+ return required ? schema : schema.optional();
281
362
  }
282
363
 
283
364
  export function getZodParameters<T extends [] | Parameter[] | undefined>(
@@ -1,3 +1,5 @@
1
+ import type { AgentCapabilities } from "@ag-ui/core";
2
+
1
3
  export type MaybePromise<T> = T | PromiseLike<T>;
2
4
 
3
5
  /**
@@ -17,6 +19,7 @@ export interface AgentDescription {
17
19
  name: string;
18
20
  className: string;
19
21
  description: string;
22
+ capabilities?: AgentCapabilities;
20
23
  }
21
24
 
22
25
  export type RuntimeMode = "sse" | "intelligence";