pinecall 0.0.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.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +167 -0
  3. data/LICENSE +202 -0
  4. data/README.md +140 -0
  5. data/lib/pinecall/agent/author.rb +31 -0
  6. data/lib/pinecall/agent/config.rb +124 -0
  7. data/lib/pinecall/agent/doc.rb +73 -0
  8. data/lib/pinecall/agent/knowledge.rb +18 -0
  9. data/lib/pinecall/agent/searching.rb +33 -0
  10. data/lib/pinecall/agent/spec.rb +133 -0
  11. data/lib/pinecall/agent/state.rb +185 -0
  12. data/lib/pinecall/agent/tools.rb +119 -0
  13. data/lib/pinecall/agent.rb +160 -0
  14. data/lib/pinecall/blocks.rb +152 -0
  15. data/lib/pinecall/bridge.rb +239 -0
  16. data/lib/pinecall/call_world/answers.rb +61 -0
  17. data/lib/pinecall/call_world/room.rb +25 -0
  18. data/lib/pinecall/call_world.rb +175 -0
  19. data/lib/pinecall/client/agent.rb +179 -0
  20. data/lib/pinecall/client/call.rb +140 -0
  21. data/lib/pinecall/client/connection.rb +190 -0
  22. data/lib/pinecall/client/endpoints.rb +30 -0
  23. data/lib/pinecall/client/listeners.rb +42 -0
  24. data/lib/pinecall/client/observe.rb +109 -0
  25. data/lib/pinecall/client/rest.rb +61 -0
  26. data/lib/pinecall/client.rb +212 -0
  27. data/lib/pinecall/errors.rb +53 -0
  28. data/lib/pinecall/panel.rb +138 -0
  29. data/lib/pinecall/reading.rb +37 -0
  30. data/lib/pinecall/rules.rb +38 -0
  31. data/lib/pinecall/serve/held.rb +40 -0
  32. data/lib/pinecall/serve/loading.rb +102 -0
  33. data/lib/pinecall/serve/viewing.rb +40 -0
  34. data/lib/pinecall/serve.rb +169 -0
  35. data/lib/pinecall/testing.rb +190 -0
  36. data/lib/pinecall/version.rb +6 -0
  37. data/lib/pinecall/view.rb +70 -0
  38. data/lib/pinecall/wire/codec.rb +75 -0
  39. data/lib/pinecall/wire/enums.rb +104 -0
  40. data/lib/pinecall/wire/errors.rb +12 -0
  41. data/lib/pinecall/wire/reduce.rb +249 -0
  42. data/lib/pinecall/wire/registry.rb +168 -0
  43. data/lib/pinecall/wire/shapes.rb +33 -0
  44. data/lib/pinecall/wire/shapes_call_events.rb +137 -0
  45. data/lib/pinecall/wire/shapes_commands.rb +114 -0
  46. data/lib/pinecall/wire/shapes_config.rb +70 -0
  47. data/lib/pinecall/wire/shapes_doors.rb +96 -0
  48. data/lib/pinecall/wire/shapes_events.rb +358 -0
  49. data/lib/pinecall/wire/shapes_metrics.rb +109 -0
  50. data/lib/pinecall/wire/shapes_parts.rb +340 -0
  51. data/lib/pinecall/wire/state.rb +56 -0
  52. data/lib/pinecall/wire/validate.rb +154 -0
  53. data/lib/pinecall/wire.rb +43 -0
  54. data/lib/pinecall.rb +45 -0
  55. data/sig/pinecall.rbs +453 -0
  56. metadata +119 -0
@@ -0,0 +1,358 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The shape of each event's data during a call: talk, tools, the desk, memory, errors.
4
+
5
+ module Pinecall
6
+ module Wire
7
+ module Shapes
8
+ EVENTS = {
9
+ "ToolResult" => {
10
+ call_id: { kind: :str, required: true },
11
+ name: { kind: :str, required: true },
12
+ output: { kind: :any },
13
+ error: { kind: :str },
14
+ summary: { kind: :str },
15
+ duration_s: { kind: :float }
16
+ }.freeze,
17
+ "LLMMetrics" => {
18
+ type: { kind: :const, const: "llm_metrics", required: true },
19
+ label: { kind: :str, required: true },
20
+ request_id: { kind: :str, required: true },
21
+ timestamp: { kind: :float, required: true },
22
+ duration: { kind: :float, required: true },
23
+ ttft: { kind: :float, required: true },
24
+ cancelled: { kind: :bool, required: true },
25
+ completion_tokens: { kind: :int, required: true },
26
+ prompt_tokens: { kind: :int, required: true },
27
+ prompt_cached_tokens: { kind: :int, required: true },
28
+ cache_creation_tokens: { kind: :int },
29
+ reasoning_tokens: { kind: :int },
30
+ total_tokens: { kind: :int, required: true },
31
+ tokens_per_second: { kind: :float, required: true },
32
+ speech_id: { kind: :str, null: true },
33
+ metadata: { kind: :ref, null: true, ref: "Metadata" }
34
+ }.freeze,
35
+ "STTMetrics" => {
36
+ type: { kind: :const, const: "stt_metrics", required: true },
37
+ label: { kind: :str, required: true },
38
+ request_id: { kind: :str, required: true },
39
+ timestamp: { kind: :float, required: true },
40
+ duration: { kind: :float, required: true },
41
+ audio_duration: { kind: :float, required: true },
42
+ input_tokens: { kind: :int },
43
+ output_tokens: { kind: :int },
44
+ streamed: { kind: :bool, required: true },
45
+ acquire_time: { kind: :float },
46
+ connection_reused: { kind: :bool },
47
+ metadata: { kind: :ref, null: true, ref: "Metadata" }
48
+ }.freeze,
49
+ "TTSMetrics" => {
50
+ type: { kind: :const, const: "tts_metrics", required: true },
51
+ label: { kind: :str, required: true },
52
+ request_id: { kind: :str, required: true },
53
+ timestamp: { kind: :float, required: true },
54
+ ttfb: { kind: :float, required: true },
55
+ duration: { kind: :float, required: true },
56
+ audio_duration: { kind: :float, required: true },
57
+ cancelled: { kind: :bool, required: true },
58
+ characters_count: { kind: :int, required: true },
59
+ input_tokens: { kind: :int },
60
+ output_tokens: { kind: :int },
61
+ streamed: { kind: :bool, required: true },
62
+ acquire_time: { kind: :float },
63
+ connection_reused: { kind: :bool },
64
+ segment_id: { kind: :str, null: true },
65
+ speech_id: { kind: :str, null: true },
66
+ metadata: { kind: :ref, null: true, ref: "Metadata" }
67
+ }.freeze,
68
+ "VADMetrics" => {
69
+ type: { kind: :const, const: "vad_metrics", required: true },
70
+ label: { kind: :str, required: true },
71
+ timestamp: { kind: :float, required: true },
72
+ idle_time: { kind: :float, required: true },
73
+ inference_duration_total: { kind: :float, required: true },
74
+ inference_count: { kind: :int, required: true },
75
+ metadata: { kind: :ref, null: true, ref: "Metadata" }
76
+ }.freeze,
77
+ "EOUMetrics" => {
78
+ type: { kind: :const, const: "eou_metrics", required: true },
79
+ timestamp: { kind: :float, required: true },
80
+ end_of_utterance_delay: { kind: :float, required: true },
81
+ transcription_delay: { kind: :float, required: true },
82
+ on_user_turn_completed_delay: { kind: :float, required: true },
83
+ speech_id: { kind: :str, null: true },
84
+ metadata: { kind: :ref, null: true, ref: "Metadata" }
85
+ }.freeze,
86
+ "EOTInferenceMetrics" => {
87
+ type: { kind: :const, const: "eot_inference_metrics", required: true },
88
+ timestamp: { kind: :float, required: true },
89
+ total_duration: { kind: :float, required: true },
90
+ detection_delay: { kind: :float, required: true },
91
+ prediction_duration: { kind: :float, required: true },
92
+ num_requests: { kind: :int },
93
+ metadata: { kind: :ref, null: true, ref: "Metadata" }
94
+ }.freeze,
95
+ "InterruptionMetrics" => {
96
+ type: { kind: :const, const: "interruption_metrics", required: true },
97
+ timestamp: { kind: :float, required: true },
98
+ total_duration: { kind: :float, required: true },
99
+ prediction_duration: { kind: :float, required: true },
100
+ detection_delay: { kind: :float, required: true },
101
+ num_interruptions: { kind: :int, required: true },
102
+ num_backchannels: { kind: :int, required: true },
103
+ num_requests: { kind: :int, required: true },
104
+ metadata: { kind: :ref, null: true, ref: "Metadata" }
105
+ }.freeze,
106
+ "RealtimeModelMetrics" => {
107
+ type: { kind: :const, const: "realtime_model_metrics", required: true },
108
+ label: { kind: :str },
109
+ request_id: { kind: :str, required: true },
110
+ timestamp: { kind: :float, required: true },
111
+ duration: { kind: :float },
112
+ session_duration: { kind: :float },
113
+ ttft: { kind: :float },
114
+ cancelled: { kind: :bool },
115
+ input_tokens: { kind: :int },
116
+ output_tokens: { kind: :int },
117
+ total_tokens: { kind: :int },
118
+ tokens_per_second: { kind: :float },
119
+ input_token_details: { kind: :ref, ref: "RealtimeInputTokenDetails", required: true },
120
+ output_token_details: { kind: :ref, ref: "RealtimeOutputTokenDetails", required: true },
121
+ acquire_time: { kind: :float },
122
+ connection_reused: { kind: :bool },
123
+ metadata: { kind: :ref, null: true, ref: "Metadata" }
124
+ }.freeze,
125
+ "AvatarMetrics" => {
126
+ type: { kind: :const, const: "avatar_metrics", required: true },
127
+ timestamp: { kind: :float, required: true },
128
+ playback_latency: { kind: :float },
129
+ session_started_time: { kind: :float, null: true },
130
+ avatar_joined_time: { kind: :float, null: true },
131
+ metadata: { kind: :ref, null: true, ref: "Metadata" }
132
+ }.freeze,
133
+ "RoomOpened" => {
134
+ name: { kind: :str, required: true },
135
+ sid: { kind: :str, required: true },
136
+ channel: { kind: :ref, ref: "Channel", required: true }
137
+ }.freeze,
138
+ "ParticipantJoined" => {
139
+ identity: { kind: :str, required: true },
140
+ kind: { kind: :ref, ref: "ParticipantKind", required: true },
141
+ name: { kind: :str },
142
+ attributes: { kind: :json, required: true }
143
+ }.freeze,
144
+ "ParticipantLeft" => {
145
+ identity: { kind: :str, required: true },
146
+ reason: { kind: :str, required: true }
147
+ }.freeze,
148
+ "ParticipantSpeaking" => {
149
+ identity: { kind: :str, required: true },
150
+ speaking: { kind: :bool, required: true }
151
+ }.freeze,
152
+ "TrackPublished" => {
153
+ identity: { kind: :str, required: true },
154
+ kind: { kind: :ref, ref: "TrackKind", required: true },
155
+ source: { kind: :ref, ref: "TrackSource", required: true }
156
+ }.freeze,
157
+ "TrackUnpublished" => {
158
+ identity: { kind: :str, required: true },
159
+ kind: { kind: :ref, ref: "TrackKind", required: true },
160
+ source: { kind: :ref, ref: "TrackSource", required: true }
161
+ }.freeze,
162
+ "EventReceived" => {
163
+ name: { kind: :str, required: true },
164
+ data: { kind: :json, required: true },
165
+ source: { kind: :ref, ref: "EventSource", required: true },
166
+ identity: { kind: :str }
167
+ }.freeze,
168
+ "RoomSent" => {
169
+ topic: { kind: :str, required: true },
170
+ to: { kind: :str },
171
+ bytes: { kind: :int, required: true }
172
+ }.freeze,
173
+ "AttentionAnswered" => {
174
+ ok: { kind: :bool, required: true },
175
+ by: { kind: :ref, null: true, ref: "Supervisor", required: true },
176
+ error: { kind: :str }
177
+ }.freeze,
178
+ "AttentionRequested" => {
179
+ reason: { kind: :str, required: true },
180
+ wait_s: { kind: :float, required: true }
181
+ }.freeze,
182
+ "CodeClaimed" => {
183
+ code: { kind: :str, required: true },
184
+ call: { kind: :str, null: true, required: true }
185
+ }.freeze,
186
+ "CodeIssued" => {
187
+ code: { kind: :str, required: true },
188
+ env: { kind: :ref, ref: "Env", required: true },
189
+ expires_at: { kind: :float, required: true },
190
+ log: { kind: :ref, ref: "Projection", required: true }
191
+ }.freeze,
192
+ "ConfirmDeclined" => {
193
+ tool: { kind: :str, required: true },
194
+ call_id: { kind: :str, required: true },
195
+ audience: { kind: :str, required: true },
196
+ said: { kind: :str },
197
+ reason: { kind: :enum, values: %w[no timeout changed cancelled], required: true }
198
+ }.freeze,
199
+ "ConfirmGranted" => {
200
+ tool: { kind: :str, required: true },
201
+ call_id: { kind: :str, required: true },
202
+ audience: { kind: :str, required: true },
203
+ said: { kind: :str, required: true },
204
+ ttl_s: { kind: :int, required: true }
205
+ }.freeze,
206
+ "ConfirmRequest" => {
207
+ tool: { kind: :str, required: true },
208
+ call_id: { kind: :str, required: true },
209
+ arguments: { kind: :json, required: true },
210
+ audience: { kind: :str, required: true },
211
+ phrase: { kind: :str, required: true },
212
+ ttl_s: { kind: :int, required: true }
213
+ }.freeze,
214
+ "CreditsExhausted" => {
215
+ org: { kind: :str, required: true },
216
+ quota: { kind: :enum, values: %w[minutes messages agents concurrent_calls memory_facts knowledge_chunks numbers seats llm_tokens], required: true },
217
+ used: { kind: :float, required: true },
218
+ limit: { kind: :int, required: true }
219
+ }.freeze,
220
+ "Custom" => {
221
+ name: { kind: :str, required: true },
222
+ data: { kind: :json, required: true }
223
+ }.freeze,
224
+ "DevRequest" => {
225
+ id: { kind: :str, required: true },
226
+ verb: { kind: :ref, ref: "DevVerb", required: true },
227
+ data: { kind: :json, required: true }
228
+ }.freeze,
229
+ "DocsSources" => {
230
+ query: { kind: :str, required: true },
231
+ sources: { kind: :list, items: { kind: :ref, ref: "DocSource" }, required: true },
232
+ took_ms: { kind: :float, required: true },
233
+ speech_id: { kind: :str }
234
+ }.freeze,
235
+ "DtmfReceived" => {
236
+ digit: { kind: :enum, values: %w[0 1 2 3 4 5 6 7 8 9 * #], required: true },
237
+ code: { kind: :int, required: true }
238
+ }.freeze,
239
+ "ErrorEvent" => {
240
+ code: { kind: :str, required: true },
241
+ message: { kind: :str, required: true },
242
+ command: { kind: :str },
243
+ id: { kind: :str },
244
+ recoverable: { kind: :bool, required: true }
245
+ }.freeze,
246
+ "FleetFull" => {
247
+ channel: { kind: :ref, ref: "Channel", required: true },
248
+ workers: { kind: :int, required: true },
249
+ active: { kind: :int, required: true }
250
+ }.freeze,
251
+ "LogCaughtUp" => {
252
+ seq: { kind: :int, required: true }
253
+ }.freeze,
254
+ "LogGap" => {
255
+ from_seq: { kind: :int, required: true },
256
+ to_seq: { kind: :int, required: true },
257
+ snapshot: { kind: :ref, null: true, ref: "State", required: true }
258
+ }.freeze,
259
+ "MemoryOps" => {
260
+ ops: { kind: :list, items: { kind: :ref, ref: "MemoryOp" }, required: true },
261
+ speech_id: { kind: :str }
262
+ }.freeze,
263
+ "MessageTaken" => {
264
+ message_id: { kind: :str, required: true },
265
+ call: { kind: :str, null: true, required: true }
266
+ }.freeze,
267
+ "MessageWaiting" => {
268
+ channel: { kind: :ref, ref: "Channel", required: true },
269
+ env: { kind: :ref, ref: "Env", required: true },
270
+ number: { kind: :str, required: true },
271
+ phone_number_id: { kind: :str, required: true },
272
+ from: { kind: :str, required: true },
273
+ name: { kind: :str, null: true, required: true },
274
+ message_id: { kind: :str, required: true },
275
+ text: { kind: :str, required: true },
276
+ received_at: { kind: :float, required: true }
277
+ }.freeze,
278
+ "Pong" => {
279
+ ts: { kind: :float, required: true }
280
+ }.freeze,
281
+ "PromptChanged" => {
282
+ name: { kind: :str, required: true },
283
+ hash: { kind: :str, required: true },
284
+ chars: { kind: :int, required: true }
285
+ }.freeze,
286
+ "SpendUnusual" => {
287
+ org: { kind: :str, required: true },
288
+ day: { kind: :str, required: true },
289
+ today_usd: { kind: :float, required: true },
290
+ usual_usd: { kind: :float, required: true },
291
+ multiple: { kind: :float, required: true }
292
+ }.freeze,
293
+ "StateChanged" => {
294
+ state: { kind: :json, required: true },
295
+ changed: { kind: :list, items: { kind: :str }, required: true },
296
+ cause: { kind: :ref, ref: "StateCause" }
297
+ }.freeze,
298
+ "SupervisorEnded" => {
299
+ by: { kind: :ref, ref: "Supervisor", required: true },
300
+ reason: { kind: :str }
301
+ }.freeze,
302
+ "SupervisorReleased" => {
303
+ by: { kind: :ref, ref: "Supervisor", required: true }
304
+ }.freeze,
305
+ "SupervisorSaid" => {
306
+ by: { kind: :ref, ref: "Supervisor", required: true },
307
+ text: { kind: :str, required: true }
308
+ }.freeze,
309
+ "SupervisorTookOver" => {
310
+ by: { kind: :ref, ref: "Supervisor", required: true }
311
+ }.freeze,
312
+ "SupervisorTransferred" => {
313
+ by: { kind: :ref, ref: "Supervisor", required: true },
314
+ to: { kind: :str, required: true },
315
+ mode: { kind: :ref, null: true, ref: "TransferMode" }
316
+ }.freeze,
317
+ "SupervisorWhispered" => {
318
+ by: { kind: :ref, ref: "Supervisor", required: true },
319
+ text: { kind: :str, required: true }
320
+ }.freeze,
321
+ "ToolCall" => {
322
+ call_id: { kind: :str, required: true },
323
+ name: { kind: :str, required: true },
324
+ arguments: { kind: :json, required: true },
325
+ speech_id: { kind: :str }
326
+ }.freeze,
327
+ "ToolsChanged" => {
328
+ visible: { kind: :list, items: { kind: :str }, required: true }
329
+ }.freeze,
330
+ "UserTurnEnded" => {
331
+ speech_id: { kind: :str, required: true },
332
+ item_id: { kind: :str },
333
+ text: { kind: :str, required: true },
334
+ language: { kind: :str },
335
+ transcript_confidence: { kind: :float },
336
+ metrics: { kind: :ref, ref: "UserTurnMetrics", required: true }
337
+ }.freeze,
338
+ "UserStateChanged" => {
339
+ state: { kind: :ref, ref: "UserState", required: true }
340
+ }.freeze,
341
+ "UserTranscript" => {
342
+ text: { kind: :str, required: true },
343
+ final: { kind: :bool, required: true },
344
+ language: { kind: :str },
345
+ confidence: { kind: :float }
346
+ }.freeze,
347
+ "VendorSwitched" => {
348
+ stage: { kind: :enum, values: %w[llm stt tts], required: true },
349
+ vendor: { kind: :str, required: true },
350
+ model: { kind: :str, required: true },
351
+ available: { kind: :bool, required: true },
352
+ serving: { kind: :str, required: true },
353
+ serving_model: { kind: :str, required: true }
354
+ }.freeze
355
+ }.freeze
356
+ end
357
+ end
358
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ # What livekit measured for a turn and a model, and the usage a call is billed by.
4
+
5
+ module Pinecall
6
+ module Wire
7
+ module Shapes
8
+ METRICS = {
9
+ "RealtimeCachedTokenDetails" => {
10
+ audio_tokens: { kind: :int },
11
+ text_tokens: { kind: :int },
12
+ image_tokens: { kind: :int }
13
+ }.freeze,
14
+ "RealtimeInputTokenDetails" => {
15
+ audio_tokens: { kind: :int },
16
+ text_tokens: { kind: :int },
17
+ image_tokens: { kind: :int },
18
+ cached_tokens: { kind: :int },
19
+ cached_tokens_details: { kind: :ref, null: true, ref: "RealtimeCachedTokenDetails" }
20
+ }.freeze,
21
+ "RealtimeOutputTokenDetails" => {
22
+ text_tokens: { kind: :int },
23
+ audio_tokens: { kind: :int },
24
+ image_tokens: { kind: :int }
25
+ }.freeze,
26
+ "UserTurnMetrics" => {
27
+ started_speaking_at: { kind: :float },
28
+ stopped_speaking_at: { kind: :float },
29
+ transcription_delay: { kind: :float },
30
+ end_of_turn_delay: { kind: :float },
31
+ on_user_turn_completed_delay: { kind: :float },
32
+ stt_metadata: { kind: :ref, ref: "TurnMetadata" }
33
+ }.freeze,
34
+ "AgentTurnMetrics" => {
35
+ started_speaking_at: { kind: :float },
36
+ stopped_speaking_at: { kind: :float },
37
+ llm_node_ttft: { kind: :float },
38
+ llm_node_tps: { kind: :float },
39
+ llm_node_ttfs: { kind: :float },
40
+ tts_node_ttfb: { kind: :float },
41
+ playback_latency: { kind: :float },
42
+ e2e_latency: { kind: :float },
43
+ provider_request_ids: { kind: :list, items: { kind: :str } },
44
+ llm_metadata: { kind: :ref, ref: "TurnMetadata" },
45
+ tts_metadata: { kind: :ref, ref: "TurnMetadata" }
46
+ }.freeze,
47
+ "LLMModelUsage" => {
48
+ type: { kind: :const, const: "llm_usage", required: true },
49
+ provider: { kind: :str, required: true },
50
+ model: { kind: :str, required: true },
51
+ input_tokens: { kind: :int },
52
+ input_cached_tokens: { kind: :int },
53
+ input_cache_creation_tokens: { kind: :int },
54
+ input_audio_tokens: { kind: :int },
55
+ input_cached_audio_tokens: { kind: :int },
56
+ input_text_tokens: { kind: :int },
57
+ input_cached_text_tokens: { kind: :int },
58
+ input_image_tokens: { kind: :int },
59
+ input_cached_image_tokens: { kind: :int },
60
+ output_tokens: { kind: :int },
61
+ output_audio_tokens: { kind: :int },
62
+ output_text_tokens: { kind: :int },
63
+ output_reasoning_tokens: { kind: :int },
64
+ session_duration: { kind: :float }
65
+ }.freeze,
66
+ "TTSModelUsage" => {
67
+ type: { kind: :const, const: "tts_usage", required: true },
68
+ provider: { kind: :str, required: true },
69
+ model: { kind: :str, required: true },
70
+ input_tokens: { kind: :int },
71
+ output_tokens: { kind: :int },
72
+ characters_count: { kind: :int },
73
+ audio_duration: { kind: :float }
74
+ }.freeze,
75
+ "STTModelUsage" => {
76
+ type: { kind: :const, const: "stt_usage", required: true },
77
+ provider: { kind: :str, required: true },
78
+ model: { kind: :str, required: true },
79
+ input_tokens: { kind: :int },
80
+ output_tokens: { kind: :int },
81
+ audio_duration: { kind: :float }
82
+ }.freeze,
83
+ "InterruptionModelUsage" => {
84
+ type: { kind: :const, const: "interruption_usage", required: true },
85
+ provider: { kind: :str, required: true },
86
+ model: { kind: :str, required: true },
87
+ total_requests: { kind: :int }
88
+ }.freeze,
89
+ "EOTModelUsage" => {
90
+ type: { kind: :const, const: "eot_usage", required: true },
91
+ provider: { kind: :str, required: true },
92
+ model: { kind: :str, required: true },
93
+ total_requests: { kind: :int }
94
+ }.freeze,
95
+ "CollectedMetrics" => {
96
+ llm: { kind: :list, items: { kind: :ref, ref: "LLMMetrics" }, required: true },
97
+ stt: { kind: :list, items: { kind: :ref, ref: "STTMetrics" }, required: true },
98
+ tts: { kind: :list, items: { kind: :ref, ref: "TTSMetrics" }, required: true },
99
+ vad: { kind: :list, items: { kind: :ref, ref: "VADMetrics" }, required: true },
100
+ eou: { kind: :list, items: { kind: :ref, ref: "EOUMetrics" }, required: true },
101
+ eot: { kind: :list, items: { kind: :ref, ref: "EOTInferenceMetrics" }, required: true },
102
+ interruption: { kind: :list, items: { kind: :ref, ref: "InterruptionMetrics" }, required: true },
103
+ realtime: { kind: :list, items: { kind: :ref, ref: "RealtimeModelMetrics" }, required: true },
104
+ avatar: { kind: :list, items: { kind: :ref, ref: "AvatarMetrics" }, required: true }
105
+ }.freeze,
106
+ }.freeze
107
+ end
108
+ end
109
+ end