pinecall-runtime 0.1.6__py3-none-any.whl

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 (328) hide show
  1. pinecall/__init__.py +0 -0
  2. pinecall/channels/__init__.py +0 -0
  3. pinecall/channels/_chooser.py +45 -0
  4. pinecall/channels/offers.py +219 -0
  5. pinecall/channels/rooms.py +176 -0
  6. pinecall/channels/routes.py +275 -0
  7. pinecall/channels/telephony/__init__.py +0 -0
  8. pinecall/channels/telephony/_twilio.py +349 -0
  9. pinecall/channels/telephony/carrier.py +229 -0
  10. pinecall/channels/telephony/carrier_catalog.py +92 -0
  11. pinecall/channels/telephony/carriers.csv +41 -0
  12. pinecall/channels/telephony/dialing.py +419 -0
  13. pinecall/channels/telephony/firewall.py +58 -0
  14. pinecall/channels/telephony/hand_over.py +78 -0
  15. pinecall/channels/telephony/number_path.py +176 -0
  16. pinecall/channels/telephony/numbers.py +530 -0
  17. pinecall/channels/telephony/origination.py +77 -0
  18. pinecall/channels/telephony/sip.py +448 -0
  19. pinecall/channels/whatsapp.py +413 -0
  20. pinecall/cli/__init__.py +0 -0
  21. pinecall/cli/_archive.py +85 -0
  22. pinecall/cli/_drift.py +38 -0
  23. pinecall/cli/_facts.py +67 -0
  24. pinecall/cli/_load.py +433 -0
  25. pinecall/cli/_operator.py +626 -0
  26. pinecall/cli/_sessions.py +164 -0
  27. pinecall/cli/_traceback.py +95 -0
  28. pinecall/cli/_usage.py +34 -0
  29. pinecall/cli/main.py +521 -0
  30. pinecall/domain/__init__.py +0 -0
  31. pinecall/domain/agent.py +446 -0
  32. pinecall/domain/call.py +152 -0
  33. pinecall/domain/country_codes.py +32 -0
  34. pinecall/domain/errors.py +151 -0
  35. pinecall/domain/names.py +115 -0
  36. pinecall/domain/org.py +120 -0
  37. pinecall/domain/person.py +208 -0
  38. pinecall/domain/scope.py +21 -0
  39. pinecall/evals/__init__.py +0 -0
  40. pinecall/evals/_evidence.py +158 -0
  41. pinecall/evals/calibration.py +112 -0
  42. pinecall/evals/callers.py +160 -0
  43. pinecall/evals/case.py +327 -0
  44. pinecall/evals/checks.py +437 -0
  45. pinecall/evals/compliance.py +197 -0
  46. pinecall/evals/dataset.py +451 -0
  47. pinecall/evals/goldens.py +331 -0
  48. pinecall/evals/judges.py +525 -0
  49. pinecall/evals/runs.py +252 -0
  50. pinecall/evals/spoken.py +356 -0
  51. pinecall/fleet/__init__.py +0 -0
  52. pinecall/fleet/client.py +569 -0
  53. pinecall/fleet/demand.py +51 -0
  54. pinecall/fleet/heartbeat.py +194 -0
  55. pinecall/fleet/measures.py +157 -0
  56. pinecall/fleet/roster.py +232 -0
  57. pinecall/fleet/worlds.py +44 -0
  58. pinecall/gateway/__init__.py +0 -0
  59. pinecall/gateway/_call_setup.py +53 -0
  60. pinecall/gateway/_deps.py +556 -0
  61. pinecall/gateway/_gateway.py +75 -0
  62. pinecall/gateway/_served.py +396 -0
  63. pinecall/gateway/_sockets.py +444 -0
  64. pinecall/gateway/_streams.py +83 -0
  65. pinecall/gateway/_text_calls.py +182 -0
  66. pinecall/gateway/api/__init__.py +0 -0
  67. pinecall/gateway/api/accounts.py +324 -0
  68. pinecall/gateway/api/agents.py +150 -0
  69. pinecall/gateway/api/apps.py +478 -0
  70. pinecall/gateway/api/box.py +658 -0
  71. pinecall/gateway/api/calibration.py +58 -0
  72. pinecall/gateway/api/callbacks.py +105 -0
  73. pinecall/gateway/api/calls.py +655 -0
  74. pinecall/gateway/api/chat.py +223 -0
  75. pinecall/gateway/api/dataset.py +163 -0
  76. pinecall/gateway/api/desk.py +113 -0
  77. pinecall/gateway/api/entries.py +77 -0
  78. pinecall/gateway/api/evals.py +647 -0
  79. pinecall/gateway/api/fleet.py +73 -0
  80. pinecall/gateway/api/hosting.py +241 -0
  81. pinecall/gateway/api/judges.py +97 -0
  82. pinecall/gateway/api/keys.py +110 -0
  83. pinecall/gateway/api/line.py +142 -0
  84. pinecall/gateway/api/members.py +197 -0
  85. pinecall/gateway/api/metrics.py +226 -0
  86. pinecall/gateway/api/numbers.py +476 -0
  87. pinecall/gateway/api/ops.py +428 -0
  88. pinecall/gateway/api/org.py +283 -0
  89. pinecall/gateway/api/personas.py +157 -0
  90. pinecall/gateway/api/pipeline.py +206 -0
  91. pinecall/gateway/api/prompts.py +50 -0
  92. pinecall/gateway/api/providers.py +240 -0
  93. pinecall/gateway/api/recordings.py +89 -0
  94. pinecall/gateway/api/relay.py +169 -0
  95. pinecall/gateway/api/retrieval.py +403 -0
  96. pinecall/gateway/api/runner.py +109 -0
  97. pinecall/gateway/api/sessions.py +102 -0
  98. pinecall/gateway/api/settings.py +463 -0
  99. pinecall/gateway/api/signup.py +164 -0
  100. pinecall/gateway/api/sso_login.py +168 -0
  101. pinecall/gateway/api/threads.py +187 -0
  102. pinecall/gateway/api/usage.py +303 -0
  103. pinecall/gateway/api/visitors.py +222 -0
  104. pinecall/gateway/api/whatsapp.py +48 -0
  105. pinecall/gateway/api/widget.py +49 -0
  106. pinecall/gateway/app.py +504 -0
  107. pinecall/gateway/calls/__init__.py +0 -0
  108. pinecall/gateway/calls/binding.py +63 -0
  109. pinecall/gateway/calls/commands.py +18 -0
  110. pinecall/gateway/calls/inbox.py +100 -0
  111. pinecall/gateway/calls/known.py +23 -0
  112. pinecall/gateway/calls/owners.py +87 -0
  113. pinecall/gateway/calls/pump.py +33 -0
  114. pinecall/gateway/calls/serving.py +118 -0
  115. pinecall/gateway/calls/threads.py +367 -0
  116. pinecall/gateway/dispatching/__init__.py +0 -0
  117. pinecall/gateway/dispatching/arrivals.py +58 -0
  118. pinecall/gateway/dispatching/sweep.py +43 -0
  119. pinecall/gateway/ending/__init__.py +0 -0
  120. pinecall/gateway/ending/reaper.py +160 -0
  121. pinecall/gateway/ending/seal.py +312 -0
  122. pinecall/gateway/ending/stranded.py +117 -0
  123. pinecall/log/__init__.py +0 -0
  124. pinecall/log/_histogram.py +74 -0
  125. pinecall/log/_relay.py +259 -0
  126. pinecall/log/_writer.py +454 -0
  127. pinecall/log/days.py +154 -0
  128. pinecall/log/drift.py +550 -0
  129. pinecall/log/facts.py +358 -0
  130. pinecall/log/inbox.py +169 -0
  131. pinecall/log/lists.py +155 -0
  132. pinecall/log/logs.py +581 -0
  133. pinecall/log/openings.py +71 -0
  134. pinecall/log/private.py +135 -0
  135. pinecall/log/queries.py +229 -0
  136. pinecall/log/readers.py +207 -0
  137. pinecall/log/reduce.py +659 -0
  138. pinecall/log/refold.py +217 -0
  139. pinecall/log/store.py +370 -0
  140. pinecall/log/usage.py +242 -0
  141. pinecall/postgres/__init__.py +0 -0
  142. pinecall/postgres/migrate.py +202 -0
  143. pinecall/postgres/migrations/0001_schema.sql +591 -0
  144. pinecall/postgres/migrations/0002_worlds.sql +15 -0
  145. pinecall/postgres/migrations/0003_lent.sql +4 -0
  146. pinecall/postgres/migrations/0004_carriers.sql +23 -0
  147. pinecall/postgres/migrations/0005_retrieved_only.sql +11 -0
  148. pinecall/postgres/migrations/0006_persona_agents.sql +9 -0
  149. pinecall/postgres/migrations/0007_money_in_dollars.sql +27 -0
  150. pinecall/postgres/migrations/0008_lexicon_per_agent.sql +27 -0
  151. pinecall/postgres/migrations/0009_personas_per_agent.sql +31 -0
  152. pinecall/postgres/migrations/0010_agent_judges.sql +12 -0
  153. pinecall/postgres/migrations/0011_erasure.sql +32 -0
  154. pinecall/postgres/migrations/0012_org_policy.sql +10 -0
  155. pinecall/postgres/migrations/0013_calling_rules.sql +12 -0
  156. pinecall/postgres/migrations/0014_consents.sql +24 -0
  157. pinecall/postgres/migrations/0015_disclosure.sql +7 -0
  158. pinecall/postgres/migrations/0016_call_records.sql +21 -0
  159. pinecall/postgres/migrations/0017_reads.sql +17 -0
  160. pinecall/postgres/migrations/0018_hosting.sql +41 -0
  161. pinecall/postgres/migrations/0019_hosted_state.sql +10 -0
  162. pinecall/postgres/migrations/0020_written_once.sql +7 -0
  163. pinecall/postgres/migrations/0021_hosted_running.sql +21 -0
  164. pinecall/postgres/migrations/0022_sealed.sql +39 -0
  165. pinecall/postgres/migrations/0023_usage_totals.sql +158 -0
  166. pinecall/postgres/migrations/0024_log_key_by_day.sql +8 -0
  167. pinecall/postgres/migrations/0025_log_before_the_days.sql +15 -0
  168. pinecall/postgres/migrations/0026_log_before_the_days_validated.sql +4 -0
  169. pinecall/postgres/migrations/0027_log_by_day.sql +96 -0
  170. pinecall/postgres/migrations/0030_whatsapp_seen.sql +17 -0
  171. pinecall/postgres/migrations/0040_reads_widened.sql +15 -0
  172. pinecall/postgres/migrations/0060_drift.sql +62 -0
  173. pinecall/postgres/migrations/0061_canaries.sql +24 -0
  174. pinecall/postgres/migrations/0062_eval_cases.sql +23 -0
  175. pinecall/postgres/migrations/0063_prompts.sql +16 -0
  176. pinecall/postgres/migrations/0075_call_private.sql +14 -0
  177. pinecall/postgres/migrations/0076_recording_keys.sql +13 -0
  178. pinecall/postgres/migrations/0077_tokens_world.sql +7 -0
  179. pinecall/postgres/migrations/0078_facts_cost_by_stage.sql +12 -0
  180. pinecall/postgres/migrations/0079_judge_labels.sql +20 -0
  181. pinecall/postgres/migrations/0080_call_openings.sql +20 -0
  182. pinecall/postgres/migrations/0081_seal_lease.sql +7 -0
  183. pinecall/postgres/migrations/0082_caller_codes.sql +14 -0
  184. pinecall/postgres/migrations/0083_one_use_words.sql +15 -0
  185. pinecall/postgres/migrations/0084_knocks_and_run_leases.sql +23 -0
  186. pinecall/postgres/migrations/0085_seal_lease_holder.sql +8 -0
  187. pinecall/postgres/migrations/0086_route_origin.sql +17 -0
  188. pinecall/postgres/migrations/0087_carrier_networks.sql +20 -0
  189. pinecall/postgres/migrations/0088_route_last_call.sql +3 -0
  190. pinecall/postgres/migrations/0089_offers.sql +21 -0
  191. pinecall/postgres/migrations/0090_invitation_purpose.sql +5 -0
  192. pinecall/postgres/migrations/0091_head_opened_by.sql +6 -0
  193. pinecall/postgres/migrations/0092_key_parent.sql +6 -0
  194. pinecall/postgres/migrations/0093_code_tries.sql +10 -0
  195. pinecall/postgres/migrations/0094_route_approval.sql +12 -0
  196. pinecall/postgres/migrations/0095_sso_domain_proofs.sql +17 -0
  197. pinecall/postgres/migrations/0096_row_level_security.sql +38 -0
  198. pinecall/postgres/migrations/0097_case_status.sql +19 -0
  199. pinecall/postgres/pool.py +190 -0
  200. pinecall/process/__init__.py +0 -0
  201. pinecall/process/_objects.py +97 -0
  202. pinecall/process/box_settings.py +23 -0
  203. pinecall/process/connections.py +124 -0
  204. pinecall/process/metrics.py +127 -0
  205. pinecall/process/recordings.py +323 -0
  206. pinecall/process/resolver.py +41 -0
  207. pinecall/process/sealed_audio.py +173 -0
  208. pinecall/process/settings.py +534 -0
  209. pinecall/process/shared.py +158 -0
  210. pinecall/process/signal.py +416 -0
  211. pinecall/providers/__init__.py +0 -0
  212. pinecall/providers/build.py +570 -0
  213. pinecall/providers/catalog.py +266 -0
  214. pinecall/providers/credentials.py +230 -0
  215. pinecall/providers/declared.py +69 -0
  216. pinecall/providers/prices.py +240 -0
  217. pinecall/providers/tried.py +104 -0
  218. pinecall/providers/voices.py +174 -0
  219. pinecall/public/console/assets/index-BIfKPSgn.js +164 -0
  220. pinecall/public/console/assets/index-ClOTU-xX.css +1 -0
  221. pinecall/public/console/favicon.png +0 -0
  222. pinecall/public/console/index.html +20 -0
  223. pinecall/public/console/logo-mark.png +0 -0
  224. pinecall/public/console/pinecall-logo-dark.png +0 -0
  225. pinecall/public/console/pinecall-logo.png +0 -0
  226. pinecall/public/console/pinecall-mark.png +0 -0
  227. pinecall/public/console/sw.js +37 -0
  228. pinecall/public/widget/pinecall-widget.js +853 -0
  229. pinecall/py.typed +0 -0
  230. pinecall/retrieval/__init__.py +0 -0
  231. pinecall/retrieval/_search.py +186 -0
  232. pinecall/retrieval/_sections.py +70 -0
  233. pinecall/retrieval/embed.py +340 -0
  234. pinecall/retrieval/extraction.py +403 -0
  235. pinecall/retrieval/knowledge.py +659 -0
  236. pinecall/retrieval/lookups.py +192 -0
  237. pinecall/retrieval/memory.py +603 -0
  238. pinecall/runner/__init__.py +0 -0
  239. pinecall/runner/_kube.py +459 -0
  240. pinecall/runner/_plan.py +157 -0
  241. pinecall/runner/main.py +306 -0
  242. pinecall/session/__init__.py +0 -0
  243. pinecall/session/_agent.py +141 -0
  244. pinecall/session/_hearing.py +101 -0
  245. pinecall/session/_livekit.py +195 -0
  246. pinecall/session/_prompt.py +147 -0
  247. pinecall/session/_recording.py +237 -0
  248. pinecall/session/call.py +367 -0
  249. pinecall/session/clock.py +40 -0
  250. pinecall/session/hold.py +239 -0
  251. pinecall/session/room.py +626 -0
  252. pinecall/session/session.py +690 -0
  253. pinecall/session/text.py +144 -0
  254. pinecall/session/tools.py +483 -0
  255. pinecall/session/voice.py +118 -0
  256. pinecall/session/widget.py +201 -0
  257. pinecall/tenancy/__init__.py +0 -0
  258. pinecall/tenancy/admission.py +204 -0
  259. pinecall/tenancy/agents.py +164 -0
  260. pinecall/tenancy/canary.py +126 -0
  261. pinecall/tenancy/carrier_networks.py +156 -0
  262. pinecall/tenancy/carriers.py +265 -0
  263. pinecall/tenancy/codes.py +196 -0
  264. pinecall/tenancy/consents.py +167 -0
  265. pinecall/tenancy/dial_policy.py +405 -0
  266. pinecall/tenancy/disclosure.py +41 -0
  267. pinecall/tenancy/erasure.py +204 -0
  268. pinecall/tenancy/export.py +167 -0
  269. pinecall/tenancy/hosted_running.py +166 -0
  270. pinecall/tenancy/hosting.py +475 -0
  271. pinecall/tenancy/judges.py +126 -0
  272. pinecall/tenancy/keys.py +467 -0
  273. pinecall/tenancy/knocks.py +40 -0
  274. pinecall/tenancy/letters.py +378 -0
  275. pinecall/tenancy/mail.py +458 -0
  276. pinecall/tenancy/org_secrets.py +123 -0
  277. pinecall/tenancy/orgs.py +78 -0
  278. pinecall/tenancy/people.py +543 -0
  279. pinecall/tenancy/personas.py +145 -0
  280. pinecall/tenancy/policy.py +65 -0
  281. pinecall/tenancy/prompts.py +48 -0
  282. pinecall/tenancy/reads.py +73 -0
  283. pinecall/tenancy/recording_keys.py +41 -0
  284. pinecall/tenancy/remembered.py +148 -0
  285. pinecall/tenancy/retention.py +86 -0
  286. pinecall/tenancy/scopes.py +406 -0
  287. pinecall/tenancy/signin.py +622 -0
  288. pinecall/tenancy/spend.py +69 -0
  289. pinecall/tenancy/sso.py +431 -0
  290. pinecall/tenancy/sso_domains.py +132 -0
  291. pinecall/tenancy/throttle.py +88 -0
  292. pinecall/tenancy/tokens.py +400 -0
  293. pinecall/tenancy/traceback.py +70 -0
  294. pinecall/tenancy/usage.py +136 -0
  295. pinecall/tenancy/vault.py +204 -0
  296. pinecall/tenancy/words.py +144 -0
  297. pinecall/wire/__init__.py +0 -0
  298. pinecall/wire/commands.py +350 -0
  299. pinecall/wire/events.py +655 -0
  300. pinecall/wire/frames.py +65 -0
  301. pinecall/wire/metrics.py +287 -0
  302. pinecall/wire/parts.py +320 -0
  303. pinecall/wire/rest/__init__.py +0 -0
  304. pinecall/wire/rest/accounts.py +512 -0
  305. pinecall/wire/rest/agents.py +172 -0
  306. pinecall/wire/rest/calls.py +397 -0
  307. pinecall/wire/rest/evals.py +453 -0
  308. pinecall/wire/rest/fleet.py +69 -0
  309. pinecall/wire/rest/hosting.py +174 -0
  310. pinecall/wire/rest/numbers.py +280 -0
  311. pinecall/wire/rest/ops.py +342 -0
  312. pinecall/wire/rest/providers.py +83 -0
  313. pinecall/wire/rest/retrieval.py +301 -0
  314. pinecall/wire/rest/settings.py +184 -0
  315. pinecall/wire/rest/usage.py +245 -0
  316. pinecall/wire/room.py +61 -0
  317. pinecall/wire/scores.py +49 -0
  318. pinecall/wire/state.py +243 -0
  319. pinecall/worker/__init__.py +0 -0
  320. pinecall/worker/_job.py +655 -0
  321. pinecall/worker/_recorder.py +82 -0
  322. pinecall/worker/_traces.py +48 -0
  323. pinecall/worker/main.py +307 -0
  324. pinecall_runtime-0.1.6.dist-info/METADATA +212 -0
  325. pinecall_runtime-0.1.6.dist-info/RECORD +328 -0
  326. pinecall_runtime-0.1.6.dist-info/WHEEL +4 -0
  327. pinecall_runtime-0.1.6.dist-info/entry_points.txt +2 -0
  328. pinecall_runtime-0.1.6.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,287 @@
1
+ """Every livekit-agents 1.8 metric and usage row, verbatim."""
2
+
3
+ from typing import Annotated, Literal
4
+
5
+ from pydantic import Field
6
+
7
+ from pinecall.wire.frames import WireModel
8
+
9
+
10
+ class Metadata(WireModel):
11
+ """Which model and provider produced a block."""
12
+
13
+ model_name: str | None = None
14
+ model_provider: str | None = None
15
+
16
+
17
+ class LLMMetrics(WireModel):
18
+ """One LLM request, measured by the session's llm node."""
19
+
20
+ type: Literal["llm_metrics"] = "llm_metrics"
21
+ label: str
22
+ request_id: str
23
+ timestamp: float
24
+ duration: float
25
+ ttft: float
26
+ cancelled: bool
27
+ completion_tokens: int
28
+ prompt_tokens: int
29
+ prompt_cached_tokens: int
30
+ cache_creation_tokens: int | None = None
31
+ reasoning_tokens: int | None = None
32
+ total_tokens: int
33
+ tokens_per_second: float
34
+ speech_id: str | None = None
35
+ metadata: Metadata | None = None
36
+
37
+
38
+ class STTMetrics(WireModel):
39
+ """One speech-to-text request, measured by the session's stt node."""
40
+
41
+ type: Literal["stt_metrics"] = "stt_metrics"
42
+ label: str
43
+ request_id: str
44
+ timestamp: float
45
+ duration: float
46
+ audio_duration: float
47
+ input_tokens: int | None = None
48
+ output_tokens: int | None = None
49
+ streamed: bool
50
+ acquire_time: float | None = None
51
+ connection_reused: bool | None = None
52
+ metadata: Metadata | None = None
53
+
54
+
55
+ class TTSMetrics(WireModel):
56
+ """One text-to-speech request, measured by the session's tts node."""
57
+
58
+ type: Literal["tts_metrics"] = "tts_metrics"
59
+ label: str
60
+ request_id: str
61
+ timestamp: float
62
+ ttfb: float
63
+ duration: float
64
+ audio_duration: float
65
+ cancelled: bool
66
+ characters_count: int
67
+ input_tokens: int | None = None
68
+ output_tokens: int | None = None
69
+ streamed: bool
70
+ acquire_time: float | None = None
71
+ connection_reused: bool | None = None
72
+ segment_id: str | None = None
73
+ speech_id: str | None = None
74
+ metadata: Metadata | None = None
75
+
76
+
77
+ class VADMetrics(WireModel):
78
+ """The voice activity detector's health, reported about once a second while it runs."""
79
+
80
+ type: Literal["vad_metrics"] = "vad_metrics"
81
+ label: str
82
+ timestamp: float
83
+ idle_time: float
84
+ inference_duration_total: float
85
+ inference_count: int
86
+ metadata: Metadata | None = None
87
+
88
+
89
+ class EOUMetrics(WireModel):
90
+ """How long the session took to decide that the caller had finished."""
91
+
92
+ type: Literal["eou_metrics"] = "eou_metrics"
93
+ timestamp: float
94
+ end_of_utterance_delay: float
95
+ transcription_delay: float
96
+ on_user_turn_completed_delay: float
97
+ speech_id: str | None = None
98
+ metadata: Metadata | None = None
99
+
100
+
101
+ class EOTInferenceMetrics(WireModel):
102
+ """One prediction by the end-of-turn model."""
103
+
104
+ type: Literal["eot_inference_metrics"] = "eot_inference_metrics"
105
+ timestamp: float
106
+ total_duration: float
107
+ detection_delay: float
108
+ prediction_duration: float
109
+ num_requests: int | None = None
110
+ metadata: Metadata | None = None
111
+
112
+
113
+ class InterruptionMetrics(WireModel):
114
+ """The interruption detector's latest inference and its running counts."""
115
+
116
+ type: Literal["interruption_metrics"] = "interruption_metrics"
117
+ timestamp: float
118
+ total_duration: float
119
+ prediction_duration: float
120
+ detection_delay: float
121
+ num_interruptions: int
122
+ num_backchannels: int
123
+ num_requests: int
124
+ metadata: Metadata | None = None
125
+
126
+
127
+ class RealtimeCachedTokenDetails(WireModel):
128
+ """Of a realtime model's cached input, how much was audio, text or image."""
129
+
130
+ audio_tokens: int | None = None
131
+ text_tokens: int | None = None
132
+ image_tokens: int | None = None
133
+
134
+
135
+ class RealtimeInputTokenDetails(WireModel):
136
+ """What a realtime model read, by kind, with the cached part broken out."""
137
+
138
+ audio_tokens: int | None = None
139
+ text_tokens: int | None = None
140
+ image_tokens: int | None = None
141
+ cached_tokens: int | None = None
142
+ cached_tokens_details: RealtimeCachedTokenDetails | None = None
143
+
144
+
145
+ class RealtimeOutputTokenDetails(WireModel):
146
+ """What a realtime model produced, by kind."""
147
+
148
+ text_tokens: int | None = None
149
+ audio_tokens: int | None = None
150
+ image_tokens: int | None = None
151
+
152
+
153
+ class RealtimeModelMetrics(WireModel):
154
+ """One response from a speech-to-speech model, which replaces STT, LLM and TTS at once."""
155
+
156
+ type: Literal["realtime_model_metrics"] = "realtime_model_metrics"
157
+ label: str | None = None
158
+ request_id: str
159
+ timestamp: float
160
+ duration: float | None = None
161
+ session_duration: float | None = None
162
+ ttft: float | None = None
163
+ cancelled: bool | None = None
164
+ input_tokens: int | None = None
165
+ output_tokens: int | None = None
166
+ total_tokens: int | None = None
167
+ tokens_per_second: float | None = None
168
+ input_token_details: RealtimeInputTokenDetails
169
+ output_token_details: RealtimeOutputTokenDetails
170
+ acquire_time: float | None = None
171
+ connection_reused: bool | None = None
172
+ metadata: Metadata | None = None
173
+
174
+
175
+ class AvatarMetrics(WireModel):
176
+ """Timing of a video avatar worker, when one is in the chain."""
177
+
178
+ type: Literal["avatar_metrics"] = "avatar_metrics"
179
+ timestamp: float
180
+ playback_latency: float | None = None
181
+ session_started_time: float | None = None
182
+ avatar_joined_time: float | None = None
183
+ metadata: Metadata | None = None
184
+
185
+
186
+ class TurnMetadata(WireModel):
187
+ """Which model handled one leg of a turn."""
188
+
189
+ model_name: str | None = None
190
+ model_provider: str | None = None
191
+
192
+
193
+ # Every field is optional: a text session has no speech to time.
194
+ class UserTurnMetrics(WireModel):
195
+ """What the session measured about the caller's turn."""
196
+
197
+ started_speaking_at: float | None = None
198
+ stopped_speaking_at: float | None = None
199
+ transcription_delay: float | None = None
200
+ end_of_turn_delay: float | None = None
201
+ on_user_turn_completed_delay: float | None = None
202
+ stt_metadata: TurnMetadata | None = None
203
+
204
+
205
+ class AgentTurnMetrics(WireModel):
206
+ """What the session measured about the agent's reply."""
207
+
208
+ started_speaking_at: float | None = None
209
+ stopped_speaking_at: float | None = None
210
+ llm_node_ttft: float | None = None
211
+ llm_node_tps: float | None = None
212
+ llm_node_ttfs: float | None = None
213
+ tts_node_ttfb: float | None = None
214
+ playback_latency: float | None = None
215
+ e2e_latency: float | None = None
216
+ provider_request_ids: list[str] | None = None
217
+ llm_metadata: TurnMetadata | None = None
218
+ tts_metadata: TurnMetadata | None = None
219
+
220
+
221
+ class LLMModelUsage(WireModel):
222
+ """Everything one LLM consumed over the call."""
223
+
224
+ type: Literal["llm_usage"] = "llm_usage"
225
+ provider: str
226
+ model: str
227
+ input_tokens: int | None = None
228
+ input_cached_tokens: int | None = None
229
+ input_cache_creation_tokens: int | None = None
230
+ input_audio_tokens: int | None = None
231
+ input_cached_audio_tokens: int | None = None
232
+ input_text_tokens: int | None = None
233
+ input_cached_text_tokens: int | None = None
234
+ input_image_tokens: int | None = None
235
+ input_cached_image_tokens: int | None = None
236
+ output_tokens: int | None = None
237
+ output_audio_tokens: int | None = None
238
+ output_text_tokens: int | None = None
239
+ output_reasoning_tokens: int | None = None
240
+ session_duration: float | None = None
241
+
242
+
243
+ class TTSModelUsage(WireModel):
244
+ """Everything one TTS consumed over the call."""
245
+
246
+ type: Literal["tts_usage"] = "tts_usage"
247
+ provider: str
248
+ model: str
249
+ input_tokens: int | None = None
250
+ output_tokens: int | None = None
251
+ characters_count: int | None = None
252
+ audio_duration: float | None = None
253
+
254
+
255
+ class STTModelUsage(WireModel):
256
+ """Everything one STT consumed over the call."""
257
+
258
+ type: Literal["stt_usage"] = "stt_usage"
259
+ provider: str
260
+ model: str
261
+ input_tokens: int | None = None
262
+ output_tokens: int | None = None
263
+ audio_duration: float | None = None
264
+
265
+
266
+ class InterruptionModelUsage(WireModel):
267
+ """How often the interruption detector was asked over the call."""
268
+
269
+ type: Literal["interruption_usage"] = "interruption_usage"
270
+ provider: str
271
+ model: str
272
+ total_requests: int | None = None
273
+
274
+
275
+ class EOTModelUsage(WireModel):
276
+ """How often the end-of-turn model was asked over the call."""
277
+
278
+ type: Literal["eot_usage"] = "eot_usage"
279
+ provider: str
280
+ model: str
281
+ total_requests: int | None = None
282
+
283
+
284
+ type ModelUsage = Annotated[
285
+ LLMModelUsage | TTSModelUsage | STTModelUsage | InterruptionModelUsage | EOTModelUsage,
286
+ Field(discriminator="type"),
287
+ ]
pinecall/wire/parts.py ADDED
@@ -0,0 +1,320 @@
1
+ """The parts events, commands and state share: the wire's words and its common shapes."""
2
+
3
+ from typing import Literal
4
+
5
+ from pydantic import AliasChoices, Field
6
+
7
+ from pinecall.domain.agent import EventSource
8
+ from pinecall.domain.names import Channel, Json, JsonObject
9
+ from pinecall.wire.frames import WireModel
10
+
11
+ # What a console may ask of the process standing in the agent's directory, relayed by the gateway.
12
+ type DevVerb = Literal[
13
+ "chat.roster",
14
+ "chat.start",
15
+ "chat.say",
16
+ "chat.end",
17
+ "view.render",
18
+ "simulate.start",
19
+ "goldens.roster",
20
+ "goldens.run",
21
+ "knowledge.roster",
22
+ "knowledge.push",
23
+ "knowledge.eval",
24
+ "memory.roster",
25
+ "memory.eval",
26
+ "memory.extraction",
27
+ "promote.roster",
28
+ "promote.write",
29
+ "drift.read",
30
+ "reproductions.roster",
31
+ "reproductions.read",
32
+ ]
33
+
34
+ # drained: the worker went down with the call on it; app_detached: the app closed mid-call.
35
+ type EndReason = Literal[
36
+ "caller_hung_up",
37
+ "agent_hung_up",
38
+ "supervisor_ended",
39
+ "transferred",
40
+ "no_answer",
41
+ "busy",
42
+ "dial_failed",
43
+ "timeout",
44
+ "drained",
45
+ "app_detached",
46
+ "error",
47
+ ]
48
+
49
+ # platform covers timeouts, errors and a drained worker.
50
+ type EndedBy = Literal["caller", "agent", "supervisor", "platform"]
51
+
52
+ # skipped: no model was reachable inside the call's judging budget.
53
+ type ScoreVerdict = Literal["held", "broken", "deferred", "skipped"]
54
+
55
+ # cold: a REFER on the caller's SIP leg. warm: the number is dialled into the room.
56
+ type TransferMode = Literal["cold", "warm"]
57
+
58
+ type PromptRegion = Literal["static", "dynamic"]
59
+ type DocsMode = Literal["retrieved", "tool"]
60
+ type PlatformTool = Literal["recall", "search"]
61
+ type UserState = Literal["listening", "speaking", "away"]
62
+ type AgentState = Literal["initializing", "idle", "listening", "thinking", "speaking"]
63
+ type ParticipantKind = Literal["caller", "agent", "supervisor", "listener", "sip"]
64
+ type TrackKind = Literal["audio", "video", "screen"]
65
+ type TrackSource = Literal["microphone", "camera", "screen_share", "screen_share_audio", "unknown"]
66
+ type Visibility = Literal["public", "tenant", "pii"]
67
+
68
+ # Which projection a sink applies before a state or an entry leaves the platform.
69
+ type Projection = Literal["public", "tenant"]
70
+
71
+ type CallStatus = Literal["idle", "ringing", "dialing", "active", "ended"]
72
+ type SessionFlag = Literal["escalated", "low_score", "promise"]
73
+ type ThreadKind = Literal["in", "out", "call"]
74
+ type WidgetTheme = Literal["auto", "light", "dark"]
75
+
76
+
77
+ # The provider of the box's own rows (its compute): what the platform cost, beside the vendors'.
78
+ PLATFORM = "pinecall"
79
+
80
+
81
+ class PromptBlockSpec(WireModel):
82
+ """One named block of the prompt and the region it lives in."""
83
+
84
+ name: str = Field(pattern="^[a-z][a-z0-9_]*$")
85
+ region: PromptRegion
86
+
87
+
88
+ class Contact(WireModel):
89
+ """Who is on the line, as far as the platform knows; a web visitor may be nobody yet."""
90
+
91
+ id: str | None = None
92
+ phone: str | None = None
93
+ name: str | None = None
94
+ email: str | None = None
95
+ external_id: str | None = None
96
+
97
+
98
+ class Route(WireModel):
99
+ """One door to an agent: a channel and, for phone and WhatsApp, the number that answers."""
100
+
101
+ channel: Channel
102
+ number: str | None
103
+ label: str | None = None
104
+
105
+
106
+ class Supervisor(WireModel):
107
+ """The human who sent a supervise verb, as the token that let them in names them."""
108
+
109
+ id: str
110
+ name: str | None = None
111
+
112
+
113
+ class ToolSpec(WireModel):
114
+ """What the app declares about one tool."""
115
+
116
+ name: str
117
+ description: str
118
+ parameters: JsonObject
119
+ side_effect: Literal["read", "write", "irreversible"] = "read"
120
+ confirm: str | None = None
121
+ pii: list[str] | None = None
122
+ timeout_s: float | None = None
123
+
124
+
125
+ class ToolResult(WireModel):
126
+ """What came back from running a tool in the app's process: an output or an error."""
127
+
128
+ call_id: str
129
+ name: str
130
+ output: Json = None
131
+ error: str | None = None
132
+ summary: str | None = None
133
+ duration_s: float | None = None
134
+
135
+
136
+ class MemoryFact(WireModel):
137
+ """One thing remembered about a contact."""
138
+
139
+ id: str | None = None
140
+ text: str
141
+ category: str | None = None
142
+ score: float | None = None
143
+ source: str | None = None
144
+
145
+
146
+ class MemoryOp(WireModel):
147
+ """One operation against the contact's memory."""
148
+
149
+ op: Literal["recall", "remember", "forget"]
150
+ contact: str | None = None
151
+ query: str | None = None
152
+ facts: list[MemoryFact]
153
+ took_ms: float
154
+
155
+
156
+ class DocSource(WireModel):
157
+ """One chunk of the knowledge base that retrieval put in front of the model for this turn."""
158
+
159
+ id: str
160
+ base: str | None = None
161
+ path: str
162
+ heading: str | None = None
163
+ score: float
164
+ excerpt: str | None = None
165
+
166
+
167
+ class CostRow(WireModel):
168
+ """One priced line: a model, what was counted, how much, and what it came to."""
169
+
170
+ provider: str
171
+ model: str
172
+ unit: Literal[
173
+ "input_tokens",
174
+ "cached_input_tokens",
175
+ "cache_creation_tokens",
176
+ "output_tokens",
177
+ "characters",
178
+ "audio_seconds",
179
+ "requests",
180
+ "session_seconds",
181
+ "minutes",
182
+ ]
183
+ quantity: float
184
+ unit_price_usd: float
185
+ # A summary written before money in dollars priced its rows in euros: the same number, read as
186
+ # dollars and never converted, as migration 0007 kept the facts' column.
187
+ usd: float = Field(validation_alias=AliasChoices("usd", "eur"))
188
+
189
+
190
+ class UnpricedRow(WireModel):
191
+ """A usage row the price table does not know: listed, never priced at zero."""
192
+
193
+ provider: str
194
+ model: str
195
+
196
+
197
+ class Cost(WireModel):
198
+ """What the call cost in provider fees and, priced, the box's own compute; US dollars."""
199
+
200
+ usd: float = Field(validation_alias=AliasChoices("usd", "eur"))
201
+ rows: list[CostRow]
202
+ unpriced: list[UnpricedRow]
203
+ # The euro's rate a summary written before money in dollars carried; read, never written.
204
+ rate: JsonObject | None = Field(default=None, exclude=True)
205
+
206
+
207
+ class VoiceConfig(WireModel):
208
+ """Which voice speaks for the agent."""
209
+
210
+ name: str | None = None
211
+ provider: str | None = None
212
+ model: str | None = None
213
+ voice_id: str | None = None
214
+
215
+
216
+ class ModelConfig(WireModel):
217
+ """Which model does a job (the LLM, or the STT), and the one or two knobs worth turning."""
218
+
219
+ provider: str
220
+ model: str
221
+ temperature: float | None = None
222
+
223
+
224
+ class TurnConfig(WireModel):
225
+ """How the session decides that the caller has finished, and when the caller may interrupt."""
226
+
227
+ min_interruption_words: int | None = None
228
+ endpointing_ms: int | None = None
229
+ eot_threshold: float | None = None
230
+ eager_eot_threshold: float | None = None
231
+ min_interruption_ms: int | None = None
232
+
233
+
234
+ class Pronunciation(WireModel):
235
+ """How the voice says one word it would otherwise get wrong."""
236
+
237
+ word: str
238
+ spoken: str
239
+
240
+
241
+ class StateFieldSpec(WireModel):
242
+ """What the app declares about one field of its state: who may see it."""
243
+
244
+ name: str
245
+ visibility: Visibility
246
+
247
+
248
+ class ViewSpec(WireModel):
249
+ """The panel the agent draws beside a conversation; its contents come by dev verb."""
250
+
251
+ name: str
252
+
253
+
254
+ class EventSpec(WireModel):
255
+ """One outside event the agent accepts, and from whom."""
256
+
257
+ name: str
258
+ from_: list[EventSource] = Field(alias="from")
259
+
260
+
261
+ class KnowledgeFile(WireModel):
262
+ """One file of a base, as a push sends it: its path as the tenant keeps it, and its text."""
263
+
264
+ path: str
265
+ text: str
266
+
267
+
268
+ class DocsConfig(WireModel):
269
+ """The knowledge base the agent answers from, and how its chunks reach the model."""
270
+
271
+ base: str
272
+ mode: DocsMode = "retrieved"
273
+ k: int = 8
274
+ min_score: float | None = None
275
+
276
+
277
+ class GreetingConfig(WireModel):
278
+ """How the agent opens a call: `say` the words, or `reply` what the model reads first."""
279
+
280
+ say: str | None = None
281
+ reply: str | None = None
282
+ allow_interruptions: bool | None = None
283
+
284
+
285
+ class HangupConfig(WireModel):
286
+ """Whether the model may end the call itself, and when."""
287
+
288
+ when: str = ""
289
+
290
+
291
+ class MemoryConfig(WireModel):
292
+ """What memory keeps about a contact across calls, and what it must never keep."""
293
+
294
+ remember: list[str] = Field(default_factory=list[str])
295
+ forget: list[str] = Field(default_factory=list[str])
296
+
297
+
298
+ # Every field is optional so a configure can change one thing.
299
+ class AgentConfig(WireModel):
300
+ """What an app declares about its agent."""
301
+
302
+ prompt: list[PromptBlockSpec] | None = None
303
+ language: str | None = None
304
+ greeting: GreetingConfig | None = None
305
+ voice: VoiceConfig | None = None
306
+ llm: ModelConfig | None = None
307
+ stt: ModelConfig | None = None
308
+ turn: TurnConfig | None = None
309
+ says: list[Pronunciation] | None = None
310
+ hears: list[str] | None = None
311
+ knowledge: KnowledgeFile | None = None
312
+ docs: DocsConfig | None = None
313
+ memory: MemoryConfig | None = None
314
+ hangup: HangupConfig | None = None
315
+ record: bool = True
316
+ tools: list[ToolSpec] | None = None
317
+ uses_knowledge: bool = False
318
+ state_fields: list[StateFieldSpec] | None = None
319
+ view: ViewSpec | None = None
320
+ events: list[EventSpec] | None = None
File without changes