xo-harness 0.1.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.
Files changed (86) hide show
  1. package/README.md +32 -0
  2. package/dist/harness.d.ts +1 -0
  3. package/dist/harness.js +1 -0
  4. package/dist/index.d.ts +4 -0
  5. package/dist/index.js +4 -0
  6. package/dist/internal/harness/event-stream.d.ts +7 -0
  7. package/dist/internal/harness/event-stream.js +42 -0
  8. package/dist/internal/harness/index.d.ts +7 -0
  9. package/dist/internal/harness/index.js +7 -0
  10. package/dist/internal/harness/message.d.ts +26 -0
  11. package/dist/internal/harness/message.js +192 -0
  12. package/dist/internal/harness/report.d.ts +51 -0
  13. package/dist/internal/harness/report.js +115 -0
  14. package/dist/internal/harness/shadow.d.ts +28 -0
  15. package/dist/internal/harness/shadow.js +118 -0
  16. package/dist/internal/harness/socket-bridge.d.ts +65 -0
  17. package/dist/internal/harness/socket-bridge.js +227 -0
  18. package/dist/internal/harness/task-supervisor.d.ts +20 -0
  19. package/dist/internal/harness/task-supervisor.js +180 -0
  20. package/dist/internal/harness/tool-runtime.d.ts +20 -0
  21. package/dist/internal/harness/tool-runtime.js +93 -0
  22. package/dist/internal/harness/tools.d.ts +32 -0
  23. package/dist/internal/harness/tools.js +30 -0
  24. package/dist/internal/harness/voice-session.d.ts +33 -0
  25. package/dist/internal/harness/voice-session.js +268 -0
  26. package/dist/internal/harness/xo.d.ts +25 -0
  27. package/dist/internal/harness/xo.js +24 -0
  28. package/dist/internal/protocol/async-queue.d.ts +8 -0
  29. package/dist/internal/protocol/async-queue.js +34 -0
  30. package/dist/internal/protocol/audio.d.ts +12 -0
  31. package/dist/internal/protocol/audio.js +24 -0
  32. package/dist/internal/protocol/events.d.ts +350 -0
  33. package/dist/internal/protocol/events.js +167 -0
  34. package/dist/internal/protocol/index.d.ts +6 -0
  35. package/dist/internal/protocol/index.js +6 -0
  36. package/dist/internal/protocol/parts.d.ts +219 -0
  37. package/dist/internal/protocol/parts.js +105 -0
  38. package/dist/internal/protocol/provider.d.ts +118 -0
  39. package/dist/internal/protocol/provider.js +77 -0
  40. package/dist/internal/protocol/tools.d.ts +62 -0
  41. package/dist/internal/protocol/tools.js +47 -0
  42. package/dist/internal/provider/contract.d.ts +24 -0
  43. package/dist/internal/provider/contract.js +1 -0
  44. package/dist/internal/provider/grok-voice.d.ts +45 -0
  45. package/dist/internal/provider/grok-voice.js +77 -0
  46. package/dist/internal/provider/index.d.ts +6 -0
  47. package/dist/internal/provider/index.js +9 -0
  48. package/dist/internal/provider/node-socket.d.ts +3 -0
  49. package/dist/internal/provider/node-socket.js +74 -0
  50. package/dist/internal/provider/openai-realtime.d.ts +43 -0
  51. package/dist/internal/provider/openai-realtime.js +76 -0
  52. package/dist/internal/provider/realtime-session.d.ts +30 -0
  53. package/dist/internal/provider/realtime-session.js +461 -0
  54. package/dist/internal/provider/realtime-socket.d.ts +42 -0
  55. package/dist/internal/provider/realtime-socket.js +30 -0
  56. package/dist/internal/provider/workers-socket.d.ts +11 -0
  57. package/dist/internal/provider/workers-socket.js +108 -0
  58. package/dist/internal/provider/workers.d.ts +6 -0
  59. package/dist/internal/provider/workers.js +11 -0
  60. package/dist/internal/provider-fake/index.d.ts +46 -0
  61. package/dist/internal/provider-fake/index.js +112 -0
  62. package/dist/internal/provider-fake/replay-voice-provider.d.ts +47 -0
  63. package/dist/internal/provider-fake/replay-voice-provider.js +133 -0
  64. package/dist/internal/provider-fake/scripted-voice-provider.d.ts +61 -0
  65. package/dist/internal/provider-fake/scripted-voice-provider.js +185 -0
  66. package/dist/internal/storage/append-tail.d.ts +12 -0
  67. package/dist/internal/storage/append-tail.js +19 -0
  68. package/dist/internal/storage/event-store.d.ts +19 -0
  69. package/dist/internal/storage/event-store.js +1 -0
  70. package/dist/internal/storage/index.d.ts +4 -0
  71. package/dist/internal/storage/index.js +4 -0
  72. package/dist/internal/storage/jsonl-event-store.d.ts +13 -0
  73. package/dist/internal/storage/jsonl-event-store.js +105 -0
  74. package/dist/internal/storage/memory-event-store.d.ts +8 -0
  75. package/dist/internal/storage/memory-event-store.js +22 -0
  76. package/dist/protocol.d.ts +1 -0
  77. package/dist/protocol.js +1 -0
  78. package/dist/provider-workers.d.ts +1 -0
  79. package/dist/provider-workers.js +1 -0
  80. package/dist/provider.d.ts +1 -0
  81. package/dist/provider.js +1 -0
  82. package/dist/storage.d.ts +1 -0
  83. package/dist/storage.js +1 -0
  84. package/dist/testing.d.ts +1 -0
  85. package/dist/testing.js +1 -0
  86. package/package.json +76 -0
@@ -0,0 +1,350 @@
1
+ import { z } from "zod";
2
+ /** Bounds for a typed user message, shared by the event, the session API, and wire schemas. */
3
+ export declare const MessageInputTextSchema: z.ZodString;
4
+ /**
5
+ * The authoritative session log: every observable fact of a conversation, in one flat,
6
+ * durably ordered stream. There is deliberately no turn or message hierarchy here —
7
+ * duplex audio overlaps — conversation views are projections over this log.
8
+ * The full catalog with ordering rules lives in docs/protocol.md.
9
+ */
10
+ export declare const HarnessEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
11
+ id: z.ZodString;
12
+ sessionId: z.ZodString;
13
+ sequence: z.ZodInt;
14
+ recordedAtMs: z.ZodNumber;
15
+ sessionTimeMs: z.ZodNumber;
16
+ correlationId: z.ZodOptional<z.ZodString>;
17
+ causationId: z.ZodOptional<z.ZodString>;
18
+ type: z.ZodLiteral<"session.started">;
19
+ formatVersion: z.ZodOptional<z.ZodInt>;
20
+ providerId: z.ZodString;
21
+ capabilities: z.ZodObject<{
22
+ continuousInputDuringOutput: z.ZodBoolean;
23
+ modelManagedFloor: z.ZodBoolean;
24
+ supportsToolCalls: z.ZodBoolean;
25
+ supportsAsyncContext: z.ZodBoolean;
26
+ supportsPlayoutAcknowledgements: z.ZodBoolean;
27
+ }, z.core.$strip>;
28
+ instructions: z.ZodOptional<z.ZodString>;
29
+ outputModalities: z.ZodOptional<z.ZodArray<z.ZodEnum<{
30
+ audio: "audio";
31
+ text: "text";
32
+ }>>>;
33
+ }, z.core.$strip>, z.ZodObject<{
34
+ id: z.ZodString;
35
+ sessionId: z.ZodString;
36
+ sequence: z.ZodInt;
37
+ recordedAtMs: z.ZodNumber;
38
+ sessionTimeMs: z.ZodNumber;
39
+ correlationId: z.ZodOptional<z.ZodString>;
40
+ causationId: z.ZodOptional<z.ZodString>;
41
+ type: z.ZodLiteral<"session.ended">;
42
+ reason: z.ZodString;
43
+ }, z.core.$strip>, z.ZodObject<{
44
+ id: z.ZodString;
45
+ sessionId: z.ZodString;
46
+ sequence: z.ZodInt;
47
+ recordedAtMs: z.ZodNumber;
48
+ sessionTimeMs: z.ZodNumber;
49
+ correlationId: z.ZodOptional<z.ZodString>;
50
+ causationId: z.ZodOptional<z.ZodString>;
51
+ type: z.ZodLiteral<"provider.ready">;
52
+ }, z.core.$strip>, z.ZodObject<{
53
+ id: z.ZodString;
54
+ sessionId: z.ZodString;
55
+ sequence: z.ZodInt;
56
+ recordedAtMs: z.ZodNumber;
57
+ sessionTimeMs: z.ZodNumber;
58
+ correlationId: z.ZodOptional<z.ZodString>;
59
+ causationId: z.ZodOptional<z.ZodString>;
60
+ type: z.ZodLiteral<"provider.closed">;
61
+ reason: z.ZodString;
62
+ }, z.core.$strip>, z.ZodObject<{
63
+ id: z.ZodString;
64
+ sessionId: z.ZodString;
65
+ sequence: z.ZodInt;
66
+ recordedAtMs: z.ZodNumber;
67
+ sessionTimeMs: z.ZodNumber;
68
+ correlationId: z.ZodOptional<z.ZodString>;
69
+ causationId: z.ZodOptional<z.ZodString>;
70
+ type: z.ZodLiteral<"provider.error">;
71
+ message: z.ZodString;
72
+ recoverable: z.ZodBoolean;
73
+ }, z.core.$strip>, z.ZodObject<{
74
+ id: z.ZodString;
75
+ sessionId: z.ZodString;
76
+ sequence: z.ZodInt;
77
+ recordedAtMs: z.ZodNumber;
78
+ sessionTimeMs: z.ZodNumber;
79
+ correlationId: z.ZodOptional<z.ZodString>;
80
+ causationId: z.ZodOptional<z.ZodString>;
81
+ type: z.ZodLiteral<"message.input">;
82
+ text: z.ZodString;
83
+ parts: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
84
+ type: z.ZodLiteral<"text">;
85
+ text: z.ZodString;
86
+ }, z.core.$strip>, z.ZodObject<{
87
+ type: z.ZodLiteral<"image">;
88
+ mediaType: z.ZodString;
89
+ url: z.ZodString;
90
+ }, z.core.$strip>, z.ZodObject<{
91
+ type: z.ZodLiteral<"file">;
92
+ mediaType: z.ZodString;
93
+ url: z.ZodString;
94
+ filename: z.ZodOptional<z.ZodString>;
95
+ }, z.core.$strip>], "type">>>;
96
+ }, z.core.$strip>, z.ZodObject<{
97
+ id: z.ZodString;
98
+ sessionId: z.ZodString;
99
+ sequence: z.ZodInt;
100
+ recordedAtMs: z.ZodNumber;
101
+ sessionTimeMs: z.ZodNumber;
102
+ correlationId: z.ZodOptional<z.ZodString>;
103
+ causationId: z.ZodOptional<z.ZodString>;
104
+ type: z.ZodLiteral<"audio.input">;
105
+ chunk: z.ZodObject<{
106
+ streamId: z.ZodString;
107
+ sequence: z.ZodInt;
108
+ encoding: z.ZodLiteral<"pcm_s16le">;
109
+ sampleRate: z.ZodInt;
110
+ channels: z.ZodInt;
111
+ startSample: z.ZodInt;
112
+ data: z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>;
113
+ }, z.core.$strip>;
114
+ }, z.core.$strip>, z.ZodObject<{
115
+ id: z.ZodString;
116
+ sessionId: z.ZodString;
117
+ sequence: z.ZodInt;
118
+ recordedAtMs: z.ZodNumber;
119
+ sessionTimeMs: z.ZodNumber;
120
+ correlationId: z.ZodOptional<z.ZodString>;
121
+ causationId: z.ZodOptional<z.ZodString>;
122
+ type: z.ZodLiteral<"audio.output">;
123
+ chunk: z.ZodObject<{
124
+ streamId: z.ZodString;
125
+ sequence: z.ZodInt;
126
+ encoding: z.ZodLiteral<"pcm_s16le">;
127
+ sampleRate: z.ZodInt;
128
+ channels: z.ZodInt;
129
+ startSample: z.ZodInt;
130
+ data: z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>;
131
+ }, z.core.$strip>;
132
+ }, z.core.$strip>, z.ZodObject<{
133
+ role: z.ZodEnum<{
134
+ assistant: "assistant";
135
+ user: "user";
136
+ }>;
137
+ text: z.ZodString;
138
+ streamId: z.ZodOptional<z.ZodString>;
139
+ id: z.ZodString;
140
+ sessionId: z.ZodString;
141
+ sequence: z.ZodInt;
142
+ recordedAtMs: z.ZodNumber;
143
+ sessionTimeMs: z.ZodNumber;
144
+ correlationId: z.ZodOptional<z.ZodString>;
145
+ causationId: z.ZodOptional<z.ZodString>;
146
+ type: z.ZodLiteral<"transcript">;
147
+ }, z.core.$strip>, z.ZodObject<{
148
+ role: z.ZodEnum<{
149
+ assistant: "assistant";
150
+ user: "user";
151
+ }>;
152
+ delta: z.ZodString;
153
+ streamId: z.ZodOptional<z.ZodString>;
154
+ id: z.ZodString;
155
+ sessionId: z.ZodString;
156
+ sequence: z.ZodInt;
157
+ recordedAtMs: z.ZodNumber;
158
+ sessionTimeMs: z.ZodNumber;
159
+ correlationId: z.ZodOptional<z.ZodString>;
160
+ causationId: z.ZodOptional<z.ZodString>;
161
+ type: z.ZodLiteral<"transcript.delta">;
162
+ }, z.core.$strip>, z.ZodObject<{
163
+ inputTokens: z.ZodNumber;
164
+ outputTokens: z.ZodNumber;
165
+ totalTokens: z.ZodNumber;
166
+ cachedInputTokens: z.ZodOptional<z.ZodNumber>;
167
+ audioInputTokens: z.ZodOptional<z.ZodNumber>;
168
+ audioOutputTokens: z.ZodOptional<z.ZodNumber>;
169
+ cachedAudioInputTokens: z.ZodOptional<z.ZodNumber>;
170
+ id: z.ZodString;
171
+ sessionId: z.ZodString;
172
+ sequence: z.ZodInt;
173
+ recordedAtMs: z.ZodNumber;
174
+ sessionTimeMs: z.ZodNumber;
175
+ correlationId: z.ZodOptional<z.ZodString>;
176
+ causationId: z.ZodOptional<z.ZodString>;
177
+ type: z.ZodLiteral<"usage">;
178
+ }, z.core.$strip>, z.ZodObject<{
179
+ id: z.ZodString;
180
+ sessionId: z.ZodString;
181
+ sequence: z.ZodInt;
182
+ recordedAtMs: z.ZodNumber;
183
+ sessionTimeMs: z.ZodNumber;
184
+ correlationId: z.ZodOptional<z.ZodString>;
185
+ causationId: z.ZodOptional<z.ZodString>;
186
+ type: z.ZodLiteral<"playout.progress">;
187
+ streamId: z.ZodString;
188
+ playedThroughSample: z.ZodInt;
189
+ }, z.core.$strip>, z.ZodObject<{
190
+ id: z.ZodString;
191
+ sessionId: z.ZodString;
192
+ sequence: z.ZodInt;
193
+ recordedAtMs: z.ZodNumber;
194
+ sessionTimeMs: z.ZodNumber;
195
+ correlationId: z.ZodOptional<z.ZodString>;
196
+ causationId: z.ZodOptional<z.ZodString>;
197
+ type: z.ZodLiteral<"tool.requested">;
198
+ call: z.ZodObject<{
199
+ callId: z.ZodString;
200
+ name: z.ZodString;
201
+ arguments: z.ZodRecord<z.ZodString, z.ZodUnknown>;
202
+ }, z.core.$strip>;
203
+ }, z.core.$strip>, z.ZodObject<{
204
+ id: z.ZodString;
205
+ sessionId: z.ZodString;
206
+ sequence: z.ZodInt;
207
+ recordedAtMs: z.ZodNumber;
208
+ sessionTimeMs: z.ZodNumber;
209
+ correlationId: z.ZodOptional<z.ZodString>;
210
+ causationId: z.ZodOptional<z.ZodString>;
211
+ type: z.ZodLiteral<"tool.started">;
212
+ callId: z.ZodString;
213
+ name: z.ZodString;
214
+ }, z.core.$strip>, z.ZodObject<{
215
+ id: z.ZodString;
216
+ sessionId: z.ZodString;
217
+ sequence: z.ZodInt;
218
+ recordedAtMs: z.ZodNumber;
219
+ sessionTimeMs: z.ZodNumber;
220
+ correlationId: z.ZodOptional<z.ZodString>;
221
+ causationId: z.ZodOptional<z.ZodString>;
222
+ type: z.ZodLiteral<"tool.progress">;
223
+ callId: z.ZodString;
224
+ update: z.ZodJSONSchema;
225
+ }, z.core.$strip>, z.ZodObject<{
226
+ id: z.ZodString;
227
+ sessionId: z.ZodString;
228
+ sequence: z.ZodInt;
229
+ recordedAtMs: z.ZodNumber;
230
+ sessionTimeMs: z.ZodNumber;
231
+ correlationId: z.ZodOptional<z.ZodString>;
232
+ causationId: z.ZodOptional<z.ZodString>;
233
+ type: z.ZodLiteral<"tool.completed">;
234
+ callId: z.ZodString;
235
+ outcome: z.ZodDiscriminatedUnion<[z.ZodObject<{
236
+ type: z.ZodLiteral<"completed">;
237
+ value: z.ZodJSONSchema;
238
+ }, z.core.$strip>, z.ZodObject<{
239
+ type: z.ZodLiteral<"accepted_task">;
240
+ taskId: z.ZodString;
241
+ }, z.core.$strip>, z.ZodObject<{
242
+ type: z.ZodLiteral<"failed">;
243
+ error: z.ZodString;
244
+ }, z.core.$strip>], "type">;
245
+ }, z.core.$strip>, z.ZodObject<{
246
+ id: z.ZodString;
247
+ sessionId: z.ZodString;
248
+ sequence: z.ZodInt;
249
+ recordedAtMs: z.ZodNumber;
250
+ sessionTimeMs: z.ZodNumber;
251
+ correlationId: z.ZodOptional<z.ZodString>;
252
+ causationId: z.ZodOptional<z.ZodString>;
253
+ type: z.ZodLiteral<"tool.failed">;
254
+ callId: z.ZodString;
255
+ error: z.ZodString;
256
+ }, z.core.$strip>, z.ZodObject<{
257
+ id: z.ZodString;
258
+ sessionId: z.ZodString;
259
+ sequence: z.ZodInt;
260
+ recordedAtMs: z.ZodNumber;
261
+ sessionTimeMs: z.ZodNumber;
262
+ correlationId: z.ZodOptional<z.ZodString>;
263
+ causationId: z.ZodOptional<z.ZodString>;
264
+ type: z.ZodLiteral<"tool.delivery_failed">;
265
+ callId: z.ZodString;
266
+ error: z.ZodString;
267
+ }, z.core.$strip>, z.ZodObject<{
268
+ id: z.ZodString;
269
+ sessionId: z.ZodString;
270
+ sequence: z.ZodInt;
271
+ recordedAtMs: z.ZodNumber;
272
+ sessionTimeMs: z.ZodNumber;
273
+ correlationId: z.ZodOptional<z.ZodString>;
274
+ causationId: z.ZodOptional<z.ZodString>;
275
+ type: z.ZodLiteral<"task.accepted">;
276
+ taskId: z.ZodString;
277
+ callId: z.ZodString;
278
+ }, z.core.$strip>, z.ZodObject<{
279
+ id: z.ZodString;
280
+ sessionId: z.ZodString;
281
+ sequence: z.ZodInt;
282
+ recordedAtMs: z.ZodNumber;
283
+ sessionTimeMs: z.ZodNumber;
284
+ correlationId: z.ZodOptional<z.ZodString>;
285
+ causationId: z.ZodOptional<z.ZodString>;
286
+ type: z.ZodLiteral<"task.progress">;
287
+ taskId: z.ZodString;
288
+ callId: z.ZodString;
289
+ update: z.ZodJSONSchema;
290
+ }, z.core.$strip>, z.ZodObject<{
291
+ id: z.ZodString;
292
+ sessionId: z.ZodString;
293
+ sequence: z.ZodInt;
294
+ recordedAtMs: z.ZodNumber;
295
+ sessionTimeMs: z.ZodNumber;
296
+ correlationId: z.ZodOptional<z.ZodString>;
297
+ causationId: z.ZodOptional<z.ZodString>;
298
+ type: z.ZodLiteral<"task.completed">;
299
+ taskId: z.ZodString;
300
+ callId: z.ZodString;
301
+ result: z.ZodJSONSchema;
302
+ }, z.core.$strip>, z.ZodObject<{
303
+ id: z.ZodString;
304
+ sessionId: z.ZodString;
305
+ sequence: z.ZodInt;
306
+ recordedAtMs: z.ZodNumber;
307
+ sessionTimeMs: z.ZodNumber;
308
+ correlationId: z.ZodOptional<z.ZodString>;
309
+ causationId: z.ZodOptional<z.ZodString>;
310
+ type: z.ZodLiteral<"task.failed">;
311
+ taskId: z.ZodString;
312
+ callId: z.ZodString;
313
+ error: z.ZodString;
314
+ }, z.core.$strip>, z.ZodObject<{
315
+ id: z.ZodString;
316
+ sessionId: z.ZodString;
317
+ sequence: z.ZodInt;
318
+ recordedAtMs: z.ZodNumber;
319
+ sessionTimeMs: z.ZodNumber;
320
+ correlationId: z.ZodOptional<z.ZodString>;
321
+ causationId: z.ZodOptional<z.ZodString>;
322
+ type: z.ZodLiteral<"task.cancelled">;
323
+ taskId: z.ZodString;
324
+ callId: z.ZodString;
325
+ reason: z.ZodString;
326
+ }, z.core.$strip>, z.ZodObject<{
327
+ id: z.ZodString;
328
+ sessionId: z.ZodString;
329
+ sequence: z.ZodInt;
330
+ recordedAtMs: z.ZodNumber;
331
+ sessionTimeMs: z.ZodNumber;
332
+ correlationId: z.ZodOptional<z.ZodString>;
333
+ causationId: z.ZodOptional<z.ZodString>;
334
+ type: z.ZodLiteral<"task.delivery_failed">;
335
+ taskId: z.ZodString;
336
+ callId: z.ZodString;
337
+ phase: z.ZodEnum<{
338
+ progress: "progress";
339
+ terminal: "terminal";
340
+ }>;
341
+ error: z.ZodString;
342
+ }, z.core.$strip>], "type">;
343
+ export type HarnessEvent = z.infer<typeof HarnessEventSchema>;
344
+ type DynamicEventField = "sequence";
345
+ export type UnsequencedHarnessEvent = HarnessEvent extends infer Event ? Event extends HarnessEvent ? Omit<Event, DynamicEventField> : never : never;
346
+ type GeneratedEventField = "id" | "sessionId" | "sequence" | "recordedAtMs" | "sessionTimeMs";
347
+ export type NewHarnessEvent = HarnessEvent extends infer Event ? Event extends HarnessEvent ? Omit<Event, GeneratedEventField> : never : never;
348
+ export declare function stringifyHarnessEvent(event: HarnessEvent): string;
349
+ export declare function parseHarnessEvent(serialized: string): HarnessEvent;
350
+ export {};
@@ -0,0 +1,167 @@
1
+ import { z } from "zod";
2
+ import { AudioChunkSchema } from "./audio.js";
3
+ import { InputPartSchema } from "./parts.js";
4
+ import { OutputModalitySchema, ProviderCapabilitiesSchema, TranscriptDeltaPayloadSchema, TranscriptPayloadSchema, UsagePayloadSchema, } from "./provider.js";
5
+ import { JsonValueSchema, ToolCallSchema, ToolOutcomeSchema } from "./tools.js";
6
+ /** Bounds for a typed user message, shared by the event, the session API, and wire schemas. */
7
+ export const MessageInputTextSchema = z.string().min(1).max(8_000);
8
+ const EventBaseSchema = z.object({
9
+ id: z.string().min(1),
10
+ sessionId: z.string().min(1),
11
+ sequence: z.int().positive(),
12
+ recordedAtMs: z.number().nonnegative(),
13
+ sessionTimeMs: z.number().nonnegative(),
14
+ correlationId: z.string().min(1).optional(),
15
+ causationId: z.string().min(1).optional(),
16
+ });
17
+ /**
18
+ * The authoritative session log: every observable fact of a conversation, in one flat,
19
+ * durably ordered stream. There is deliberately no turn or message hierarchy here —
20
+ * duplex audio overlaps — conversation views are projections over this log.
21
+ * The full catalog with ordering rules lives in docs/protocol.md.
22
+ */
23
+ export const HarnessEventSchema = z.discriminatedUnion("type", [
24
+ /** First event of every session, durably appended before any provider event flows. */
25
+ EventBaseSchema.extend({
26
+ type: z.literal("session.started"),
27
+ formatVersion: z.int().positive().optional(),
28
+ providerId: z.string().min(1),
29
+ capabilities: ProviderCapabilitiesSchema,
30
+ instructions: z.string().optional(),
31
+ outputModalities: z.array(OutputModalitySchema).min(1).optional(),
32
+ }),
33
+ /** Always the final event; appended after tools settle and pending media records land. */
34
+ EventBaseSchema.extend({ type: z.literal("session.ended"), reason: z.string().min(1) }),
35
+ /** The provider accepted the session configuration; media may now flow. */
36
+ EventBaseSchema.extend({ type: z.literal("provider.ready") }),
37
+ /** The provider connection settled; the harness closes the session in response. */
38
+ EventBaseSchema.extend({ type: z.literal("provider.closed"), reason: z.string().min(1) }),
39
+ /** Provider-reported fault; recoverable errors leave the session running. */
40
+ EventBaseSchema.extend({
41
+ type: z.literal("provider.error"),
42
+ message: z.string().min(1),
43
+ recoverable: z.boolean(),
44
+ }),
45
+ /**
46
+ * A typed user message injected into the conversation (text mode or mixed mode).
47
+ * `text` is the collapsed string realtime providers consume; `parts` preserves the
48
+ * full multimodal input (text/image/file) for projection when one was given.
49
+ */
50
+ EventBaseSchema.extend({
51
+ type: z.literal("message.input"),
52
+ text: MessageInputTextSchema,
53
+ parts: z.array(InputPartSchema).min(1).optional(),
54
+ }),
55
+ /** Microphone PCM as received; the append and the provider forward run in parallel. */
56
+ EventBaseSchema.extend({ type: z.literal("audio.input"), chunk: AudioChunkSchema }),
57
+ /** Model PCM as received; records are pipelined so bursts never stall the event pump. */
58
+ EventBaseSchema.extend({ type: z.literal("audio.output"), chunk: AudioChunkSchema }),
59
+ /** Final text for either speaker — speech-to-text, or the model's text output in text mode. */
60
+ EventBaseSchema.extend({ type: z.literal("transcript"), ...TranscriptPayloadSchema.shape }),
61
+ /** Incremental assistant text streamed before the final transcript; live-render only. */
62
+ EventBaseSchema.extend({ type: z.literal("transcript.delta"), ...TranscriptDeltaPayloadSchema.shape }),
63
+ /** Provider-reported token accounting for one completed response. */
64
+ EventBaseSchema.extend({ type: z.literal("usage"), ...UsagePayloadSchema.shape }),
65
+ /** Client acknowledgement of playback position; the authority for barge-in truncation. */
66
+ EventBaseSchema.extend({
67
+ type: z.literal("playout.progress"),
68
+ streamId: z.string().min(1),
69
+ playedThroughSample: z.int().nonnegative(),
70
+ }),
71
+ /** The model asked for a tool; recorded before execution begins. */
72
+ EventBaseSchema.extend({ type: z.literal("tool.requested"), call: ToolCallSchema }),
73
+ /** Local execution of a requested tool has begun. */
74
+ EventBaseSchema.extend({
75
+ type: z.literal("tool.started"),
76
+ callId: z.string().min(1),
77
+ name: z.string().min(1),
78
+ }),
79
+ /** Intermediate progress reported by a running tool. */
80
+ EventBaseSchema.extend({
81
+ type: z.literal("tool.progress"),
82
+ callId: z.string().min(1),
83
+ update: JsonValueSchema,
84
+ }),
85
+ /** The tool execution settled; provider delivery is tracked independently. */
86
+ EventBaseSchema.extend({
87
+ type: z.literal("tool.completed"),
88
+ callId: z.string().min(1),
89
+ outcome: ToolOutcomeSchema,
90
+ }),
91
+ /** Tool lookup, validation, or execution failed; provider delivery is tracked independently. */
92
+ EventBaseSchema.extend({
93
+ type: z.literal("tool.failed"),
94
+ callId: z.string().min(1),
95
+ error: z.string().min(1),
96
+ }),
97
+ /** A terminal tool result could not be delivered to the provider. */
98
+ EventBaseSchema.extend({
99
+ type: z.literal("tool.delivery_failed"),
100
+ callId: z.string().min(1),
101
+ error: z.string().min(1),
102
+ }),
103
+ /** A tool handed off to a long-running task that outlives the tool call. */
104
+ EventBaseSchema.extend({
105
+ type: z.literal("task.accepted"),
106
+ taskId: z.string().min(1),
107
+ callId: z.string().min(1),
108
+ }),
109
+ /** Intermediate progress from a background task. */
110
+ EventBaseSchema.extend({
111
+ type: z.literal("task.progress"),
112
+ taskId: z.string().min(1),
113
+ callId: z.string().min(1),
114
+ update: JsonValueSchema,
115
+ }),
116
+ /** The background task finished; providers may announce the settlement mid-conversation. */
117
+ EventBaseSchema.extend({
118
+ type: z.literal("task.completed"),
119
+ taskId: z.string().min(1),
120
+ callId: z.string().min(1),
121
+ result: JsonValueSchema,
122
+ }),
123
+ /** The background task failed after acceptance. */
124
+ EventBaseSchema.extend({
125
+ type: z.literal("task.failed"),
126
+ taskId: z.string().min(1),
127
+ callId: z.string().min(1),
128
+ error: z.string().min(1),
129
+ }),
130
+ /** The background task was cancelled, usually because the session is closing. */
131
+ EventBaseSchema.extend({
132
+ type: z.literal("task.cancelled"),
133
+ taskId: z.string().min(1),
134
+ callId: z.string().min(1),
135
+ reason: z.string().min(1),
136
+ }),
137
+ /** Recorded task context could not be delivered to the provider. */
138
+ EventBaseSchema.extend({
139
+ type: z.literal("task.delivery_failed"),
140
+ taskId: z.string().min(1),
141
+ callId: z.string().min(1),
142
+ phase: z.enum(["progress", "terminal"]),
143
+ error: z.string().min(1),
144
+ }),
145
+ ]);
146
+ const bytesMarker = "$xoBytes";
147
+ export function stringifyHarnessEvent(event) {
148
+ HarnessEventSchema.parse(event);
149
+ return JSON.stringify(event, (_key, value) => {
150
+ if (value instanceof Uint8Array) {
151
+ return { [bytesMarker]: Array.from(value) };
152
+ }
153
+ return value;
154
+ });
155
+ }
156
+ export function parseHarnessEvent(serialized) {
157
+ const value = JSON.parse(serialized, (_key, candidate) => {
158
+ if (typeof candidate === "object" && candidate !== null && bytesMarker in candidate) {
159
+ const encoded = candidate[bytesMarker];
160
+ if (Array.isArray(encoded) && encoded.every((value) => typeof value === "number")) {
161
+ return Uint8Array.from(encoded);
162
+ }
163
+ }
164
+ return candidate;
165
+ });
166
+ return HarnessEventSchema.parse(value);
167
+ }
@@ -0,0 +1,6 @@
1
+ export * from "./async-queue.js";
2
+ export * from "./audio.js";
3
+ export * from "./events.js";
4
+ export * from "./parts.js";
5
+ export * from "./provider.js";
6
+ export * from "./tools.js";
@@ -0,0 +1,6 @@
1
+ export * from "./async-queue.js";
2
+ export * from "./audio.js";
3
+ export * from "./events.js";
4
+ export * from "./parts.js";
5
+ export * from "./provider.js";
6
+ export * from "./tools.js";