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,591 @@
1
+ -- The schema as it stood on 2026-09-27: pg_dump --schema-only of the sandbox database. The
2
+ -- extensions (vector, pg_textsearch) are created by the database, not here, and the runner owns
3
+ -- schema_migrations. Applied migrations are never edited: a change is a new file.
4
+
5
+ CREATE FUNCTION call_log_refuses_the_statement() RETURNS trigger
6
+ LANGUAGE plpgsql
7
+ AS $$
8
+ begin
9
+ raise exception 'call_log is append-only: % is refused', tg_op
10
+ using errcode = 'restrict_violation';
11
+ end;
12
+ $$;
13
+
14
+ CREATE TABLE agent_config (
15
+ org text NOT NULL,
16
+ env text NOT NULL,
17
+ holder text NOT NULL,
18
+ agent text NOT NULL,
19
+ version integer NOT NULL,
20
+ config jsonb NOT NULL,
21
+ author text NOT NULL,
22
+ note text,
23
+ set_at timestamp with time zone DEFAULT now() NOT NULL,
24
+ CONSTRAINT agent_config_env_check CHECK ((env = ANY (ARRAY['production'::text, 'sandbox'::text]))),
25
+ CONSTRAINT agent_config_version_check CHECK ((version >= 1))
26
+ );
27
+
28
+ CREATE TABLE agent_personas (
29
+ org text NOT NULL,
30
+ agent text,
31
+ name text NOT NULL,
32
+ about text DEFAULT ''::text NOT NULL,
33
+ goal text NOT NULL,
34
+ style text NOT NULL,
35
+ facts jsonb DEFAULT '{}'::jsonb NOT NULL,
36
+ state jsonb DEFAULT '{}'::jsonb NOT NULL,
37
+ author text DEFAULT ''::text NOT NULL,
38
+ set_at timestamp with time zone DEFAULT now() NOT NULL,
39
+ llm text,
40
+ tts text,
41
+ voice text,
42
+ accepts_when text DEFAULT ''::text NOT NULL,
43
+ declines_when text DEFAULT ''::text NOT NULL
44
+ );
45
+
46
+ CREATE TABLE agent_widgets (
47
+ org text NOT NULL,
48
+ env text NOT NULL,
49
+ agent text NOT NULL,
50
+ title text,
51
+ tagline text,
52
+ greeting text,
53
+ accent text,
54
+ autostart boolean DEFAULT false NOT NULL,
55
+ set_at timestamp with time zone DEFAULT now() NOT NULL,
56
+ theme text,
57
+ CONSTRAINT agent_widgets_env_check CHECK ((env = ANY (ARRAY['production'::text, 'sandbox'::text])))
58
+ );
59
+
60
+ CREATE TABLE api_keys (
61
+ id text NOT NULL,
62
+ hash text NOT NULL,
63
+ org text NOT NULL,
64
+ label text,
65
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
66
+ revoked_at timestamp with time zone,
67
+ env text NOT NULL,
68
+ scopes text[] NOT NULL,
69
+ subject text,
70
+ name text,
71
+ created_by text,
72
+ last_used_at timestamp with time zone,
73
+ expires_at timestamp with time zone,
74
+ CONSTRAINT api_keys_env_check CHECK ((env = ANY (ARRAY['production'::text, 'sandbox'::text])))
75
+ );
76
+
77
+ CREATE TABLE box_settings (
78
+ name text NOT NULL,
79
+ value jsonb NOT NULL,
80
+ ciphertext text,
81
+ set_at timestamp with time zone DEFAULT now() NOT NULL
82
+ );
83
+
84
+ CREATE TABLE call_facts (
85
+ call text NOT NULL,
86
+ channel text,
87
+ direction text,
88
+ from_number text,
89
+ to_number text,
90
+ name text,
91
+ contact text,
92
+ spoken boolean DEFAULT false NOT NULL,
93
+ ended_at double precision,
94
+ end_reason text,
95
+ outcome text,
96
+ cost_eur double precision,
97
+ judged integer,
98
+ held integer,
99
+ passed boolean,
100
+ reason text,
101
+ escalated boolean DEFAULT false NOT NULL,
102
+ promised boolean DEFAULT false NOT NULL,
103
+ e2e double precision[] DEFAULT '{}'::double precision[] NOT NULL,
104
+ heard_at double precision[] DEFAULT '{}'::double precision[] NOT NULL,
105
+ last_text text,
106
+ last_at double precision,
107
+ last_in boolean,
108
+ persona text
109
+ );
110
+
111
+ CREATE TABLE call_log (
112
+ call text,
113
+ seq bigint NOT NULL,
114
+ ts double precision NOT NULL,
115
+ agent text NOT NULL,
116
+ type text NOT NULL,
117
+ ephemeral boolean NOT NULL,
118
+ data jsonb NOT NULL,
119
+ log text GENERATED ALWAYS AS (COALESCE(call, ('@'::text || agent))) STORED NOT NULL,
120
+ "position" bigint NOT NULL,
121
+ CONSTRAINT call_log_call_never_opens_with_at CHECK (((call IS NULL) OR ("left"(call, 1) <> '@'::text)))
122
+ );
123
+
124
+ CREATE TABLE call_log_head (
125
+ log text NOT NULL,
126
+ agent text,
127
+ call text,
128
+ seq bigint DEFAULT 0 NOT NULL,
129
+ sealed boolean DEFAULT false NOT NULL,
130
+ started_at double precision,
131
+ org text,
132
+ env text,
133
+ holder text,
134
+ config_version integer,
135
+ lexicon_version integer
136
+ );
137
+
138
+ ALTER TABLE call_log ALTER COLUMN "position" ADD GENERATED ALWAYS AS IDENTITY (
139
+ SEQUENCE NAME call_log_position_seq
140
+ START WITH 1
141
+ INCREMENT BY 1
142
+ NO MINVALUE
143
+ NO MAXVALUE
144
+ CACHE 1
145
+ );
146
+
147
+ CREATE TABLE carriers (
148
+ org text NOT NULL,
149
+ kind text NOT NULL,
150
+ account text NOT NULL,
151
+ ciphertext text NOT NULL,
152
+ set_at timestamp with time zone DEFAULT now() NOT NULL,
153
+ CONSTRAINT carriers_kind_check CHECK ((kind = ANY (ARRAY['twilio'::text, 'sip'::text])))
154
+ );
155
+
156
+ CREATE TABLE contact_memories (
157
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
158
+ org text NOT NULL,
159
+ contact text NOT NULL,
160
+ text text NOT NULL,
161
+ category text,
162
+ embedding halfvec(1024) NOT NULL,
163
+ valid_from timestamp with time zone NOT NULL,
164
+ invalidated_at timestamp with time zone,
165
+ supersedes uuid,
166
+ source_call text,
167
+ confidence real DEFAULT 1.0 NOT NULL,
168
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
169
+ model text DEFAULT ''::text NOT NULL,
170
+ env text NOT NULL,
171
+ holder text NOT NULL,
172
+ CONSTRAINT contact_memories_env_check CHECK ((env = ANY (ARRAY['production'::text, 'sandbox'::text])))
173
+ );
174
+
175
+ CREATE TABLE dial_policy (
176
+ org text NOT NULL,
177
+ dial_anywhere boolean,
178
+ per_minute integer,
179
+ per_day integer,
180
+ countries text[],
181
+ max_duration_s integer,
182
+ set_at timestamp with time zone DEFAULT now() NOT NULL
183
+ );
184
+
185
+ CREATE TABLE dials (
186
+ id bigint NOT NULL,
187
+ org text NOT NULL,
188
+ env text NOT NULL,
189
+ agent text NOT NULL,
190
+ call text,
191
+ dialled text NOT NULL,
192
+ shown text,
193
+ asked_by text NOT NULL,
194
+ refused text,
195
+ at timestamp with time zone DEFAULT now() NOT NULL,
196
+ CONSTRAINT dials_env_check CHECK ((env = ANY (ARRAY['production'::text, 'sandbox'::text])))
197
+ );
198
+
199
+ CREATE SEQUENCE dials_id_seq
200
+ START WITH 1
201
+ INCREMENT BY 1
202
+ NO MINVALUE
203
+ NO MAXVALUE
204
+ CACHE 1;
205
+
206
+ ALTER SEQUENCE dials_id_seq OWNED BY dials.id;
207
+
208
+ CREATE TABLE eval_runs (
209
+ id text NOT NULL,
210
+ agent text NOT NULL,
211
+ started_at double precision NOT NULL,
212
+ finished_at double precision,
213
+ status text NOT NULL,
214
+ document jsonb NOT NULL
215
+ );
216
+
217
+ CREATE TABLE hold_audio (
218
+ org text NOT NULL,
219
+ agent text NOT NULL,
220
+ played text NOT NULL,
221
+ audio bytea,
222
+ sha256 text,
223
+ seconds real,
224
+ name text,
225
+ set_at timestamp with time zone DEFAULT now() NOT NULL,
226
+ CONSTRAINT hold_audio_check CHECK (((played = 'custom'::text) = ((audio IS NOT NULL) AND (sha256 IS NOT NULL)))),
227
+ CONSTRAINT hold_audio_played_check CHECK ((played = ANY (ARRAY['off'::text, 'custom'::text])))
228
+ );
229
+
230
+ CREATE TABLE invitations (
231
+ token_hash text NOT NULL,
232
+ member text NOT NULL,
233
+ expires_at timestamp with time zone NOT NULL,
234
+ spent_at timestamp with time zone,
235
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
236
+ vouched boolean DEFAULT false NOT NULL
237
+ );
238
+
239
+ CREATE TABLE knowledge_bases (
240
+ org text NOT NULL,
241
+ base text NOT NULL,
242
+ model text NOT NULL,
243
+ dimensions integer NOT NULL,
244
+ chunks integer NOT NULL,
245
+ pushed_at timestamp with time zone DEFAULT now() NOT NULL,
246
+ env text NOT NULL,
247
+ holder text NOT NULL,
248
+ CONSTRAINT knowledge_bases_env_check CHECK ((env = ANY (ARRAY['production'::text, 'sandbox'::text])))
249
+ );
250
+
251
+ CREATE TABLE knowledge_chunks (
252
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
253
+ org text NOT NULL,
254
+ base text NOT NULL,
255
+ path text NOT NULL,
256
+ heading text,
257
+ ordinal integer NOT NULL,
258
+ text text NOT NULL,
259
+ embedding halfvec(1024),
260
+ env text NOT NULL,
261
+ holder text NOT NULL,
262
+ mode text DEFAULT 'retrieved'::text NOT NULL,
263
+ CONSTRAINT knowledge_chunks_env_check CHECK ((env = ANY (ARRAY['production'::text, 'sandbox'::text]))),
264
+ CONSTRAINT knowledge_chunks_mode_check CHECK ((mode = ANY (ARRAY['retrieved'::text, 'whole'::text])))
265
+ );
266
+
267
+ CREATE TABLE knowledge_files (
268
+ org text NOT NULL,
269
+ env text NOT NULL,
270
+ holder text NOT NULL,
271
+ base text NOT NULL,
272
+ path text NOT NULL,
273
+ text text NOT NULL,
274
+ chunks integer NOT NULL,
275
+ pushed_at timestamp with time zone DEFAULT now() NOT NULL
276
+ );
277
+
278
+ CREATE TABLE lexicon (
279
+ org text NOT NULL,
280
+ env text NOT NULL,
281
+ holder text NOT NULL,
282
+ version integer NOT NULL,
283
+ said jsonb DEFAULT '{}'::jsonb NOT NULL,
284
+ heard jsonb DEFAULT '[]'::jsonb NOT NULL,
285
+ author text NOT NULL,
286
+ note text,
287
+ set_at timestamp with time zone DEFAULT now() NOT NULL,
288
+ CONSTRAINT lexicon_env_check CHECK ((env = ANY (ARRAY['production'::text, 'sandbox'::text]))),
289
+ CONSTRAINT lexicon_version_check CHECK ((version >= 1))
290
+ );
291
+
292
+ CREATE TABLE members (
293
+ id text NOT NULL,
294
+ org text NOT NULL,
295
+ email text NOT NULL,
296
+ name text NOT NULL,
297
+ role text NOT NULL,
298
+ agents text[] DEFAULT '{}'::text[] NOT NULL,
299
+ status text NOT NULL,
300
+ password_hash text,
301
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
302
+ operator boolean DEFAULT false NOT NULL,
303
+ production boolean DEFAULT false NOT NULL,
304
+ verified_at timestamp with time zone,
305
+ CONSTRAINT members_role_check CHECK ((role = ANY (ARRAY['qa'::text, 'supervisor'::text, 'manager'::text, 'admin'::text, 'developer'::text]))),
306
+ CONSTRAINT members_status_check CHECK ((status = ANY (ARRAY['invited'::text, 'active'::text, 'disabled'::text])))
307
+ );
308
+
309
+ CREATE TABLE org_mail (
310
+ org text NOT NULL,
311
+ host text NOT NULL,
312
+ port integer NOT NULL,
313
+ security text NOT NULL,
314
+ username text NOT NULL,
315
+ ciphertext text NOT NULL,
316
+ sender text NOT NULL,
317
+ verified_at timestamp with time zone,
318
+ last_error text,
319
+ set_at timestamp with time zone DEFAULT now() NOT NULL
320
+ );
321
+
322
+ CREATE TABLE org_sso (
323
+ org text NOT NULL,
324
+ issuer text NOT NULL,
325
+ client_id text NOT NULL,
326
+ ciphertext text NOT NULL,
327
+ domains text[] NOT NULL,
328
+ role text,
329
+ required boolean DEFAULT false NOT NULL,
330
+ set_at timestamp with time zone DEFAULT now() NOT NULL
331
+ );
332
+
333
+ CREATE TABLE orgs (
334
+ id text NOT NULL,
335
+ slug text NOT NULL,
336
+ name text NOT NULL,
337
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
338
+ judging boolean
339
+ );
340
+
341
+ CREATE TABLE outbound_trunks (
342
+ org text NOT NULL,
343
+ kind text NOT NULL,
344
+ trunk_id text NOT NULL,
345
+ address text NOT NULL,
346
+ username text,
347
+ ciphertext text,
348
+ set_at timestamp with time zone DEFAULT now() NOT NULL,
349
+ CONSTRAINT outbound_trunks_kind_check CHECK ((kind = ANY (ARRAY['twilio'::text, 'sip'::text])))
350
+ );
351
+
352
+ CREATE TABLE provider_keys (
353
+ org text NOT NULL,
354
+ vendor text NOT NULL,
355
+ ciphertext text NOT NULL,
356
+ set_at timestamp with time zone DEFAULT now() NOT NULL
357
+ );
358
+
359
+ CREATE TABLE quotas (
360
+ org text NOT NULL,
361
+ minutes integer,
362
+ messages integer,
363
+ agents integer,
364
+ concurrent_calls integer,
365
+ set_at timestamp with time zone DEFAULT now() NOT NULL,
366
+ memory_facts integer,
367
+ knowledge_chunks integer,
368
+ numbers integer,
369
+ seats integer,
370
+ budget_eur integer,
371
+ lends text[],
372
+ llm_tokens bigint
373
+ );
374
+
375
+ CREATE TABLE routes (
376
+ org text NOT NULL,
377
+ number text NOT NULL,
378
+ agent text NOT NULL,
379
+ channel text NOT NULL,
380
+ added_at timestamp with time zone DEFAULT now() NOT NULL,
381
+ env text NOT NULL,
382
+ managed boolean DEFAULT false NOT NULL,
383
+ CONSTRAINT routes_env_check CHECK ((env = ANY (ARRAY['production'::text, 'sandbox'::text])))
384
+ );
385
+
386
+ CREATE TABLE thread_reads (
387
+ org text NOT NULL,
388
+ env text NOT NULL,
389
+ holder text NOT NULL,
390
+ agent text NOT NULL,
391
+ reader text NOT NULL,
392
+ contact text NOT NULL,
393
+ read_at double precision NOT NULL
394
+ );
395
+
396
+ CREATE TABLE tokens (
397
+ call text NOT NULL,
398
+ org text NOT NULL,
399
+ agent text NOT NULL,
400
+ scope text NOT NULL,
401
+ minted_at timestamp with time zone DEFAULT now() NOT NULL,
402
+ expires_at timestamp with time zone NOT NULL,
403
+ spent_at timestamp with time zone
404
+ );
405
+
406
+ ALTER TABLE ONLY dials ALTER COLUMN id SET DEFAULT nextval('dials_id_seq'::regclass);
407
+
408
+ ALTER TABLE ONLY agent_config
409
+ ADD CONSTRAINT agent_config_pkey PRIMARY KEY (org, env, holder, agent, version);
410
+
411
+ ALTER TABLE ONLY agent_personas
412
+ ADD CONSTRAINT agent_personas_pkey PRIMARY KEY (org, name);
413
+
414
+ ALTER TABLE ONLY agent_widgets
415
+ ADD CONSTRAINT agent_widgets_pkey PRIMARY KEY (org, env, agent);
416
+
417
+ ALTER TABLE ONLY api_keys
418
+ ADD CONSTRAINT api_keys_hash_key UNIQUE (hash);
419
+
420
+ ALTER TABLE ONLY api_keys
421
+ ADD CONSTRAINT api_keys_pkey PRIMARY KEY (id);
422
+
423
+ ALTER TABLE ONLY box_settings
424
+ ADD CONSTRAINT box_settings_pkey PRIMARY KEY (name);
425
+
426
+ ALTER TABLE ONLY call_facts
427
+ ADD CONSTRAINT call_facts_pkey PRIMARY KEY (call);
428
+
429
+ ALTER TABLE ONLY call_log_head
430
+ ADD CONSTRAINT call_log_head_pkey PRIMARY KEY (log);
431
+
432
+ ALTER TABLE ONLY call_log
433
+ ADD CONSTRAINT call_log_one_row_per_seq PRIMARY KEY (log, seq);
434
+
435
+ ALTER TABLE ONLY carriers
436
+ ADD CONSTRAINT carriers_pkey PRIMARY KEY (org);
437
+
438
+ ALTER TABLE ONLY contact_memories
439
+ ADD CONSTRAINT contact_memories_pkey PRIMARY KEY (id);
440
+
441
+ ALTER TABLE ONLY dial_policy
442
+ ADD CONSTRAINT dial_policy_pkey PRIMARY KEY (org);
443
+
444
+ ALTER TABLE ONLY dials
445
+ ADD CONSTRAINT dials_pkey PRIMARY KEY (id);
446
+
447
+ ALTER TABLE ONLY eval_runs
448
+ ADD CONSTRAINT eval_runs_pkey PRIMARY KEY (id);
449
+
450
+ ALTER TABLE ONLY hold_audio
451
+ ADD CONSTRAINT hold_audio_pkey PRIMARY KEY (org, agent);
452
+
453
+ ALTER TABLE ONLY invitations
454
+ ADD CONSTRAINT invitations_pkey PRIMARY KEY (token_hash);
455
+
456
+ ALTER TABLE ONLY knowledge_bases
457
+ ADD CONSTRAINT knowledge_bases_pkey PRIMARY KEY (org, env, holder, base);
458
+
459
+ ALTER TABLE ONLY knowledge_chunks
460
+ ADD CONSTRAINT knowledge_chunks_pkey PRIMARY KEY (id);
461
+
462
+ ALTER TABLE ONLY knowledge_files
463
+ ADD CONSTRAINT knowledge_files_pkey PRIMARY KEY (org, env, holder, base, path);
464
+
465
+ ALTER TABLE ONLY lexicon
466
+ ADD CONSTRAINT lexicon_pkey PRIMARY KEY (org, env, holder, version);
467
+
468
+ ALTER TABLE ONLY members
469
+ ADD CONSTRAINT members_org_email_key UNIQUE (org, email);
470
+
471
+ ALTER TABLE ONLY members
472
+ ADD CONSTRAINT members_pkey PRIMARY KEY (id);
473
+
474
+ ALTER TABLE ONLY org_mail
475
+ ADD CONSTRAINT org_mail_pkey PRIMARY KEY (org);
476
+
477
+ ALTER TABLE ONLY org_sso
478
+ ADD CONSTRAINT org_sso_pkey PRIMARY KEY (org);
479
+
480
+ ALTER TABLE ONLY orgs
481
+ ADD CONSTRAINT orgs_pkey PRIMARY KEY (id);
482
+
483
+ ALTER TABLE ONLY orgs
484
+ ADD CONSTRAINT orgs_slug_key UNIQUE (slug);
485
+
486
+ ALTER TABLE ONLY outbound_trunks
487
+ ADD CONSTRAINT outbound_trunks_pkey PRIMARY KEY (org);
488
+
489
+ ALTER TABLE ONLY provider_keys
490
+ ADD CONSTRAINT provider_keys_pkey PRIMARY KEY (org, vendor);
491
+
492
+ ALTER TABLE ONLY quotas
493
+ ADD CONSTRAINT quotas_pkey PRIMARY KEY (org);
494
+
495
+ ALTER TABLE ONLY routes
496
+ ADD CONSTRAINT routes_pkey PRIMARY KEY (org, number);
497
+
498
+ ALTER TABLE ONLY thread_reads
499
+ ADD CONSTRAINT thread_reads_pkey PRIMARY KEY (org, env, holder, agent, reader, contact);
500
+
501
+ ALTER TABLE ONLY tokens
502
+ ADD CONSTRAINT tokens_pkey PRIMARY KEY (call);
503
+
504
+ CREATE INDEX call_facts_by_contact ON call_facts USING btree (contact) WHERE (contact IS NOT NULL);
505
+
506
+ CREATE INDEX call_facts_by_persona ON call_facts USING btree (persona) WHERE (persona IS NOT NULL);
507
+
508
+ CREATE INDEX call_log_head_by_agent ON call_log_head USING btree (agent, started_at) WHERE (call IS NOT NULL);
509
+
510
+ CREATE INDEX call_log_head_by_corner ON call_log_head USING btree (org, env, holder, started_at DESC) WHERE (call IS NOT NULL);
511
+
512
+ CREATE INDEX call_log_metered ON call_log USING btree (type, "position");
513
+
514
+ CREATE INDEX contact_memories_current ON contact_memories USING btree (org, env, holder, contact) WHERE (invalidated_at IS NULL);
515
+
516
+ CREATE INDEX contact_memories_embedding_hnsw ON contact_memories USING hnsw (embedding halfvec_cosine_ops);
517
+
518
+ CREATE INDEX contact_memories_text_bm25 ON contact_memories USING bm25 (text) WITH (text_config=spanish);
519
+
520
+ CREATE INDEX dials_by_org ON dials USING btree (org, at DESC);
521
+
522
+ CREATE INDEX eval_runs_newest_first ON eval_runs USING btree (started_at DESC);
523
+
524
+ CREATE INDEX knowledge_chunks_by_base ON knowledge_chunks USING btree (org, env, holder, base);
525
+
526
+ CREATE INDEX knowledge_chunks_embedding_hnsw ON knowledge_chunks USING hnsw (embedding halfvec_cosine_ops);
527
+
528
+ CREATE INDEX knowledge_chunks_text_bm25 ON knowledge_chunks USING bm25 (text) WITH (text_config=spanish);
529
+
530
+ CREATE INDEX members_operators ON members USING btree (id) WHERE operator;
531
+
532
+ CREATE TRIGGER call_log_refuses_delete BEFORE DELETE ON call_log FOR EACH STATEMENT EXECUTE FUNCTION call_log_refuses_the_statement();
533
+
534
+ CREATE TRIGGER call_log_refuses_update BEFORE UPDATE ON call_log FOR EACH STATEMENT EXECUTE FUNCTION call_log_refuses_the_statement();
535
+
536
+ ALTER TABLE ONLY agent_config
537
+ ADD CONSTRAINT agent_config_org_fkey FOREIGN KEY (org) REFERENCES orgs(id) ON DELETE CASCADE;
538
+
539
+ ALTER TABLE ONLY agent_personas
540
+ ADD CONSTRAINT agent_personas_org_fkey FOREIGN KEY (org) REFERENCES orgs(id) ON DELETE CASCADE;
541
+
542
+ ALTER TABLE ONLY agent_widgets
543
+ ADD CONSTRAINT agent_widgets_org_fkey FOREIGN KEY (org) REFERENCES orgs(id) ON DELETE CASCADE;
544
+
545
+ ALTER TABLE ONLY carriers
546
+ ADD CONSTRAINT carriers_org_fkey FOREIGN KEY (org) REFERENCES orgs(id) ON DELETE CASCADE;
547
+
548
+ ALTER TABLE ONLY contact_memories
549
+ ADD CONSTRAINT contact_memories_org_fkey FOREIGN KEY (org) REFERENCES orgs(id) ON DELETE CASCADE;
550
+
551
+ ALTER TABLE ONLY contact_memories
552
+ ADD CONSTRAINT contact_memories_supersedes_fkey FOREIGN KEY (supersedes) REFERENCES contact_memories(id);
553
+
554
+ ALTER TABLE ONLY dial_policy
555
+ ADD CONSTRAINT dial_policy_org_fkey FOREIGN KEY (org) REFERENCES orgs(id) ON DELETE CASCADE;
556
+
557
+ ALTER TABLE ONLY invitations
558
+ ADD CONSTRAINT invitations_member_fkey FOREIGN KEY (member) REFERENCES members(id) ON DELETE CASCADE;
559
+
560
+ ALTER TABLE ONLY knowledge_bases
561
+ ADD CONSTRAINT knowledge_bases_org_fkey FOREIGN KEY (org) REFERENCES orgs(id) ON DELETE CASCADE;
562
+
563
+ ALTER TABLE ONLY knowledge_chunks
564
+ ADD CONSTRAINT knowledge_chunks_org_env_holder_base_fkey FOREIGN KEY (org, env, holder, base) REFERENCES knowledge_bases(org, env, holder, base) ON DELETE CASCADE;
565
+
566
+ ALTER TABLE ONLY knowledge_files
567
+ ADD CONSTRAINT knowledge_files_org_env_holder_base_fkey FOREIGN KEY (org, env, holder, base) REFERENCES knowledge_bases(org, env, holder, base) ON DELETE CASCADE;
568
+
569
+ ALTER TABLE ONLY lexicon
570
+ ADD CONSTRAINT lexicon_org_fkey FOREIGN KEY (org) REFERENCES orgs(id) ON DELETE CASCADE;
571
+
572
+ ALTER TABLE ONLY members
573
+ ADD CONSTRAINT members_org_fkey FOREIGN KEY (org) REFERENCES orgs(id) ON DELETE CASCADE;
574
+
575
+ ALTER TABLE ONLY org_mail
576
+ ADD CONSTRAINT org_mail_org_fkey FOREIGN KEY (org) REFERENCES orgs(id) ON DELETE CASCADE;
577
+
578
+ ALTER TABLE ONLY org_sso
579
+ ADD CONSTRAINT org_sso_org_fkey FOREIGN KEY (org) REFERENCES orgs(id) ON DELETE CASCADE;
580
+
581
+ ALTER TABLE ONLY outbound_trunks
582
+ ADD CONSTRAINT outbound_trunks_org_fkey FOREIGN KEY (org) REFERENCES orgs(id) ON DELETE CASCADE;
583
+
584
+ ALTER TABLE ONLY provider_keys
585
+ ADD CONSTRAINT provider_keys_org_fkey FOREIGN KEY (org) REFERENCES orgs(id) ON DELETE CASCADE;
586
+
587
+ ALTER TABLE ONLY quotas
588
+ ADD CONSTRAINT quotas_org_fkey FOREIGN KEY (org) REFERENCES orgs(id) ON DELETE CASCADE;
589
+
590
+ -- The org the first key is issued against, and the one a verb that names none falls back to.
591
+ INSERT INTO orgs (id, slug, name) VALUES ('default', 'default', 'default') ON CONFLICT DO NOTHING;
@@ -0,0 +1,15 @@
1
+ -- One database serves both worlds, so an org's limits and an agent's hold melody are kept per
2
+ -- world, as the tuning, the lexicon and the widget already are. A row written before this
3
+ -- migration is production's: the sandbox's rows arrive with their world at the cutover.
4
+
5
+ ALTER TABLE quotas ADD COLUMN env text NOT NULL DEFAULT 'production'
6
+ CONSTRAINT quotas_env_check CHECK (env = ANY (ARRAY['production'::text, 'sandbox'::text]));
7
+ ALTER TABLE quotas ALTER COLUMN env DROP DEFAULT;
8
+ ALTER TABLE quotas DROP CONSTRAINT quotas_pkey;
9
+ ALTER TABLE quotas ADD CONSTRAINT quotas_pkey PRIMARY KEY (org, env);
10
+
11
+ ALTER TABLE hold_audio ADD COLUMN env text NOT NULL DEFAULT 'production'
12
+ CONSTRAINT hold_audio_env_check CHECK (env = ANY (ARRAY['production'::text, 'sandbox'::text]));
13
+ ALTER TABLE hold_audio ALTER COLUMN env DROP DEFAULT;
14
+ ALTER TABLE hold_audio DROP CONSTRAINT hold_audio_pkey;
15
+ ALTER TABLE hold_audio ADD CONSTRAINT hold_audio_pkey PRIMARY KEY (org, env, agent);
@@ -0,0 +1,4 @@
1
+ -- The vendors a call ran on the box's own key: their usage is the operator's to bill. Kept with
2
+ -- the call's facts at its seal, and not on the wire.
3
+
4
+ ALTER TABLE call_facts ADD COLUMN lent text[] NOT NULL DEFAULT '{}';
@@ -0,0 +1,23 @@
1
+ -- An org holds many carrier accounts (Twilio accounts, SIP peers, WhatsApp numbers at Meta), one
2
+ -- row each, keyed by the account's own id. A route names the account its number lives in, or
3
+ -- none: a number the org hooked itself, or one the box bought. A number the org hooked itself
4
+ -- keeps the networks the box admits it from on its own row.
5
+
6
+ ALTER TABLE carriers DROP CONSTRAINT carriers_pkey;
7
+ ALTER TABLE carriers ADD CONSTRAINT carriers_pkey PRIMARY KEY (org, account);
8
+ ALTER TABLE carriers ADD COLUMN label text NOT NULL DEFAULT '';
9
+ ALTER TABLE carriers DROP CONSTRAINT carriers_kind_check;
10
+ ALTER TABLE carriers ADD CONSTRAINT carriers_kind_check
11
+ CHECK (kind = ANY (ARRAY['twilio'::text, 'sip'::text, 'whatsapp'::text]));
12
+
13
+ ALTER TABLE routes ADD COLUMN account text;
14
+ ALTER TABLE routes ADD COLUMN networks text[] NOT NULL DEFAULT '{}';
15
+ -- Forgetting an account leaves its numbers routed until each is let go.
16
+ ALTER TABLE routes ADD CONSTRAINT routes_account_fkey FOREIGN KEY (org, account)
17
+ REFERENCES carriers (org, account) ON DELETE SET NULL (account);
18
+
19
+ -- The SFU keeps no outbound trunk: a leg is dialled with its trunk inline.
20
+ DROP TABLE outbound_trunks;
21
+
22
+ -- Which countries a dial reaches is the carrier account's setting; nothing ever read this.
23
+ ALTER TABLE dial_policy DROP COLUMN countries;
@@ -0,0 +1,11 @@
1
+ -- Every chunk is found by its vector: no chunk is kept whole without one. A file keeps the hash of
2
+ -- the text it was cut from, so a push embeds only the files that changed; blank means pushed before
3
+ -- this migration, and the next push fills it.
4
+
5
+ -- Nothing ever wrote such a row; the statement makes the two constraints below safe to add.
6
+ DELETE FROM knowledge_chunks WHERE mode <> 'retrieved' OR embedding IS NULL;
7
+
8
+ ALTER TABLE knowledge_chunks DROP COLUMN mode;
9
+ ALTER TABLE knowledge_chunks ALTER COLUMN embedding SET NOT NULL;
10
+
11
+ ALTER TABLE knowledge_files ADD COLUMN sha256 text NOT NULL DEFAULT '';
@@ -0,0 +1,9 @@
1
+ -- A persona is written for the agents it may call; none named is every agent of the org, which is
2
+ -- what a row without an agent meant.
3
+ ALTER TABLE agent_personas ADD COLUMN agents text[] NOT NULL DEFAULT '{}';
4
+ UPDATE agent_personas SET agents = ARRAY[agent] WHERE agent IS NOT NULL;
5
+ ALTER TABLE agent_personas DROP COLUMN agent;
6
+
7
+ -- A run belongs to an org and a world; a row restored without them is listed once they are filled.
8
+ ALTER TABLE eval_runs ADD COLUMN org text, ADD COLUMN env text;
9
+ CREATE INDEX eval_runs_by_scope ON eval_runs (org, env, started_at DESC);
@@ -0,0 +1,27 @@
1
+ -- Money in US dollars: what a call cost, and what an org may spend in a month.
2
+ --
3
+ -- Providers price in dollars, so the runtime stops converting to euros at a rate. Every euro
4
+ -- kept so far becomes the same number of dollars, never converted: a budget of 50 euros is $50,
5
+ -- and a call that cost 2 euros cost $2. A database taken over from v1 may carry both columns
6
+ -- already, the dollar one beside the euro one: there the dollars that are missing are copied
7
+ -- from the euros, and the euro column goes.
8
+
9
+ DO $$
10
+ BEGIN
11
+ IF EXISTS (SELECT 1 FROM information_schema.columns
12
+ WHERE table_schema = current_schema() AND table_name = 'call_facts'
13
+ AND column_name = 'cost_usd') THEN
14
+ UPDATE call_facts SET cost_usd = cost_eur WHERE cost_usd IS NULL;
15
+ ALTER TABLE call_facts DROP COLUMN cost_eur;
16
+ ELSE
17
+ ALTER TABLE call_facts RENAME COLUMN cost_eur TO cost_usd;
18
+ END IF;
19
+ IF EXISTS (SELECT 1 FROM information_schema.columns
20
+ WHERE table_schema = current_schema() AND table_name = 'quotas'
21
+ AND column_name = 'budget_usd') THEN
22
+ UPDATE quotas SET budget_usd = budget_eur WHERE budget_usd IS NULL;
23
+ ALTER TABLE quotas DROP COLUMN budget_eur;
24
+ ELSE
25
+ ALTER TABLE quotas RENAME COLUMN budget_eur TO budget_usd;
26
+ END IF;
27
+ END $$;