@copilotkit/shared 1.54.1 → 1.55.0-next.8

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 (87) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/dist/constants/index.cjs +5 -0
  3. package/dist/constants/index.cjs.map +1 -1
  4. package/dist/constants/index.d.cts +4 -1
  5. package/dist/constants/index.d.cts.map +1 -1
  6. package/dist/constants/index.d.mts +4 -1
  7. package/dist/constants/index.d.mts.map +1 -1
  8. package/dist/constants/index.mjs +4 -1
  9. package/dist/constants/index.mjs.map +1 -1
  10. package/dist/finalize-events.cjs +106 -0
  11. package/dist/finalize-events.cjs.map +1 -0
  12. package/dist/finalize-events.d.cts +11 -0
  13. package/dist/finalize-events.d.cts.map +1 -0
  14. package/dist/finalize-events.d.mts +11 -0
  15. package/dist/finalize-events.d.mts.map +1 -0
  16. package/dist/finalize-events.mjs +105 -0
  17. package/dist/finalize-events.mjs.map +1 -0
  18. package/dist/index.cjs +25 -0
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +9 -4
  21. package/dist/index.d.cts.map +1 -1
  22. package/dist/index.d.mts +9 -4
  23. package/dist/index.d.mts.map +1 -1
  24. package/dist/index.mjs +10 -3
  25. package/dist/index.mjs.map +1 -1
  26. package/dist/index.umd.js +286 -5
  27. package/dist/index.umd.js.map +1 -1
  28. package/dist/logger.cjs +7 -0
  29. package/dist/logger.cjs.map +1 -0
  30. package/dist/logger.d.cts +5 -0
  31. package/dist/logger.d.cts.map +1 -0
  32. package/dist/logger.d.mts +5 -0
  33. package/dist/logger.d.mts.map +1 -0
  34. package/dist/logger.mjs +6 -0
  35. package/dist/logger.mjs.map +1 -0
  36. package/dist/package.cjs +1 -1
  37. package/dist/package.mjs +1 -1
  38. package/dist/standard-schema.cjs +29 -0
  39. package/dist/standard-schema.cjs.map +1 -0
  40. package/dist/standard-schema.d.cts +32 -0
  41. package/dist/standard-schema.d.cts.map +1 -0
  42. package/dist/standard-schema.d.mts +32 -0
  43. package/dist/standard-schema.d.mts.map +1 -0
  44. package/dist/standard-schema.mjs +28 -0
  45. package/dist/standard-schema.mjs.map +1 -0
  46. package/dist/transcription-errors.cjs +84 -0
  47. package/dist/transcription-errors.cjs.map +1 -0
  48. package/dist/transcription-errors.d.cts +52 -0
  49. package/dist/transcription-errors.d.cts.map +1 -0
  50. package/dist/transcription-errors.d.mts +52 -0
  51. package/dist/transcription-errors.d.mts.map +1 -0
  52. package/dist/transcription-errors.mjs +82 -0
  53. package/dist/transcription-errors.mjs.map +1 -0
  54. package/dist/types/message.d.cts +1 -1
  55. package/dist/types/message.d.mts +1 -1
  56. package/dist/utils/index.cjs +49 -0
  57. package/dist/utils/index.cjs.map +1 -1
  58. package/dist/utils/index.d.cts +24 -2
  59. package/dist/utils/index.d.cts.map +1 -1
  60. package/dist/utils/index.d.mts +24 -2
  61. package/dist/utils/index.d.mts.map +1 -1
  62. package/dist/utils/index.mjs +45 -1
  63. package/dist/utils/index.mjs.map +1 -1
  64. package/dist/utils/types.cjs +9 -0
  65. package/dist/utils/types.cjs.map +1 -0
  66. package/dist/utils/types.d.cts +12 -1
  67. package/dist/utils/types.d.cts.map +1 -1
  68. package/dist/utils/types.d.mts +12 -1
  69. package/dist/utils/types.d.mts.map +1 -1
  70. package/dist/utils/types.mjs +7 -0
  71. package/dist/utils/types.mjs.map +1 -0
  72. package/package.json +11 -4
  73. package/src/__tests__/standard-schema-types.test.ts +144 -0
  74. package/src/__tests__/standard-schema.test.ts +267 -0
  75. package/src/__tests__/zod-regression.test.ts +319 -0
  76. package/src/constants/index.ts +5 -0
  77. package/src/finalize-events.ts +154 -0
  78. package/src/index.ts +12 -0
  79. package/src/logger.ts +1 -0
  80. package/src/standard-schema.ts +76 -0
  81. package/src/transcription-errors.ts +99 -0
  82. package/src/types/message.ts +1 -1
  83. package/src/utils/index.ts +58 -0
  84. package/src/utils/types.ts +21 -0
  85. package/src/utils.test.ts +66 -0
  86. package/tsconfig.json +9 -1
  87. package/tsdown.config.ts +10 -2
@@ -0,0 +1,319 @@
1
+ /**
2
+ * Regression tests proving that `schemaToJsonSchema` produces identical output
3
+ * to a direct `zodToJsonSchema` call for all common Zod patterns.
4
+ *
5
+ * These tests exist to guarantee that the Standard Schema migration did not
6
+ * change the JSON Schema output for existing Zod users.
7
+ */
8
+ import { describe, it, expect } from "vitest";
9
+ import { z } from "zod";
10
+ import { zodToJsonSchema } from "zod-to-json-schema";
11
+ import { schemaToJsonSchema } from "../standard-schema";
12
+
13
+ /**
14
+ * Helper: call zodToJsonSchema the same way the old code path did, then
15
+ * compare with the new schemaToJsonSchema path.
16
+ */
17
+ function expectIdenticalOutput(schema: z.ZodTypeAny) {
18
+ const direct = zodToJsonSchema(schema, { $refStrategy: "none" });
19
+ const migrated = schemaToJsonSchema(schema, { zodToJsonSchema });
20
+ expect(migrated).toEqual(direct);
21
+ }
22
+
23
+ describe("Zod regression — schemaToJsonSchema produces identical output to direct zodToJsonSchema", () => {
24
+ describe("simple object schemas", () => {
25
+ it("required string and number fields", () => {
26
+ expectIdenticalOutput(z.object({ name: z.string(), age: z.number() }));
27
+ });
28
+
29
+ it("optional fields", () => {
30
+ expectIdenticalOutput(
31
+ z.object({
32
+ city: z.string(),
33
+ units: z.enum(["celsius", "fahrenheit"]).optional(),
34
+ }),
35
+ );
36
+ });
37
+
38
+ it("empty object", () => {
39
+ expectIdenticalOutput(z.object({}));
40
+ });
41
+
42
+ it("object with default values", () => {
43
+ expectIdenticalOutput(
44
+ z.object({
45
+ page: z.number().default(1),
46
+ perPage: z.number().default(20),
47
+ query: z.string(),
48
+ }),
49
+ );
50
+ });
51
+ });
52
+
53
+ describe("nested objects", () => {
54
+ it("single level nesting", () => {
55
+ expectIdenticalOutput(
56
+ z.object({
57
+ user: z.object({ name: z.string(), email: z.string() }),
58
+ }),
59
+ );
60
+ });
61
+
62
+ it("deep nesting", () => {
63
+ expectIdenticalOutput(
64
+ z.object({
65
+ level1: z.object({
66
+ level2: z.object({
67
+ level3: z.object({
68
+ value: z.boolean(),
69
+ }),
70
+ }),
71
+ }),
72
+ }),
73
+ );
74
+ });
75
+ });
76
+
77
+ describe("arrays", () => {
78
+ it("string array", () => {
79
+ expectIdenticalOutput(z.object({ tags: z.array(z.string()) }));
80
+ });
81
+
82
+ it("object array", () => {
83
+ expectIdenticalOutput(
84
+ z.object({
85
+ items: z.array(z.object({ id: z.number(), label: z.string() })),
86
+ }),
87
+ );
88
+ });
89
+
90
+ it("nested arrays", () => {
91
+ expectIdenticalOutput(z.object({ matrix: z.array(z.array(z.number())) }));
92
+ });
93
+ });
94
+
95
+ describe("enums and literals", () => {
96
+ it("z.enum", () => {
97
+ expectIdenticalOutput(
98
+ z.object({ status: z.enum(["active", "inactive", "pending"]) }),
99
+ );
100
+ });
101
+
102
+ it("z.literal string", () => {
103
+ expectIdenticalOutput(z.object({ type: z.literal("user") }));
104
+ });
105
+
106
+ it("z.literal number", () => {
107
+ expectIdenticalOutput(z.object({ version: z.literal(2) }));
108
+ });
109
+
110
+ it("z.nativeEnum", () => {
111
+ enum Color {
112
+ Red = "red",
113
+ Green = "green",
114
+ Blue = "blue",
115
+ }
116
+ expectIdenticalOutput(z.object({ color: z.nativeEnum(Color) }));
117
+ });
118
+ });
119
+
120
+ describe("unions and discriminated unions", () => {
121
+ it("z.union of primitives", () => {
122
+ expectIdenticalOutput(
123
+ z.object({ value: z.union([z.string(), z.number()]) }),
124
+ );
125
+ });
126
+
127
+ it("z.union of objects", () => {
128
+ expectIdenticalOutput(
129
+ z.object({
130
+ result: z.union([
131
+ z.object({ ok: z.literal(true), data: z.string() }),
132
+ z.object({ ok: z.literal(false), error: z.string() }),
133
+ ]),
134
+ }),
135
+ );
136
+ });
137
+
138
+ it("z.discriminatedUnion", () => {
139
+ expectIdenticalOutput(
140
+ z.object({
141
+ event: z.discriminatedUnion("type", [
142
+ z.object({
143
+ type: z.literal("click"),
144
+ x: z.number(),
145
+ y: z.number(),
146
+ }),
147
+ z.object({ type: z.literal("keypress"), key: z.string() }),
148
+ ]),
149
+ }),
150
+ );
151
+ });
152
+ });
153
+
154
+ describe("nullable and nullish", () => {
155
+ it("z.nullable", () => {
156
+ expectIdenticalOutput(z.object({ bio: z.string().nullable() }));
157
+ });
158
+
159
+ it("z.nullish (optional + nullable)", () => {
160
+ expectIdenticalOutput(z.object({ nickname: z.string().nullish() }));
161
+ });
162
+ });
163
+
164
+ describe("records and tuples", () => {
165
+ it("z.record", () => {
166
+ expectIdenticalOutput(
167
+ z.object({ metadata: z.record(z.string(), z.unknown()) }),
168
+ );
169
+ });
170
+
171
+ it("z.tuple", () => {
172
+ expectIdenticalOutput(
173
+ z.object({ point: z.tuple([z.number(), z.number()]) }),
174
+ );
175
+ });
176
+ });
177
+
178
+ describe("intersections", () => {
179
+ it("z.intersection", () => {
180
+ expectIdenticalOutput(
181
+ z.intersection(
182
+ z.object({ id: z.number() }),
183
+ z.object({ name: z.string() }),
184
+ ),
185
+ );
186
+ });
187
+ });
188
+
189
+ describe("string constraints", () => {
190
+ it("z.string with min/max", () => {
191
+ expectIdenticalOutput(z.object({ username: z.string().min(3).max(20) }));
192
+ });
193
+
194
+ it("z.string with email", () => {
195
+ expectIdenticalOutput(z.object({ email: z.string().email() }));
196
+ });
197
+
198
+ it("z.string with url", () => {
199
+ expectIdenticalOutput(z.object({ website: z.string().url() }));
200
+ });
201
+
202
+ it("z.string with regex", () => {
203
+ expectIdenticalOutput(
204
+ z.object({ code: z.string().regex(/^[A-Z]{3}-\d{4}$/) }),
205
+ );
206
+ });
207
+ });
208
+
209
+ describe("number constraints", () => {
210
+ it("z.number with min/max", () => {
211
+ expectIdenticalOutput(z.object({ score: z.number().min(0).max(100) }));
212
+ });
213
+
214
+ it("z.number.int", () => {
215
+ expectIdenticalOutput(z.object({ count: z.number().int() }));
216
+ });
217
+
218
+ it("z.number.positive", () => {
219
+ expectIdenticalOutput(z.object({ amount: z.number().positive() }));
220
+ });
221
+ });
222
+
223
+ describe("catchall and passthrough", () => {
224
+ it("z.object with catchall", () => {
225
+ expectIdenticalOutput(z.object({}).catchall(z.string()));
226
+ });
227
+
228
+ it("z.object with passthrough", () => {
229
+ expectIdenticalOutput(z.object({ id: z.number() }).passthrough());
230
+ });
231
+ });
232
+
233
+ describe("z.any and z.unknown", () => {
234
+ it("z.any", () => {
235
+ expectIdenticalOutput(z.any());
236
+ });
237
+
238
+ it("z.unknown", () => {
239
+ expectIdenticalOutput(z.unknown());
240
+ });
241
+
242
+ it("object with z.any field", () => {
243
+ expectIdenticalOutput(z.object({ data: z.any() }));
244
+ });
245
+ });
246
+
247
+ describe("complex real-world schemas", () => {
248
+ it("tool-like schema with multiple field types", () => {
249
+ expectIdenticalOutput(
250
+ z.object({
251
+ query: z.string().describe("Search query"),
252
+ filters: z
253
+ .object({
254
+ category: z.enum(["books", "movies", "music"]).optional(),
255
+ minRating: z.number().min(0).max(5).optional(),
256
+ tags: z.array(z.string()).optional(),
257
+ })
258
+ .optional(),
259
+ pagination: z
260
+ .object({
261
+ page: z.number().int().positive().default(1),
262
+ perPage: z.number().int().positive().default(20),
263
+ })
264
+ .optional(),
265
+ sortBy: z.enum(["relevance", "date", "rating"]).default("relevance"),
266
+ }),
267
+ );
268
+ });
269
+
270
+ it("CopilotKit-like weather tool schema", () => {
271
+ expectIdenticalOutput(
272
+ z.object({
273
+ city: z.string().describe("The city to get weather for"),
274
+ units: z
275
+ .enum(["celsius", "fahrenheit"])
276
+ .optional()
277
+ .describe("Temperature units"),
278
+ }),
279
+ );
280
+ });
281
+
282
+ it("agent-like action schema with nested results", () => {
283
+ expectIdenticalOutput(
284
+ z.object({
285
+ action: z.discriminatedUnion("type", [
286
+ z.object({
287
+ type: z.literal("search"),
288
+ query: z.string(),
289
+ maxResults: z.number().int().optional(),
290
+ }),
291
+ z.object({
292
+ type: z.literal("navigate"),
293
+ url: z.string().url(),
294
+ }),
295
+ z.object({
296
+ type: z.literal("execute"),
297
+ code: z.string(),
298
+ language: z.enum(["javascript", "python", "shell"]),
299
+ }),
300
+ ]),
301
+ context: z.record(z.string(), z.unknown()).optional(),
302
+ }),
303
+ );
304
+ });
305
+ });
306
+
307
+ describe("described schemas (common in tool definitions)", () => {
308
+ it("preserves .describe() metadata", () => {
309
+ expectIdenticalOutput(
310
+ z
311
+ .object({
312
+ city: z.string().describe("The city name"),
313
+ count: z.number().describe("Number of results"),
314
+ })
315
+ .describe("Weather tool parameters"),
316
+ );
317
+ });
318
+ });
319
+ });
@@ -3,3 +3,8 @@ export const COPILOT_CLOUD_VERSION = "v1";
3
3
  export const COPILOT_CLOUD_CHAT_URL = `${COPILOT_CLOUD_API_URL}/copilotkit/${COPILOT_CLOUD_VERSION}`;
4
4
  export const COPILOT_CLOUD_PUBLIC_API_KEY_HEADER =
5
5
  "X-CopilotCloud-Public-Api-Key";
6
+
7
+ export const DEFAULT_AGENT_ID = "default";
8
+
9
+ /** Phoenix channel event name used for all AG-UI events. */
10
+ export const AG_UI_CHANNEL_EVENT = "ag-ui";
@@ -0,0 +1,154 @@
1
+ import { BaseEvent, EventType, RunErrorEvent } from "@ag-ui/client";
2
+ import { randomUUID } from "./utils";
3
+
4
+ interface FinalizeRunOptions {
5
+ stopRequested?: boolean;
6
+ interruptionMessage?: string;
7
+ }
8
+
9
+ const defaultStopMessage = "Run stopped by user";
10
+ const defaultAbruptEndMessage = "Run ended without emitting a terminal event";
11
+
12
+ export function finalizeRunEvents(
13
+ events: BaseEvent[],
14
+ options: FinalizeRunOptions = {},
15
+ ): BaseEvent[] {
16
+ const { stopRequested = false, interruptionMessage } = options;
17
+
18
+ const resolvedStopMessage = interruptionMessage ?? defaultStopMessage;
19
+ const resolvedAbruptMessage =
20
+ interruptionMessage && interruptionMessage !== defaultStopMessage
21
+ ? interruptionMessage
22
+ : defaultAbruptEndMessage;
23
+
24
+ const appended: BaseEvent[] = [];
25
+
26
+ const openMessageIds = new Set<string>();
27
+ const openToolCalls = new Map<
28
+ string,
29
+ {
30
+ hasEnd: boolean;
31
+ hasResult: boolean;
32
+ }
33
+ >();
34
+
35
+ for (const event of events) {
36
+ switch (event.type) {
37
+ case EventType.TEXT_MESSAGE_START: {
38
+ const messageId = (event as { messageId?: string }).messageId;
39
+ if (typeof messageId === "string") {
40
+ openMessageIds.add(messageId);
41
+ }
42
+ break;
43
+ }
44
+ case EventType.TEXT_MESSAGE_END: {
45
+ const messageId = (event as { messageId?: string }).messageId;
46
+ if (typeof messageId === "string") {
47
+ openMessageIds.delete(messageId);
48
+ }
49
+ break;
50
+ }
51
+ case EventType.TOOL_CALL_START: {
52
+ const toolCallId = (event as { toolCallId?: string }).toolCallId;
53
+ if (typeof toolCallId === "string") {
54
+ openToolCalls.set(toolCallId, {
55
+ hasEnd: false,
56
+ hasResult: false,
57
+ });
58
+ }
59
+ break;
60
+ }
61
+ case EventType.TOOL_CALL_END: {
62
+ const toolCallId = (event as { toolCallId?: string }).toolCallId;
63
+ const info = toolCallId ? openToolCalls.get(toolCallId) : undefined;
64
+ if (info) {
65
+ info.hasEnd = true;
66
+ }
67
+ break;
68
+ }
69
+ case EventType.TOOL_CALL_RESULT: {
70
+ const toolCallId = (event as { toolCallId?: string }).toolCallId;
71
+ const info = toolCallId ? openToolCalls.get(toolCallId) : undefined;
72
+ if (info) {
73
+ info.hasResult = true;
74
+ }
75
+ break;
76
+ }
77
+ default:
78
+ break;
79
+ }
80
+ }
81
+
82
+ const hasRunFinished = events.some(
83
+ (event) => event.type === EventType.RUN_FINISHED,
84
+ );
85
+ const hasRunError = events.some(
86
+ (event) => event.type === EventType.RUN_ERROR,
87
+ );
88
+ const hasTerminalEvent = hasRunFinished || hasRunError;
89
+ const terminalEventMissing = !hasTerminalEvent;
90
+
91
+ for (const messageId of openMessageIds) {
92
+ const endEvent = {
93
+ type: EventType.TEXT_MESSAGE_END,
94
+ messageId,
95
+ } as BaseEvent;
96
+ events.push(endEvent);
97
+ appended.push(endEvent);
98
+ }
99
+
100
+ for (const [toolCallId, info] of openToolCalls) {
101
+ if (!info.hasEnd) {
102
+ const endEvent = {
103
+ type: EventType.TOOL_CALL_END,
104
+ toolCallId,
105
+ } as BaseEvent;
106
+ events.push(endEvent);
107
+ appended.push(endEvent);
108
+ }
109
+
110
+ if (terminalEventMissing && !info.hasResult) {
111
+ const resultEvent = {
112
+ type: EventType.TOOL_CALL_RESULT,
113
+ toolCallId,
114
+ messageId: `${toolCallId ?? randomUUID()}-result`,
115
+ role: "tool",
116
+ content: JSON.stringify(
117
+ stopRequested
118
+ ? {
119
+ status: "stopped",
120
+ reason: "stop_requested",
121
+ message: resolvedStopMessage,
122
+ }
123
+ : {
124
+ status: "error",
125
+ reason: "missing_terminal_event",
126
+ message: resolvedAbruptMessage,
127
+ },
128
+ ),
129
+ } as BaseEvent;
130
+ events.push(resultEvent);
131
+ appended.push(resultEvent);
132
+ }
133
+ }
134
+
135
+ if (terminalEventMissing) {
136
+ if (stopRequested) {
137
+ const finishedEvent = {
138
+ type: EventType.RUN_FINISHED,
139
+ } as BaseEvent;
140
+ events.push(finishedEvent);
141
+ appended.push(finishedEvent);
142
+ } else {
143
+ const errorEvent: RunErrorEvent = {
144
+ type: EventType.RUN_ERROR,
145
+ message: resolvedAbruptMessage,
146
+ code: "INCOMPLETE_STREAM",
147
+ };
148
+ events.push(errorEvent);
149
+ appended.push(errorEvent);
150
+ }
151
+ }
152
+
153
+ return appended;
154
+ }
package/src/index.ts CHANGED
@@ -2,6 +2,18 @@ export * from "./types";
2
2
  export * from "./utils";
3
3
  export * from "./constants";
4
4
  export * from "./telemetry";
5
+ export * from "./standard-schema";
6
+
7
+ export { logger } from "./logger";
8
+ export { finalizeRunEvents } from "./finalize-events";
9
+
10
+ export {
11
+ TranscriptionErrorCode,
12
+ TranscriptionErrors,
13
+ type TranscriptionErrorResponse,
14
+ } from "./transcription-errors";
5
15
 
6
16
  import * as packageJson from "../package.json";
7
17
  export const COPILOTKIT_VERSION = packageJson.version;
18
+
19
+ export * from "@copilotkit/license-verifier";
package/src/logger.ts ADDED
@@ -0,0 +1 @@
1
+ export const logger = console;
@@ -0,0 +1,76 @@
1
+ import type {
2
+ StandardSchemaV1,
3
+ StandardJSONSchemaV1,
4
+ } from "@standard-schema/spec";
5
+
6
+ export type { StandardSchemaV1, StandardJSONSchemaV1 };
7
+
8
+ /**
9
+ * Extract the Output type from a StandardSchemaV1 schema.
10
+ * Replaces `z.infer<S>` for generic schema inference.
11
+ */
12
+ export type InferSchemaOutput<S> =
13
+ S extends StandardSchemaV1<any, infer O> ? O : never;
14
+
15
+ export interface SchemaToJsonSchemaOptions {
16
+ /**
17
+ * Injected `zodToJsonSchema` function so that `shared` does not depend on
18
+ * `zod-to-json-schema`. Required when the schema is a Zod v3 schema that
19
+ * does not implement Standard JSON Schema V1.
20
+ */
21
+ zodToJsonSchema?: (
22
+ schema: unknown,
23
+ options?: { $refStrategy?: string },
24
+ ) => Record<string, unknown>;
25
+ }
26
+
27
+ /**
28
+ * Check whether a schema implements the Standard JSON Schema V1 protocol.
29
+ */
30
+ function hasStandardJsonSchema(
31
+ schema: StandardSchemaV1,
32
+ ): schema is StandardSchemaV1 & StandardJSONSchemaV1 {
33
+ const props = schema["~standard"];
34
+ return (
35
+ props != null &&
36
+ typeof props === "object" &&
37
+ "jsonSchema" in props &&
38
+ props.jsonSchema != null &&
39
+ typeof props.jsonSchema === "object" &&
40
+ "input" in props.jsonSchema &&
41
+ typeof props.jsonSchema.input === "function"
42
+ );
43
+ }
44
+
45
+ /**
46
+ * Convert any StandardSchemaV1-compatible schema to a JSON Schema object.
47
+ *
48
+ * Strategy:
49
+ * 1. If the schema implements Standard JSON Schema V1 (`~standard.jsonSchema`),
50
+ * call `schema['~standard'].jsonSchema.input({ target: 'draft-07' })`.
51
+ * 2. If the schema is a Zod v3 schema (`~standard.vendor === 'zod'`), use the
52
+ * injected `zodToJsonSchema()` function.
53
+ * 3. Otherwise throw a descriptive error.
54
+ */
55
+ export function schemaToJsonSchema(
56
+ schema: StandardSchemaV1,
57
+ options?: SchemaToJsonSchemaOptions,
58
+ ): Record<string, unknown> {
59
+ // 1. Standard JSON Schema V1
60
+ if (hasStandardJsonSchema(schema)) {
61
+ return schema["~standard"].jsonSchema.input({ target: "draft-07" });
62
+ }
63
+
64
+ // 2. Zod v3 fallback
65
+ const vendor = schema["~standard"].vendor;
66
+ if (vendor === "zod" && options?.zodToJsonSchema) {
67
+ return options.zodToJsonSchema(schema, { $refStrategy: "none" });
68
+ }
69
+
70
+ throw new Error(
71
+ `Cannot convert schema to JSON Schema. The schema (vendor: "${vendor}") does not implement Standard JSON Schema V1 ` +
72
+ `and no zodToJsonSchema fallback is available. ` +
73
+ `Use a library that supports Standard JSON Schema (e.g., Zod 3.24+, Valibot v1+, ArkType v2+) ` +
74
+ `or pass a zodToJsonSchema function in options.`,
75
+ );
76
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Error codes for transcription HTTP responses.
3
+ * Uses snake_case to align with existing CopilotKitCoreErrorCode pattern.
4
+ * These codes are returned by the runtime and parsed by the client.
5
+ */
6
+ export enum TranscriptionErrorCode {
7
+ /** Transcription service not configured in runtime */
8
+ SERVICE_NOT_CONFIGURED = "service_not_configured",
9
+ /** Audio format not supported */
10
+ INVALID_AUDIO_FORMAT = "invalid_audio_format",
11
+ /** Audio file is too long */
12
+ AUDIO_TOO_LONG = "audio_too_long",
13
+ /** Audio file is empty or too short */
14
+ AUDIO_TOO_SHORT = "audio_too_short",
15
+ /** Rate limited by transcription provider */
16
+ RATE_LIMITED = "rate_limited",
17
+ /** Authentication failed with transcription provider */
18
+ AUTH_FAILED = "auth_failed",
19
+ /** Transcription provider returned an error */
20
+ PROVIDER_ERROR = "provider_error",
21
+ /** Network error during transcription */
22
+ NETWORK_ERROR = "network_error",
23
+ /** Invalid request format */
24
+ INVALID_REQUEST = "invalid_request",
25
+ }
26
+
27
+ /**
28
+ * Error response format returned by the transcription endpoint.
29
+ */
30
+ export interface TranscriptionErrorResponse {
31
+ error: TranscriptionErrorCode;
32
+ message: string;
33
+ retryable?: boolean;
34
+ }
35
+
36
+ /**
37
+ * Helper functions to create transcription error responses.
38
+ * Used by the runtime to return consistent error responses.
39
+ */
40
+ export const TranscriptionErrors = {
41
+ serviceNotConfigured: (): TranscriptionErrorResponse => ({
42
+ error: TranscriptionErrorCode.SERVICE_NOT_CONFIGURED,
43
+ message: "Transcription service is not configured",
44
+ retryable: false,
45
+ }),
46
+
47
+ invalidAudioFormat: (
48
+ format: string,
49
+ supported: string[],
50
+ ): TranscriptionErrorResponse => ({
51
+ error: TranscriptionErrorCode.INVALID_AUDIO_FORMAT,
52
+ message: `Unsupported audio format: ${format}. Supported: ${supported.join(", ")}`,
53
+ retryable: false,
54
+ }),
55
+
56
+ invalidRequest: (details: string): TranscriptionErrorResponse => ({
57
+ error: TranscriptionErrorCode.INVALID_REQUEST,
58
+ message: details,
59
+ retryable: false,
60
+ }),
61
+
62
+ rateLimited: (): TranscriptionErrorResponse => ({
63
+ error: TranscriptionErrorCode.RATE_LIMITED,
64
+ message: "Rate limited. Please try again later.",
65
+ retryable: true,
66
+ }),
67
+
68
+ authFailed: (): TranscriptionErrorResponse => ({
69
+ error: TranscriptionErrorCode.AUTH_FAILED,
70
+ message: "Authentication failed with transcription provider",
71
+ retryable: false,
72
+ }),
73
+
74
+ providerError: (message: string): TranscriptionErrorResponse => ({
75
+ error: TranscriptionErrorCode.PROVIDER_ERROR,
76
+ message,
77
+ retryable: true,
78
+ }),
79
+
80
+ networkError: (
81
+ message: string = "Network error during transcription",
82
+ ): TranscriptionErrorResponse => ({
83
+ error: TranscriptionErrorCode.NETWORK_ERROR,
84
+ message,
85
+ retryable: true,
86
+ }),
87
+
88
+ audioTooLong: (): TranscriptionErrorResponse => ({
89
+ error: TranscriptionErrorCode.AUDIO_TOO_LONG,
90
+ message: "Audio file is too long",
91
+ retryable: false,
92
+ }),
93
+
94
+ audioTooShort: (): TranscriptionErrorResponse => ({
95
+ error: TranscriptionErrorCode.AUDIO_TOO_SHORT,
96
+ message: "Audio is too short to transcribe",
97
+ retryable: false,
98
+ }),
99
+ };
@@ -1,4 +1,4 @@
1
- import agui from "@ag-ui/core";
1
+ import * as agui from "@ag-ui/core";
2
2
 
3
3
  export interface ImageData {
4
4
  format: string;