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,245 @@
1
+ """The bodies of the org's meters: the usage feed, a window's insights, its drift, the limits."""
2
+
3
+ from typing import Literal
4
+
5
+ from pinecall.domain.names import Env
6
+ from pinecall.wire.frames import WireModel
7
+
8
+
9
+ class UsageTotals(WireModel):
10
+ """What was consumed: calls, minutes, turns, tokens, characters, judge calls, the cost."""
11
+
12
+ calls: int
13
+ minutes: float
14
+ messages: int
15
+ input_tokens: int
16
+ output_tokens: int
17
+ characters: int
18
+ judge_calls: int
19
+ cost_usd: float
20
+
21
+
22
+ # Flat, as v1 wrote it: a billing layer that reads the feed today reads it unchanged at the cutover.
23
+ class UsageRow(WireModel):
24
+ """One metered entry: whose it was, which call, what it consumed, and where the feed is."""
25
+
26
+ cursor: int
27
+ org: str
28
+ agent: str
29
+ call: str
30
+ type: str
31
+ at: float
32
+ minutes: float
33
+ messages: int
34
+ input_tokens: int
35
+ output_tokens: int
36
+ characters: int
37
+ judge_calls: int
38
+ cost_usd: float
39
+
40
+
41
+ class UsagePage(WireModel):
42
+ """GET /v1/usage: the org's metered rows after the cursor, their totals, the next cursor."""
43
+
44
+ rows: list[UsageRow]
45
+ totals: UsageTotals | None
46
+ next: int | None
47
+
48
+
49
+ class BoxUsagePage(WireModel):
50
+ """GET /v1/ops/usage: every org's metered rows after the cursor, totals per org, the next."""
51
+
52
+ rows: list[UsageRow]
53
+ totals: dict[str, UsageTotals]
54
+ next: int | None
55
+
56
+
57
+ class InsightsConversations(WireModel):
58
+ """How many calls started in the window, and in the window of the same length before it."""
59
+
60
+ now: int
61
+ before: int
62
+
63
+
64
+ class InsightsChannels(WireModel):
65
+ """The window's calls by the door they came in by."""
66
+
67
+ phone: int
68
+ web: int
69
+ whatsapp: int
70
+
71
+
72
+ class InsightsSpend(WireModel):
73
+ """What one agent's window cost by stage, in US dollars, and per minute of its ended calls."""
74
+
75
+ llm_usd: float
76
+ stt_usd: float
77
+ tts_usd: float
78
+ phone_usd: float
79
+ platform_usd: float
80
+ minutes: float
81
+ per_minute_usd: float | None
82
+
83
+
84
+ class InsightsAgent(WireModel):
85
+ """One agent's window: its calls, the share of judgments it held, what it cost by stage."""
86
+
87
+ slug: str
88
+ calls: int
89
+ score: float | None
90
+ spend: InsightsSpend
91
+
92
+
93
+ class InsightsStage(WireModel):
94
+ """One stage of the window's turns on one vendor and model: how slow, how sure the ears were."""
95
+
96
+ stage: Literal["stt", "llm", "tts"]
97
+ vendor: str | None
98
+ model: str | None
99
+ turns: int
100
+ median_s: float | None
101
+ p95_s: float | None
102
+ confidence: float | None
103
+
104
+
105
+ class InsightsBudget(WireModel):
106
+ """What the org may spend in a month and what it has spent so far, both worlds together."""
107
+
108
+ limit_usd: int | None
109
+ spent_usd_month: float
110
+
111
+
112
+ class InsightsEnding(WireModel):
113
+ """One way the window's calls ended, and how many did."""
114
+
115
+ reason: str
116
+ count: int
117
+
118
+
119
+ class InsightsDay(WireModel):
120
+ """One UTC day of the window: its calls by door, what they cost, how their judges answered."""
121
+
122
+ day: str
123
+ phone: int
124
+ web: int
125
+ whatsapp: int
126
+ spend_usd: float
127
+ judged: int
128
+ passed: int
129
+
130
+
131
+ class Insights(WireModel):
132
+ """GET /v1/insights: whole UTC days of the key's world and scope, counted off the call index."""
133
+
134
+ day: str
135
+ days: int
136
+ timezone: str
137
+ conversations: InsightsConversations
138
+ resolved_rate: float | None
139
+ median_e2e_s: float | None
140
+ spend_usd: float
141
+ channels: InsightsChannels
142
+ judged: int
143
+ passed: int
144
+ escalated: int
145
+ mean_length_s: float | None
146
+ endings: list[InsightsEnding]
147
+ series: list[InsightsDay]
148
+ sessions_total: int
149
+ live: int
150
+ agents: list[InsightsAgent]
151
+ stages: list[InsightsStage]
152
+ budget: InsightsBudget
153
+
154
+
155
+ class DriftSide(WireModel):
156
+ """One side of a drift as asked: a day, a version; and the versions its calls ran."""
157
+
158
+ day: str | None
159
+ version: int | None
160
+ versions: list[int]
161
+
162
+
163
+ class JudgeTally(WireModel):
164
+ """One judge on one side: its verdicts that held, those settled, and the share that held."""
165
+
166
+ held: int
167
+ judged: int
168
+ pass_rate: float | None
169
+
170
+
171
+ class DriftJudge(WireModel):
172
+ """One judge on both sides, how far its pass rate moved, and whether its question changed."""
173
+
174
+ name: str
175
+ before: JudgeTally | None
176
+ after: JudgeTally | None
177
+ moved: float | None
178
+ criteria_changed: bool
179
+
180
+
181
+ class StageTally(WireModel):
182
+ """One stage on one side: its turns, median and p95 in seconds, the ears' confidence."""
183
+
184
+ turns: int
185
+ median_s: float | None
186
+ p95_s: float | None
187
+ confidence: float | None
188
+
189
+
190
+ class DriftStage(WireModel):
191
+ """One stage on one vendor and model on both sides, and how far its median and p95 moved."""
192
+
193
+ stage: Literal["stt", "llm", "tts"]
194
+ vendor: str | None
195
+ model: str | None
196
+ before: StageTally | None
197
+ after: StageTally | None
198
+ median_moved_s: float | None
199
+ p95_moved_s: float | None
200
+
201
+
202
+ class DriftVersion(WireModel):
203
+ """A version of the agent's settings a side ran or that was set between: who, when, why."""
204
+
205
+ version: int
206
+ holder: str
207
+ author: str
208
+ note: str | None
209
+ set_at: float
210
+ ran_before: bool
211
+ ran_after: bool
212
+
213
+
214
+ class Drift(WireModel):
215
+ """GET /v1/insights/drift: what moved between two days or versions of an agent, and why."""
216
+
217
+ agent: str
218
+ world: Env
219
+ before: DriftSide
220
+ after: DriftSide
221
+ judges: list[DriftJudge]
222
+ stages: list[DriftStage]
223
+ versions: list[DriftVersion]
224
+
225
+
226
+ class Limit(WireModel):
227
+ """One quota: the limit the org was given, and how much of it is used."""
228
+
229
+ limit: int | None
230
+ used: float
231
+
232
+
233
+ class Limits(WireModel):
234
+ """GET /v1/limits: what the key's org may use in the world and has used, and its lends."""
235
+
236
+ minutes: Limit
237
+ messages: Limit
238
+ llm_tokens: Limit
239
+ concurrent_calls: Limit
240
+ agents: Limit
241
+ seats: Limit
242
+ numbers: Limit
243
+ lends: list[str] | None
244
+ billing_url: str | None
245
+ world: Env
pinecall/wire/room.py ADDED
@@ -0,0 +1,61 @@
1
+ """The room's events: the room opened, who joined, left and spoke, what they published, sent."""
2
+
3
+ from pinecall.domain.names import Channel, JsonObject
4
+ from pinecall.wire.frames import WireModel
5
+ from pinecall.wire.parts import ParticipantKind, TrackKind, TrackSource
6
+
7
+
8
+ class RoomOpened(WireModel):
9
+ """The LiveKit room exists and the call lives in it; a text session never logs this."""
10
+
11
+ name: str
12
+ sid: str
13
+ channel: Channel
14
+
15
+
16
+ # The attributes travel verbatim: the caller's number is a fact of the room, not a field of ours.
17
+ class ParticipantJoined(WireModel):
18
+ """Somebody joined the room."""
19
+
20
+ identity: str
21
+ kind: ParticipantKind
22
+ name: str | None = None
23
+ attributes: JsonObject
24
+
25
+
26
+ class ParticipantLeft(WireModel):
27
+ """Somebody left the room; when it is the caller, call.ended follows."""
28
+
29
+ identity: str
30
+ reason: str
31
+
32
+
33
+ class ParticipantSpeaking(WireModel):
34
+ """The room's own voice activity for one participant flipped; a light for the console."""
35
+
36
+ identity: str
37
+ speaking: bool
38
+
39
+
40
+ class TrackPublished(WireModel):
41
+ """A participant put a track on the room: their microphone, their camera, a screen."""
42
+
43
+ identity: str
44
+ kind: TrackKind
45
+ source: TrackSource
46
+
47
+
48
+ class TrackUnpublished(WireModel):
49
+ """A participant's track left the room."""
50
+
51
+ identity: str
52
+ kind: TrackKind
53
+ source: TrackSource
54
+
55
+
56
+ class RoomSent(WireModel):
57
+ """The agent pushed a payload to a browser in the room; the payload stays out of the log."""
58
+
59
+ topic: str
60
+ to: str | None = None
61
+ bytes: int
@@ -0,0 +1,49 @@
1
+ """What the judges said about a call: call.score, one judgment per judge, and its evidence."""
2
+
3
+ from pydantic import AliasChoices, Field
4
+
5
+ from pinecall.wire.frames import WireModel
6
+ from pinecall.wire.parts import ScoreVerdict
7
+
8
+
9
+ class JudgmentEvidence(WireModel):
10
+ """Where in the call's own log a judgment is about."""
11
+
12
+ seqs: list[int]
13
+ said: str | None = None
14
+
15
+
16
+ class Judgment(WireModel):
17
+ """One judge's answer about one call."""
18
+
19
+ name: str
20
+ verdict: ScoreVerdict
21
+ criteria: str
22
+ reason: str
23
+ evidence: JudgmentEvidence
24
+
25
+
26
+ class JudgedBy(WireModel):
27
+ """Who gave a score: the judge model, and one hash of every question the panel asked."""
28
+
29
+ # None: the panel was settled by code alone, no model asked.
30
+ provider: str | None
31
+ model: str | None
32
+ criteria: str
33
+
34
+
35
+ class CallScore(WireModel):
36
+ """The last entry of a call: what the judges said about it at hang-up, one row per judge."""
37
+
38
+ passed: bool | None = None
39
+ not_judged: str | None = None
40
+ judges: list[Judgment]
41
+ panel: list[str] | None = None
42
+ judge_calls: int
43
+ # A score written before money in dollars said it in euros: the same number, read as dollars.
44
+ judge_cost_usd: float | None = Field(
45
+ default=None, validation_alias=AliasChoices("judge_cost_usd", "judge_cost_eur")
46
+ )
47
+ # Absent on a score written before 10.6, or with nothing judged: drift tells a worse agent from
48
+ # a changed judge by it.
49
+ judged_by: JudgedBy | None = None
pinecall/wire/state.py ADDED
@@ -0,0 +1,243 @@
1
+ """What a log reduces to: State and its parts."""
2
+
3
+ from typing import Annotated, Literal
4
+
5
+ from pydantic import Field
6
+
7
+ from pinecall.domain.agent import EventSource
8
+ from pinecall.domain.names import Channel, Direction, Json, JsonObject
9
+ from pinecall.wire.frames import WireModel
10
+ from pinecall.wire.metrics import (
11
+ AgentTurnMetrics,
12
+ AvatarMetrics,
13
+ EOTInferenceMetrics,
14
+ EOUMetrics,
15
+ InterruptionMetrics,
16
+ LLMMetrics,
17
+ ModelUsage,
18
+ RealtimeModelMetrics,
19
+ STTMetrics,
20
+ TTSMetrics,
21
+ UserTurnMetrics,
22
+ VADMetrics,
23
+ )
24
+ from pinecall.wire.parts import (
25
+ AgentState,
26
+ CallStatus,
27
+ Contact,
28
+ Cost,
29
+ DocSource,
30
+ EndReason,
31
+ MemoryOp,
32
+ ParticipantKind,
33
+ Route,
34
+ Supervisor,
35
+ TransferMode,
36
+ UserState,
37
+ )
38
+
39
+
40
+ class UserTurn(WireModel):
41
+ """One finished turn of the caller, with what the session measured about it."""
42
+
43
+ role: Literal["user"] = "user"
44
+ speech_id: str
45
+ item_id: str | None = None
46
+ text: str
47
+ language: str | None = None
48
+ transcript_confidence: float | None = None
49
+ metrics: UserTurnMetrics
50
+
51
+
52
+ class AgentTurn(WireModel):
53
+ """One finished reply of the agent, with what the session measured about it."""
54
+
55
+ role: Literal["agent"] = "agent"
56
+ speech_id: str
57
+ item_id: str | None = None
58
+ text: str
59
+ interrupted: bool
60
+ metrics: AgentTurnMetrics
61
+
62
+
63
+ type Turn = Annotated[UserTurn | AgentTurn, Field(discriminator="role")]
64
+
65
+
66
+ class CollectedMetrics(WireModel):
67
+ """Every raw metric block of the call, by kind, in the order it arrived."""
68
+
69
+ llm: list[LLMMetrics]
70
+ stt: list[STTMetrics]
71
+ tts: list[TTSMetrics]
72
+ vad: list[VADMetrics]
73
+ eou: list[EOUMetrics]
74
+ eot: list[EOTInferenceMetrics]
75
+ interruption: list[InterruptionMetrics]
76
+ realtime: list[RealtimeModelMetrics]
77
+ avatar: list[AvatarMetrics]
78
+
79
+
80
+ class ToolRun(WireModel):
81
+ """One tool call and, once the app answered, its result."""
82
+
83
+ call_id: str
84
+ name: str
85
+ arguments: JsonObject
86
+ speech_id: str | None = None
87
+ status: Literal["running", "done", "failed"]
88
+ output: Json = None
89
+ error: str | None = None
90
+ summary: str | None = None
91
+ duration_s: float | None = None
92
+ seq: int
93
+
94
+
95
+ class PromptBlockState(WireModel):
96
+ """What is known about one block of the prompt without storing its text."""
97
+
98
+ hash: str
99
+ chars: int
100
+ seq: int
101
+
102
+
103
+ type PromptState = dict[str, PromptBlockState]
104
+
105
+
106
+ class Confirm(WireModel):
107
+ """One confirmation the platform asked for, and how it went."""
108
+
109
+ tool: str
110
+ call_id: str
111
+ audience: str
112
+ phrase: str
113
+ status: Literal["pending", "granted", "declined"]
114
+ said: str | None = None
115
+ reason: str | None = None
116
+
117
+
118
+ class Handoff(WireModel):
119
+ """Whether a supervisor holds the line right now."""
120
+
121
+ active: bool
122
+ by: Supervisor | None
123
+
124
+
125
+ class TransferState(WireModel):
126
+ """The transfer in flight or the one that happened."""
127
+
128
+ to: str
129
+ mode: TransferMode | None = None
130
+ status: Literal["requested", "done", "failed"]
131
+ by: Literal["agent", "supervisor"]
132
+
133
+
134
+ class AttentionState(WireModel):
135
+ """The agent's last ask for a person, until attention.answered settles it."""
136
+
137
+ reason: str
138
+ wait_s: float
139
+ status: Literal["open", "answered", "lapsed"]
140
+ asked_at: float
141
+ by: Supervisor | None
142
+
143
+
144
+ class LiveTranscript(WireModel):
145
+ """The words on screen right now: interim transcripts that a finished turn clears."""
146
+
147
+ user: str | None
148
+ agent: str | None
149
+
150
+
151
+ class Gap(WireModel):
152
+ """A stretch of seqs this reader never saw."""
153
+
154
+ from_seq: int
155
+ to_seq: int
156
+
157
+
158
+ class LoggedError(WireModel):
159
+ """An error entry, kept so the console can show what went wrong and when."""
160
+
161
+ seq: int
162
+ code: str
163
+ message: str
164
+
165
+
166
+ class Participant(WireModel):
167
+ """One participant in the room right now, as the room reported them when they joined."""
168
+
169
+ identity: str
170
+ kind: ParticipantKind
171
+ name: str | None = None
172
+ joined_at: float
173
+ speaking: bool
174
+ attributes: JsonObject
175
+
176
+
177
+ class Room(WireModel):
178
+ """The LiveKit room the call lives in, and who is in it right now."""
179
+
180
+ name: str
181
+ sid: str
182
+ participants: list[Participant]
183
+ caller: str | None
184
+
185
+
186
+ class ReceivedEvent(WireModel):
187
+ """One fact that reached the agent from outside, kept by name and origin; its data is at seq."""
188
+
189
+ seq: int
190
+ name: str
191
+ source: EventSource
192
+ identity: str | None = None
193
+
194
+
195
+ class CustomNote(WireModel):
196
+ """A line the app wrote into the log with call.log."""
197
+
198
+ seq: int
199
+ name: str
200
+ data: JsonObject
201
+
202
+
203
+ class State(WireModel):
204
+ """The whole of what a log says, at the seq it was read to."""
205
+
206
+ seq: int
207
+ agent: str
208
+ call: str | None
209
+ status: CallStatus
210
+ channel: Channel | None
211
+ direction: Direction | None
212
+ from_: str | None = Field(alias="from")
213
+ to: str | None
214
+ caller: Contact | None
215
+ room: Room | None
216
+ started_at: float | None
217
+ ended_at: float | None
218
+ end_reason: EndReason | None
219
+ outcome: str | None
220
+ user_state: UserState | None
221
+ agent_state: AgentState | None
222
+ live: LiveTranscript
223
+ turns: list[Turn]
224
+ metrics: CollectedMetrics
225
+ tools: list[ToolRun]
226
+ app_state: JsonObject
227
+ events: list[ReceivedEvent]
228
+ prompt: PromptState
229
+ tools_visible: list[str]
230
+ confirms: list[Confirm]
231
+ memory: list[MemoryOp]
232
+ sources: list[DocSource]
233
+ handoff: Handoff
234
+ held: bool
235
+ muted: bool
236
+ transfer: TransferState | None
237
+ attention: AttentionState | None = None
238
+ usage: list[ModelUsage]
239
+ cost: Cost | None
240
+ routes: list[Route]
241
+ gaps: list[Gap]
242
+ errors: list[LoggedError]
243
+ custom: list[CustomNote]
File without changes