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,301 @@
1
+ """The bodies of the knowledge and memory doors."""
2
+
3
+ from pydantic import Field
4
+
5
+ from pinecall.domain.names import Channel
6
+ from pinecall.wire.frames import WireModel
7
+ from pinecall.wire.parts import (
8
+ KnowledgeFile,
9
+ )
10
+
11
+ # ── knowledge bases ──
12
+
13
+
14
+ # The base is replaced whole, never merged.
15
+ class KnowledgePush(WireModel):
16
+ """PUT /v1/knowledge/{base}, the body: the tenant's folder as of now."""
17
+
18
+ files: list[KnowledgeFile]
19
+
20
+
21
+ class KnowledgePushed(WireModel):
22
+ """PUT /v1/knowledge/{base}, the answer: the base, the chunks it became, how long it took."""
23
+
24
+ base: str
25
+ chunks: int
26
+ took_ms: float
27
+
28
+
29
+ class KnowledgeBase(WireModel):
30
+ """One base as the list draws it: its size, the model that wrote it, when it was pushed."""
31
+
32
+ base: str
33
+ chunks: int
34
+ model: str
35
+ pushed_at: float
36
+
37
+
38
+ class KnowledgeList(WireModel):
39
+ """GET /v1/knowledge: every base the key's scope reads."""
40
+
41
+ bases: list[KnowledgeBase]
42
+
43
+
44
+ class KnowledgeUse(WireModel):
45
+ """One base and the agents whose settings attach it."""
46
+
47
+ base: str
48
+ agents: list[str]
49
+
50
+
51
+ class KnowledgeUses(WireModel):
52
+ """GET /v1/knowledge/attached: which agents read each base, off their newest settings."""
53
+
54
+ bases: list[KnowledgeUse]
55
+
56
+
57
+ class KnowledgeFileRow(WireModel):
58
+ """One file of a base as the list draws it."""
59
+
60
+ path: str
61
+ chars: int
62
+ chunks: int
63
+ pushed_at: float
64
+
65
+
66
+ # `kept` is false for a base whose files were never stored, only its chunks.
67
+ class KnowledgeFiles(WireModel):
68
+ """GET /v1/knowledge/{base}: every file of the base, never its text."""
69
+
70
+ base: str
71
+ kept: bool
72
+ files: list[KnowledgeFileRow]
73
+
74
+
75
+ class KnowledgeFileRead(WireModel):
76
+ """GET /v1/knowledge/{base}/files/{path}: one file, text and all."""
77
+
78
+ path: str
79
+ text: str
80
+ chunks: int
81
+ pushed_at: float
82
+
83
+
84
+ class KnowledgeFilePut(WireModel):
85
+ """PUT /v1/knowledge/{base}/files/{path}, the body: the file's whole text."""
86
+
87
+ text: str
88
+
89
+
90
+ class KnowledgeFilePushed(WireModel):
91
+ """PUT /v1/knowledge/{base}/files/{path}, the answer: the file, its chunks, how long it took."""
92
+
93
+ base: str
94
+ path: str
95
+ chunks: int
96
+ took_ms: float
97
+
98
+
99
+ # A chunk answers when its file and heading path start with `expects`, never by substring.
100
+ class GoldenQuestion(WireModel):
101
+ """One question of a base's golden: what somebody asks, and the chunk that should answer."""
102
+
103
+ asks: str
104
+ expects: str
105
+
106
+
107
+ class KnowledgeGolden(WireModel):
108
+ """POST /v1/knowledge/{base}/eval, the body: the questions a base is held to."""
109
+
110
+ questions: list[GoldenQuestion]
111
+ k: int | None = None
112
+
113
+
114
+ class GoldenMiss(WireModel):
115
+ """One question whose chunk was not among the k returned, and what came back instead."""
116
+
117
+ asks: str
118
+ expects: str
119
+ found: list[str]
120
+
121
+
122
+ class KnowledgeScore(WireModel):
123
+ """POST /v1/knowledge/{base}/eval, the answer: recall@k and nDCG@10, computed with no model."""
124
+
125
+ base: str
126
+ model: str
127
+ questions: int
128
+ k: int
129
+ recall_at_k: float
130
+ ndcg_at_10: float
131
+ took_ms: float
132
+ misses: list[GoldenMiss]
133
+
134
+
135
+ # ── memory ──
136
+
137
+
138
+ # A fact is never updated, only superseded, so the history keeps every version.
139
+ class ContactFact(WireModel):
140
+ """One fact of a contact's history, with the two dates that bound it."""
141
+
142
+ id: str | None = None
143
+ text: str
144
+ category: str | None = None
145
+ source: str | None = None
146
+ valid_from: float
147
+ invalidated_at: float | None
148
+
149
+
150
+ class ContactMemory(WireModel):
151
+ """GET /v1/contacts/{contact}/memory: every fact ever kept of the contact, current first."""
152
+
153
+ facts: list[ContactFact]
154
+
155
+
156
+ class Forgotten(WireModel):
157
+ """DELETE /v1/contacts/{contact}/memory and /v1/memory/facts/{id}: how many facts went."""
158
+
159
+ forgotten: int
160
+
161
+
162
+ class AgentFact(WireModel):
163
+ """One current fact, among the contacts an agent's calls taught."""
164
+
165
+ id: str
166
+ contact: str
167
+ text: str
168
+ category: str | None
169
+ written_at: float
170
+
171
+
172
+ class AgentMemory(WireModel):
173
+ """GET /v1/agents/{slug}/memory: the facts the agent's calls taught, newest first, a page."""
174
+
175
+ facts: list[AgentFact]
176
+ next: str | None
177
+
178
+
179
+ class OrgFact(WireModel):
180
+ """One current fact of the org, with the agent whose call taught it."""
181
+
182
+ id: str
183
+ agent: str
184
+ contact: str
185
+ text: str
186
+ category: str | None
187
+ written_at: float
188
+
189
+
190
+ class OrgMemory(WireModel):
191
+ """GET /v1/memory: the org's current facts from every agent, newest first, a page."""
192
+
193
+ facts: list[OrgFact]
194
+ next: str | None = None
195
+
196
+
197
+ # A question brings its own facts: written to a scratch contact, asked, and forgotten.
198
+ class MemoryQuestion(WireModel):
199
+ """One question of a memory golden: what memory holds, what is asked, what should come back."""
200
+
201
+ holds: list[str]
202
+ asks: str
203
+ expects: list[str]
204
+
205
+
206
+ class MemoryGolden(WireModel):
207
+ """POST /v1/contacts/memory/eval, the body: the questions memory is held to."""
208
+
209
+ questions: list[MemoryQuestion]
210
+ k: int | None = None
211
+
212
+
213
+ class MemoryMiss(WireModel):
214
+ """One question memory did not answer whole: what it missed, and what came back instead."""
215
+
216
+ asks: str
217
+ missing: list[str]
218
+ found: list[str]
219
+
220
+
221
+ class MemoryScore(WireModel):
222
+ """POST /v1/contacts/memory/eval, the answer: recall@k and nDCG@10, computed with no model."""
223
+
224
+ model: str
225
+ questions: int
226
+ k: int
227
+ recall_at_k: float
228
+ ndcg_at_10: float
229
+ took_ms: float
230
+ misses: list[MemoryMiss]
231
+
232
+
233
+ # A category is the agent's own word, a value is a literal the caller said, a supersession an id:
234
+ # nothing is judged by comparing two sentences.
235
+ class ExtractionExpected(WireModel):
236
+ """What must come of one call's hang-up."""
237
+
238
+ writes: list[str] = Field(default_factory=list[str])
239
+ never: list[str] = Field(default_factory=list[str])
240
+ never_says: list[str] = Field(default_factory=list[str])
241
+ invalidates: list[str] = Field(default_factory=list[str])
242
+
243
+
244
+ class ExtractionGolden(WireModel):
245
+ """One call written down, what memory holds before it, and what memory must make of it."""
246
+
247
+ name: str
248
+ said: list[tuple[str, str]]
249
+ holds: list[str] = Field(default_factory=list[str])
250
+ plants: list[str] = Field(default_factory=list[str])
251
+ channel: Channel = "phone"
252
+ expect: ExtractionExpected = Field(default_factory=ExtractionExpected)
253
+
254
+
255
+ class ExtractionCases(WireModel):
256
+ """POST /v1/agents/{slug}/memory/extraction, the body: one model call per case."""
257
+
258
+ # Fifty model calls in one request at most, on keys the box may lend.
259
+ cases: list[ExtractionGolden] = Field(max_length=50)
260
+
261
+
262
+ class ExtractionBroke(WireModel):
263
+ """One check a case did not hold, and the evidence in a sentence."""
264
+
265
+ check: str
266
+ detail: str
267
+
268
+
269
+ class ExtractionJudged(WireModel):
270
+ """One case run: what memory would have kept, what admission refused, what did not hold."""
271
+
272
+ name: str
273
+ held: bool
274
+ wrote: list[str] = Field(default_factory=list[str])
275
+ refused: list[str] = Field(default_factory=list[str])
276
+ broke: list[ExtractionBroke] = Field(default_factory=list[ExtractionBroke])
277
+
278
+
279
+ class ExtractionRun(WireModel):
280
+ """POST /v1/agents/{slug}/memory/extraction, the answer: the model, how many held, each case."""
281
+
282
+ agent: str
283
+ model: str
284
+ cases: int
285
+ held: int
286
+ took_ms: float
287
+ results: list[ExtractionJudged]
288
+
289
+
290
+ class FoundChunk(WireModel):
291
+ """One chunk a search found: the file it came from, the heading it sits under, its body."""
292
+
293
+ path: str
294
+ heading: str | None
295
+ text: str
296
+
297
+
298
+ class SearchFound(WireModel):
299
+ """What search answers a call and an app's `this.knowledge.search`: the best chunks first."""
300
+
301
+ chunks: list[FoundChunk]
@@ -0,0 +1,184 @@
1
+ """The bodies of the settings doors: an agent's tuning and lexicon, versioned, and its canary."""
2
+
3
+ from pydantic import Field
4
+
5
+ from pinecall.domain.names import Env
6
+ from pinecall.wire.frames import WireModel
7
+ from pinecall.wire.parts import (
8
+ DocsConfig,
9
+ GreetingConfig,
10
+ HangupConfig,
11
+ MemoryConfig,
12
+ Pronunciation,
13
+ TurnConfig,
14
+ )
15
+
16
+
17
+ # Every field is optional: one left out is not set, and the runtime's own default stands for it.
18
+ class SettingsBody(WireModel):
19
+ """An agent's settings as the org set them, per world and per scope."""
20
+
21
+ voice: str | None = None
22
+ tts: str | None = None
23
+ tts_model: str | None = None
24
+ stt: str | None = None
25
+ llm: str | None = None
26
+ language: str | None = None
27
+ greeting: GreetingConfig | None = None
28
+ hangup: HangupConfig | None = None
29
+ turn: TurnConfig | None = None
30
+ memory: MemoryConfig | None = None
31
+ record: bool | None = None
32
+ max_duration_s: int | None = None
33
+ llm_timeout_s: float | None = None
34
+ knowledge: str | None = None
35
+ bases: list[DocsConfig] | None = None
36
+
37
+
38
+ class SettingsRow(WireModel):
39
+ """One kept version of an agent's settings: whose scope, which version, by whom, what."""
40
+
41
+ holder: str
42
+ version: int
43
+ author: str
44
+ note: str | None
45
+ set_at: float
46
+ config: SettingsBody
47
+
48
+
49
+ class SettingsResponse(WireModel):
50
+ """GET /v1/agents/{slug}/settings: yours, the team's and production's newest, or null."""
51
+
52
+ world: Env
53
+ yours: SettingsRow | None
54
+ team: SettingsRow | None
55
+ production: SettingsRow | None
56
+
57
+
58
+ class PutSettingsRequest(WireModel):
59
+ """PUT /v1/agents/{slug}/settings: the whole set, the version read, why, whose scope."""
60
+
61
+ config: SettingsBody
62
+ if_version: int | None = None
63
+ note: str | None = None
64
+ team: bool = False
65
+
66
+
67
+ class HistoryQuery(WireModel):
68
+ """The query string of a history: whose scope, and how many versions at most."""
69
+
70
+ team: bool = False
71
+ limit: int = Field(default=20, ge=1, le=200)
72
+
73
+
74
+ class SettingsHistoryResponse(WireModel):
75
+ """GET /v1/agents/{slug}/settings/history: one scope's versions, newest first."""
76
+
77
+ world: Env
78
+ holder: str
79
+ rows: list[SettingsRow]
80
+
81
+
82
+ class SettingsDiffResponse(WireModel):
83
+ """GET /v1/agents/{slug}/settings/diff: this scope's newest against another's, by field."""
84
+
85
+ ours: SettingsRow | None
86
+ theirs: SettingsRow | None
87
+ changed: list[str]
88
+
89
+
90
+ class RollbackSettingsRequest(WireModel):
91
+ """POST /v1/agents/{slug}/settings/rollback: the version to bring back, as a new one."""
92
+
93
+ version: int
94
+ team: bool = False
95
+
96
+
97
+ # A share is whole percents: 0 keeps the version off every call without clearing the canary.
98
+ class PutCanaryRequest(WireModel):
99
+ """PUT /v1/agents/{slug}/settings/canary: the version, its share of the calls, why, whose."""
100
+
101
+ version: int = Field(ge=1)
102
+ share: int = Field(ge=0, le=100)
103
+ note: str | None = None
104
+ team: bool = False
105
+
106
+
107
+ class CanaryQuery(WireModel):
108
+ """The query string of a canary's read or clearing: whose scope."""
109
+
110
+ team: bool = False
111
+
112
+
113
+ class CanaryRow(WireModel):
114
+ """The canary a scope stands on: which version takes how many calls in a hundred, by whom."""
115
+
116
+ holder: str
117
+ version: int
118
+ share: int
119
+ author: str
120
+ note: str | None
121
+ set_at: float
122
+
123
+
124
+ class CanaryResponse(WireModel):
125
+ """GET, PUT and DELETE /v1/agents/{slug}/settings/canary: the scope's canary, or null."""
126
+
127
+ world: Env
128
+ holder: str
129
+ canary: CanaryRow | None
130
+
131
+
132
+ class LexiconBody(WireModel):
133
+ """The agent's lexicon: how the voice says its words, and the words the ears must know."""
134
+
135
+ said: list[Pronunciation]
136
+ heard: list[str]
137
+
138
+
139
+ class LexiconRow(WireModel):
140
+ """One kept version of the agent's lexicon."""
141
+
142
+ holder: str
143
+ version: int
144
+ author: str
145
+ note: str | None
146
+ set_at: float
147
+ lexicon: LexiconBody
148
+
149
+
150
+ class LexiconResponse(WireModel):
151
+ """GET /v1/agents/{slug}/lexicon: yours, the team's and production's newest, or null."""
152
+
153
+ world: Env
154
+ yours: LexiconRow | None
155
+ team: LexiconRow | None
156
+ production: LexiconRow | None
157
+
158
+
159
+ class PutLexiconRequest(WireModel):
160
+ """PUT /v1/agents/{slug}/lexicon: the whole lexicon, the version read, why, whose scope."""
161
+
162
+ lexicon: LexiconBody
163
+ if_version: int | None = None
164
+ note: str | None = None
165
+ team: bool = False
166
+
167
+
168
+ class LexiconHistoryResponse(WireModel):
169
+ """GET /v1/agents/{slug}/lexicon/history: one scope's versions, newest first."""
170
+
171
+ world: Env
172
+ holder: str
173
+ rows: list[LexiconRow]
174
+
175
+
176
+ class CallSettingsResponse(WireModel):
177
+ """GET /v1/calls/{call}/settings: the tuning and lexicon the call was built on."""
178
+
179
+ config_version: int | None
180
+ lexicon_version: int | None
181
+ config: SettingsRow | None
182
+ lexicon: LexiconRow | None
183
+ # The call ran a canary's version, picked for its share of the calls.
184
+ canary: bool = False