@superpanel-sdk/runtime 0.2.2 → 0.5.0

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 (274) hide show
  1. package/README.md +28 -8
  2. package/dist/builder/codegen/emit.d.ts +29 -11
  3. package/dist/builder/codegen/emit.js +328 -61
  4. package/dist/builder/codegen/generate.d.ts +21 -0
  5. package/dist/builder/codegen/generate.js +152 -20
  6. package/dist/builder/company-import-graph.d.ts +2 -0
  7. package/dist/builder/company-import-graph.js +40 -8
  8. package/dist/builder/company-imports.d.ts +24 -0
  9. package/dist/builder/company-imports.js +114 -0
  10. package/dist/builder/compile/compile-sequence.d.ts +59 -8
  11. package/dist/builder/compile/compile-sequence.js +279 -77
  12. package/dist/builder/compile/function-code.d.ts +12 -2
  13. package/dist/builder/compile/function-code.js +87 -39
  14. package/dist/builder/compile/registry.d.ts +7 -3
  15. package/dist/builder/compile/registry.js +24 -23
  16. package/dist/builder/load.d.ts +70 -10
  17. package/dist/builder/load.js +250 -61
  18. package/dist/builder/paths.d.ts +3 -0
  19. package/dist/builder/paths.js +16 -0
  20. package/dist/builder/schedules.d.ts +23 -0
  21. package/dist/builder/schedules.js +102 -0
  22. package/dist/builder/slot-schema-validation.d.ts +4 -0
  23. package/dist/builder/slot-schema-validation.js +10 -0
  24. package/dist/builder/typecheck.d.ts +8 -0
  25. package/dist/builder/typecheck.js +105 -0
  26. package/dist/builder/types.d.ts +91 -19
  27. package/dist/builder/types.js +2 -1
  28. package/dist/cli/auth/auth.d.ts +37 -0
  29. package/dist/cli/auth/auth.js +211 -0
  30. package/dist/cli/auth/backend-url.d.ts +5 -0
  31. package/dist/cli/auth/backend-url.js +25 -0
  32. package/dist/cli/auth/clipboard.d.ts +9 -0
  33. package/dist/cli/auth/clipboard.js +38 -0
  34. package/dist/cli/auth/http.d.ts +20 -0
  35. package/dist/cli/auth/http.js +27 -0
  36. package/dist/cli/auth/index.d.ts +10 -0
  37. package/dist/cli/auth/index.js +27 -0
  38. package/dist/cli/auth/progress.d.ts +12 -0
  39. package/dist/cli/auth/progress.js +15 -0
  40. package/dist/cli/auth/serve-login.d.ts +8 -0
  41. package/dist/cli/auth/serve-login.js +24 -0
  42. package/dist/cli/compile/index.js +3 -0
  43. package/dist/cli/config.d.ts +10 -0
  44. package/dist/cli/config.js +52 -0
  45. package/dist/cli/index.js +28 -8
  46. package/dist/cli/serve/index.d.ts +73 -3
  47. package/dist/cli/serve/index.js +410 -113
  48. package/dist/cli/type-gen/index.js +9 -8
  49. package/dist/compiler.d.ts +7 -0
  50. package/dist/compiler.js +7 -0
  51. package/dist/compute-host/compute-host.d.ts +15 -23
  52. package/dist/compute-host/compute-host.js +25 -28
  53. package/dist/compute-host/index.d.ts +2 -2
  54. package/dist/compute-host/index.js +1 -1
  55. package/dist/compute-host/source-compute-host.d.ts +11 -9
  56. package/dist/compute-host/source-compute-host.js +50 -31
  57. package/dist/core/case-orchestrator/contact-hours.d.ts +50 -0
  58. package/dist/core/case-orchestrator/contact-hours.js +108 -0
  59. package/dist/core/case-orchestrator/follow-ups.d.ts +31 -0
  60. package/dist/core/case-orchestrator/follow-ups.js +103 -0
  61. package/dist/core/case-orchestrator/index.d.ts +6 -0
  62. package/dist/core/case-orchestrator/index.js +6 -0
  63. package/dist/core/case-orchestrator/render.d.ts +75 -0
  64. package/dist/core/case-orchestrator/render.js +239 -0
  65. package/dist/core/case-orchestrator/time.d.ts +11 -0
  66. package/dist/core/case-orchestrator/time.js +29 -0
  67. package/dist/core/case-orchestrator/tools.d.ts +29 -0
  68. package/dist/core/case-orchestrator/tools.js +31 -0
  69. package/dist/core/case-orchestrator/types.d.ts +753 -0
  70. package/dist/core/case-orchestrator/types.js +46 -0
  71. package/dist/core/case-orchestrator/validate.d.ts +11 -0
  72. package/dist/core/case-orchestrator/validate.js +63 -0
  73. package/dist/core/context/call.d.ts +291 -0
  74. package/dist/core/context/call.js +94 -0
  75. package/dist/core/context/channels.d.ts +60 -0
  76. package/dist/core/context/channels.js +35 -0
  77. package/dist/core/context/contact.d.ts +96 -6
  78. package/dist/core/context/contact.js +48 -2
  79. package/dist/core/context/email-message.d.ts +159 -0
  80. package/dist/core/context/email-message.js +59 -0
  81. package/dist/core/context/email.d.ts +97 -0
  82. package/dist/core/context/email.js +91 -0
  83. package/dist/core/context/exchanges.d.ts +142 -0
  84. package/dist/core/context/exchanges.js +63 -0
  85. package/dist/core/context/instances.d.ts +278 -0
  86. package/dist/core/context/instances.js +123 -0
  87. package/dist/core/context/kv.d.ts +113 -0
  88. package/dist/core/context/kv.js +60 -0
  89. package/dist/core/context/platform-registry.d.ts +509 -4
  90. package/dist/core/context/platform-registry.js +14 -2
  91. package/dist/core/context/platform.d.ts +2 -1
  92. package/dist/core/context/sms.d.ts +147 -0
  93. package/dist/core/context/sms.js +57 -0
  94. package/dist/core/context/types.d.ts +51 -30
  95. package/dist/core/context/types.js +1 -7
  96. package/dist/core/conversation/index.d.ts +31 -0
  97. package/dist/core/conversation/index.js +14 -0
  98. package/dist/core/functions/define/bind.d.ts +25 -0
  99. package/dist/core/functions/define/bind.js +14 -0
  100. package/dist/core/functions/define/case.d.ts +9 -0
  101. package/dist/core/functions/define/case.js +13 -0
  102. package/dist/core/functions/define/events.d.ts +20 -0
  103. package/dist/core/functions/define/events.js +21 -0
  104. package/dist/core/functions/define/no-case.d.ts +4 -0
  105. package/dist/core/functions/define/no-case.js +9 -0
  106. package/dist/core/functions/events.d.ts +247 -0
  107. package/dist/core/functions/events.js +32 -0
  108. package/dist/core/functions/func-ref.d.ts +11 -2
  109. package/dist/core/functions/schedules.d.ts +51 -0
  110. package/dist/core/functions/schedules.js +20 -0
  111. package/dist/core/functions/types.d.ts +62 -51
  112. package/dist/core/functions/types.js +6 -1
  113. package/dist/core/office-hours/index.d.ts +39 -0
  114. package/dist/core/office-hours/index.js +187 -0
  115. package/dist/core/page/define.d.ts +834 -0
  116. package/dist/core/page/define.js +477 -0
  117. package/dist/core/page/ops.d.ts +58 -0
  118. package/dist/core/page/ops.js +220 -0
  119. package/dist/core/page/render.d.ts +253 -0
  120. package/dist/core/page/render.js +840 -0
  121. package/dist/core/page/time-format.d.ts +19 -0
  122. package/dist/core/page/time-format.js +41 -0
  123. package/dist/core/page/timeline.d.ts +40 -0
  124. package/dist/core/page/timeline.js +2 -0
  125. package/dist/core/page/typed.d.ts +642 -0
  126. package/dist/core/page/typed.js +2 -0
  127. package/dist/core/page/workspace.d.ts +33 -0
  128. package/dist/core/page/workspace.js +231 -0
  129. package/dist/core/party/index.d.ts +3 -0
  130. package/dist/core/party/index.js +3 -0
  131. package/dist/core/party/schema.d.ts +137 -0
  132. package/dist/core/party/schema.js +80 -0
  133. package/dist/core/party/types.d.ts +40 -0
  134. package/dist/core/party/types.js +15 -0
  135. package/dist/core/sequence/define.d.ts +57 -0
  136. package/dist/core/sequence/define.js +10 -0
  137. package/dist/core/sequence/index.d.ts +63 -0
  138. package/dist/core/sequence/index.js +231 -0
  139. package/dist/core/slot/binding.d.ts +40 -0
  140. package/dist/core/slot/binding.js +2 -0
  141. package/dist/core/slot/company-metadata.d.ts +113 -0
  142. package/dist/core/slot/company-metadata.js +563 -0
  143. package/dist/core/slot/compile-schema.d.ts +19 -13
  144. package/dist/core/slot/compile-schema.js +51 -248
  145. package/dist/core/slot/contact-timezone.d.ts +110 -0
  146. package/dist/core/slot/contact-timezone.js +186 -0
  147. package/dist/core/slot/field.d.ts +2 -24
  148. package/dist/core/slot/field.js +0 -69
  149. package/dist/core/slot/id-ref.d.ts +17 -2
  150. package/dist/core/slot/id-ref.js +16 -8
  151. package/dist/core/slot/index.d.ts +12 -13
  152. package/dist/core/slot/index.js +11 -12
  153. package/dist/core/slot/naming.d.ts +15 -0
  154. package/dist/core/slot/naming.js +96 -0
  155. package/dist/core/slot/platform-fields.d.ts +119 -0
  156. package/dist/core/slot/platform-fields.js +121 -0
  157. package/dist/core/slot/ref.d.ts +16 -0
  158. package/dist/core/slot/ref.js +14 -0
  159. package/dist/core/slot/row.d.ts +2 -9
  160. package/dist/core/slot/row.js +13 -23
  161. package/dist/core/slot/schema-compat.d.ts +16 -0
  162. package/dist/core/slot/schema-compat.js +112 -0
  163. package/dist/core/slot/schema.d.ts +409 -76
  164. package/dist/core/slot/schema.js +178 -10
  165. package/dist/core/slot/types.d.ts +27 -92
  166. package/dist/core/slot/value.d.ts +26 -3
  167. package/dist/core/slot/value.js +89 -57
  168. package/dist/dev-overlay/protocol.d.ts +41 -8
  169. package/dist/fn-context/build-context.d.ts +3 -1
  170. package/dist/fn-context/build-context.js +20 -10
  171. package/dist/fn-context/fake/empty-api.js +9 -28
  172. package/dist/fn-context/fake/index.d.ts +11 -4
  173. package/dist/fn-context/fake/index.js +27 -2
  174. package/dist/fn-context/fn-params.d.ts +6 -0
  175. package/dist/fn-context/fn-params.js +13 -0
  176. package/dist/fn-context/index.d.ts +5 -5
  177. package/dist/fn-context/index.js +4 -4
  178. package/dist/fn-context/log.js +2 -2
  179. package/dist/fn-context/make-ctx.d.ts +11 -0
  180. package/dist/fn-context/make-ctx.js +18 -8
  181. package/dist/fn-context/rpc/case-orchestrator-tools.d.ts +24 -0
  182. package/dist/fn-context/rpc/case-orchestrator-tools.js +13 -0
  183. package/dist/fn-context/rpc/index.d.ts +3 -1
  184. package/dist/fn-context/rpc/index.js +3 -1
  185. package/dist/fn-context/rpc/integration/index.d.ts +4 -4
  186. package/dist/fn-context/rpc/integration/index.js +1 -1
  187. package/dist/fn-context/rpc/integration/list-surfaces.d.ts +21 -0
  188. package/dist/fn-context/rpc/integration/{list-bindings.js → list-surfaces.js} +4 -4
  189. package/dist/fn-context/rpc/platform.d.ts +2 -2
  190. package/dist/fn-context/rpc/platform.js +1 -1
  191. package/dist/fn-context/rpc/records.d.ts +78 -0
  192. package/dist/fn-context/rpc/records.js +26 -0
  193. package/dist/fn-context/rpc/trpc-client.d.ts +2 -2
  194. package/dist/fn-context/rpc/trpc-client.js +89 -5
  195. package/dist/fn-context/rpc/trpc-init.d.ts +2 -2
  196. package/dist/fn-context/rpc/trpc-router-factory.d.ts +49 -3
  197. package/dist/fn-context/rpc/trpc-router-factory.js +2 -0
  198. package/dist/fn-context/run-scope.d.ts +4 -0
  199. package/dist/fn-context/run-scope.js +9 -0
  200. package/dist/fn-context/types.d.ts +36 -3
  201. package/dist/index.d.ts +37 -46
  202. package/dist/index.js +33 -33
  203. package/dist/logger.d.ts +7 -0
  204. package/dist/logger.js +41 -0
  205. package/dist/platform.d.ts +76 -0
  206. package/dist/platform.js +56 -0
  207. package/dist/voice-service/actions.d.ts +71 -4
  208. package/dist/voice-service/types.d.ts +42 -2
  209. package/dist/worker.d.ts +10 -0
  210. package/dist/worker.js +10 -0
  211. package/package.json +38 -19
  212. package/dist/builder/compile/compile-agenda.d.ts +0 -15
  213. package/dist/builder/compile/compile-agenda.js +0 -59
  214. package/dist/builder/merge.d.ts +0 -4
  215. package/dist/builder/merge.js +0 -19
  216. package/dist/core/context/db.d.ts +0 -69
  217. package/dist/core/context/db.js +0 -44
  218. package/dist/core/context/docusign.d.ts +0 -134
  219. package/dist/core/context/docusign.js +0 -108
  220. package/dist/core/context/filevine.d.ts +0 -323
  221. package/dist/core/context/filevine.js +0 -254
  222. package/dist/core/context/http.d.ts +0 -9
  223. package/dist/core/context/http.js +0 -4
  224. package/dist/core/context/hubspot.d.ts +0 -250
  225. package/dist/core/context/hubspot.js +0 -191
  226. package/dist/core/context/twilio.d.ts +0 -50
  227. package/dist/core/context/twilio.js +0 -42
  228. package/dist/core/functions/define/case-context.d.ts +0 -14
  229. package/dist/core/functions/define/case-context.js +0 -15
  230. package/dist/core/functions/define/compute.d.ts +0 -7
  231. package/dist/core/functions/define/compute.js +0 -17
  232. package/dist/core/functions/define/custom.d.ts +0 -4
  233. package/dist/core/functions/define/custom.js +0 -8
  234. package/dist/core/functions/define/system.d.ts +0 -7
  235. package/dist/core/functions/define/system.js +0 -12
  236. package/dist/core/slot/deps.d.ts +0 -15
  237. package/dist/core/slot/deps.js +0 -88
  238. package/dist/core/slot/derived.d.ts +0 -32
  239. package/dist/core/slot/derived.js +0 -115
  240. package/dist/core/slot/platform-session-fields.d.ts +0 -38
  241. package/dist/core/slot/platform-session-fields.js +0 -48
  242. package/dist/core/slot/sf-schema.d.ts +0 -23
  243. package/dist/core/slot/sf-schema.js +0 -125
  244. package/dist/core/slot/sf-validate.d.ts +0 -14
  245. package/dist/core/slot/sf-validate.js +0 -132
  246. package/dist/core/slot/snapshot.d.ts +0 -18
  247. package/dist/core/slot/snapshot.js +0 -138
  248. package/dist/core/slot/write.d.ts +0 -41
  249. package/dist/core/slot/write.js +0 -319
  250. package/dist/core/stage/builders.d.ts +0 -36
  251. package/dist/core/stage/builders.js +0 -28
  252. package/dist/core/stage/condition.d.ts +0 -17
  253. package/dist/core/stage/condition.js +0 -198
  254. package/dist/core/stage/drive.d.ts +0 -43
  255. package/dist/core/stage/drive.js +0 -77
  256. package/dist/core/stage/finish-when.d.ts +0 -20
  257. package/dist/core/stage/finish-when.js +0 -82
  258. package/dist/core/stage/flatten.d.ts +0 -27
  259. package/dist/core/stage/flatten.js +0 -464
  260. package/dist/core/stage/index.d.ts +0 -11
  261. package/dist/core/stage/index.js +0 -10
  262. package/dist/core/stage/simulate.d.ts +0 -24
  263. package/dist/core/stage/simulate.js +0 -33
  264. package/dist/core/stage/transfer-fields.d.ts +0 -14
  265. package/dist/core/stage/transfer-fields.js +0 -88
  266. package/dist/core/stage/types.d.ts +0 -177
  267. package/dist/core/stage/types.js +0 -2
  268. package/dist/core/stage/validate.d.ts +0 -11
  269. package/dist/core/stage/validate.js +0 -226
  270. package/dist/core/stage/walk.d.ts +0 -34
  271. package/dist/core/stage/walk.js +0 -96
  272. package/dist/fn-context/rpc/integration/list-bindings.d.ts +0 -21
  273. package/dist/fn-context/system-args.d.ts +0 -6
  274. package/dist/fn-context/system-args.js +0 -14
@@ -0,0 +1,220 @@
1
+ /**
2
+ * What the AI may do to a page (15 §10.6.2, 17b §4): change a slot (a value, `asked_unknown` /
3
+ * `declined`, or `empty` to clear it; a `multi_select` also by adding or removing options, 27 §3.3) and
4
+ * press an action. The check that turns its operations into ones
5
+ * the platform can run — every operation resolved against the page the AI saw, invalid ones dropped one
6
+ * by one with the reason.
7
+ */
8
+ import { contactScheduleValueSchema } from '../slot/schema.js';
9
+ import { TIME_VALUE_PATTERN } from '../slot/value.js';
10
+ export function resolvePageOps(page, names, answer, allowed) {
11
+ const ops = [];
12
+ const dropped = [];
13
+ const list = Array.isArray(answer)
14
+ ? answer
15
+ : answer && typeof answer === 'object' && Array.isArray(answer.ops)
16
+ ? answer.ops
17
+ : null;
18
+ if (!list)
19
+ return { ops, dropped: answer == null ? [] : [{ op: answer, why: 'not { ops: [...] }' }] };
20
+ const slots = new Set(allowed.slots);
21
+ const actions = new Set(allowed.actions);
22
+ const opens = new Set(allowed.open);
23
+ for (const op of list) {
24
+ if (!op || typeof op !== 'object') {
25
+ dropped.push({ op, why: 'not an object' });
26
+ continue;
27
+ }
28
+ const o = op;
29
+ try {
30
+ if (typeof o.slot === 'string') {
31
+ if (!slots.has(o.slot))
32
+ throw new OpError(`slot ${o.slot} is not editable here`);
33
+ ops.push(resolveSlot(page, names, page.cells[o.slot], o));
34
+ }
35
+ else if (typeof o.action === 'string') {
36
+ if (!actions.has(o.action))
37
+ throw new OpError(`action ${o.action} is not on the page here`);
38
+ const action = page.actions[o.action];
39
+ ops.push({ kind: 'action', action, args: resolveArguments(names, action, o.arguments) });
40
+ }
41
+ else if (typeof o.open === 'string') {
42
+ if (!opens.has(o.open))
43
+ throw new OpError(`cannot open ${o.open}`);
44
+ ops.push({ kind: 'open', path: o.open, why: typeof o.why === 'string' ? o.why : '' });
45
+ }
46
+ else {
47
+ throw new OpError('neither slot, action nor open');
48
+ }
49
+ }
50
+ catch (error) {
51
+ if (!(error instanceof OpError))
52
+ throw error;
53
+ dropped.push({ op, why: error.message });
54
+ }
55
+ }
56
+ return { ops, dropped };
57
+ }
58
+ class OpError extends Error {
59
+ }
60
+ const TIME_RE = new RegExp(TIME_VALUE_PATTERN);
61
+ const STATES = new Set(['filled', 'asked_unknown', 'declined', 'empty']);
62
+ function resolveSlot(page, names, cell, o) {
63
+ const state = (o.state ?? 'filled');
64
+ if (!STATES.has(state))
65
+ throw new OpError(`${cell.slotId}: state ${state} is not filled / asked_unknown / declined / empty`);
66
+ const reason = typeof o.reason === 'string' && o.reason ? o.reason : null;
67
+ const edits = ['add', 'remove'].filter((key) => key in o);
68
+ if (edits.length && cell.type !== 'multi_select')
69
+ throw new OpError(`${cell.slotId}: ${edits.join(' / ')} is for a multi_select field; write value`);
70
+ if (state !== 'filled') {
71
+ if (edits.length)
72
+ throw new OpError(`${cell.slotId}: ${edits.join(' / ')} goes with state filled`);
73
+ return { kind: 'slot', cell, value: null, state: state, reason };
74
+ }
75
+ if (cell.type === 'multi_select')
76
+ return { kind: 'slot', cell, value: multiSelectValue(cell, o, edits), state: 'filled', reason };
77
+ if (!('value' in o) || o.value === null || o.value === undefined || o.value === '') {
78
+ throw new OpError(`${cell.slotId}: filled needs a value`);
79
+ }
80
+ let value = o.value;
81
+ if (cell.options) {
82
+ // A lookup: the AI names one of the rows on the page.
83
+ if (typeof value !== 'string' || !cell.options.includes(value)) {
84
+ throw new OpError(`${cell.slotId}: ${JSON.stringify(value)} is not one of ${cell.options.join(', ') || '(no rows on the page)'}`);
85
+ }
86
+ const row = names.resolve(value);
87
+ if (!row)
88
+ throw new OpError(`${cell.slotId}: ${value} is not a row on the page`);
89
+ value = row.id;
90
+ }
91
+ else {
92
+ value = coerce(cell.slotId, cell.type, cell.choices, value);
93
+ }
94
+ return { kind: 'slot', cell, value, state: 'filled', reason };
95
+ }
96
+ /**
97
+ * A `multi_select`'s new value (27 §3.3): `value` replaces the list, `add` / `remove` change the one
98
+ * the AI saw on the page and keep the rest. In the options' order, each once.
99
+ */
100
+ function multiSelectValue(cell, o, edits) {
101
+ const choices = cell.choices ?? [];
102
+ const given = edits.length ? edits : ['value'];
103
+ if (given.length + (edits.length && 'value' in o ? 1 : 0) > 1)
104
+ throw new OpError(`${cell.slotId}: one of value, add or remove at a time`);
105
+ const key = given[0];
106
+ const raw = o[key];
107
+ if (raw === null || raw === undefined)
108
+ throw new OpError(`${cell.slotId}: filled needs ${key}`);
109
+ // One option alone is taken as a list of one.
110
+ const list = Array.isArray(raw) ? raw : [raw];
111
+ const outside = list.filter((item) => typeof item !== 'string' || !choices.includes(item));
112
+ if (outside.length) {
113
+ throw new OpError(`${cell.slotId}: ${outside.map((v) => JSON.stringify(v)).join(', ')} not one of ${choices.map((v) => JSON.stringify(v)).join(', ')}`);
114
+ }
115
+ const now = cell.state === 'filled' && Array.isArray(cell.value) ? cell.value : [];
116
+ const next = new Set(key === 'value' ? list : now);
117
+ if (key === 'add')
118
+ for (const item of list)
119
+ next.add(item);
120
+ if (key === 'remove')
121
+ for (const item of list)
122
+ next.delete(item);
123
+ return choices.filter((choice) => next.has(choice));
124
+ }
125
+ function resolveArguments(names, action, raw) {
126
+ if (!action.input) {
127
+ if (raw && typeof raw === 'object' && Object.keys(raw).length)
128
+ throw new OpError(`${action.id}: takes no arguments`);
129
+ return {};
130
+ }
131
+ return resolveObject(names, action.id, action.input.properties, action.input.required, raw ?? {});
132
+ }
133
+ function resolveObject(names, where, properties, required, raw) {
134
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw))
135
+ throw new OpError(`${where}: arguments must be an object`);
136
+ const out = {};
137
+ for (const [key, value] of Object.entries(raw)) {
138
+ const prop = properties[key];
139
+ if (!prop)
140
+ throw new OpError(`${where}: ${key} is not an argument here`);
141
+ if (value === null || value === undefined || value === '')
142
+ continue;
143
+ out[key] = resolveValue(names, `${where}.${key}`, prop, value);
144
+ }
145
+ for (const key of required ?? []) {
146
+ if (!(key in out))
147
+ throw new OpError(`${where}: ${key} is required`);
148
+ }
149
+ return out;
150
+ }
151
+ function resolveValue(names, where, prop, value) {
152
+ if (prop.type === 'array') {
153
+ if (!Array.isArray(value))
154
+ throw new OpError(`${where}: must be a list`);
155
+ return value.map((item, i) => resolveValue(names, `${where}[${i}]`, prop.items, item));
156
+ }
157
+ if (prop.type === 'object' && prop['x-type'] === 'contact_schedule') {
158
+ // Checked as the field checks it; `run` gets the schedule as it is.
159
+ const parsed = contactScheduleValueSchema.safeParse(value);
160
+ if (parsed.success)
161
+ return value;
162
+ const issue = parsed.error.issues[0];
163
+ throw new OpError(`${where}: not a contact schedule (${issue.path.join('.') || 'value'}: ${issue.message})`);
164
+ }
165
+ if (prop.type === 'object')
166
+ return resolveObject(names, where, prop.properties, prop.required, value);
167
+ if (prop.type === 'ref') {
168
+ // A row choice: one of the rows on the page, by page name; `run` gets its id.
169
+ const row = typeof value === 'string' && prop.enum.includes(value) ? names.resolve(value) : undefined;
170
+ if (!row)
171
+ throw new OpError(`${where}: must be one of ${prop.enum.join(', ') || '(no rows on the page)'}`);
172
+ return row.id;
173
+ }
174
+ if (prop.type === 'multi_select') {
175
+ // As a fill writes it: one option alone is a list of one; each once, in the options' order.
176
+ const list = Array.isArray(value) ? value : [value];
177
+ const outside = list.filter((item) => !prop.enum.includes(item));
178
+ if (outside.length)
179
+ throw new OpError(`${where}: ${outside.map((v) => JSON.stringify(v)).join(', ')} not one of ${prop.enum.map((v) => JSON.stringify(v)).join(', ')}`);
180
+ return prop.enum.filter((option) => list.includes(option));
181
+ }
182
+ // A schema field's argument is checked as a fill of the field is.
183
+ return coerce(where, prop.type === 'integer' ? 'number' : prop.type, prop.enum ?? null, value);
184
+ }
185
+ function coerce(where, type, enumValues, value) {
186
+ let out = value;
187
+ if (type === 'number') {
188
+ out = typeof value === 'string' && value.trim() !== '' && Number.isFinite(Number(value)) ? Number(value) : value;
189
+ if (typeof out !== 'number' || !Number.isFinite(out))
190
+ throw new OpError(`${where}: ${JSON.stringify(value)} is not a number`);
191
+ }
192
+ else if (type === 'boolean') {
193
+ out = value === 'true' ? true : value === 'false' ? false : value;
194
+ if (typeof out !== 'boolean')
195
+ throw new OpError(`${where}: ${JSON.stringify(value)} is not true / false`);
196
+ }
197
+ else if (type === 'date') {
198
+ if (typeof value !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(value))
199
+ throw new OpError(`${where}: ${JSON.stringify(value)} is not YYYY-MM-DD`);
200
+ }
201
+ else if (type === 'datetime') {
202
+ if (typeof value !== 'string' || Number.isNaN(Date.parse(value)))
203
+ throw new OpError(`${where}: ${JSON.stringify(value)} is not a date-time`);
204
+ }
205
+ else if (type === 'time') {
206
+ if (typeof value !== 'string' || !TIME_RE.test(value))
207
+ throw new OpError(`${where}: ${JSON.stringify(value)} is not a time of day HH:mm, 24-hour (15:30)`);
208
+ }
209
+ else if (type === 'string' || type === 'select' || type === 'text' || type === 'phone' || type === 'email') {
210
+ if (typeof value === 'number' || typeof value === 'boolean')
211
+ out = String(value);
212
+ if (typeof out !== 'string')
213
+ throw new OpError(`${where}: ${JSON.stringify(value)} is not text`);
214
+ }
215
+ if (enumValues && !enumValues.includes(out)) {
216
+ throw new OpError(`${where}: ${JSON.stringify(value)} is not one of ${enumValues.map((v) => JSON.stringify(v)).join(', ')}`);
217
+ }
218
+ return out;
219
+ }
220
+ //# sourceMappingURL=ops.js.map
@@ -0,0 +1,253 @@
1
+ import type { CompiledSlotSchema, RuntimeFieldDef } from '../slot/types.js';
2
+ import type { ChannelAction, PageAction, PageChannel, SlotRef, SlotState } from './define.js';
3
+ /**
4
+ * `table#n` for each row a conversation has seen: the same row keeps its name on every page of the
5
+ * conversation; names only grow and are never reused, so a late output naming a deleted row's name
6
+ * cannot reach another row. Serialisable (`toJSON` / `fromJSON`) so a session can keep it.
7
+ */
8
+ export declare class RowNames {
9
+ private readonly byId;
10
+ private readonly byName;
11
+ private readonly counters;
12
+ name(table: string, id: string): string;
13
+ resolve(name: string): {
14
+ table: string;
15
+ id: string;
16
+ } | undefined;
17
+ nameOf(id: string): string | undefined;
18
+ toJSON(): Array<[string, string, string]>;
19
+ static fromJSON(entries: Array<[string, string, string]>): RowNames;
20
+ }
21
+ export type ReadSlot = {
22
+ value: unknown;
23
+ state: SlotState;
24
+ reason: string | null;
25
+ updatedAt: string | null;
26
+ };
27
+ export type PageReads = {
28
+ /** A row this run read, with its true slots; undefined when it was not read. */
29
+ row(id: string): {
30
+ table: string;
31
+ slots: Record<string, ReadSlot>;
32
+ } | undefined;
33
+ /** The ids new rows of `table` would hang under, from the parent conditions of this run's reads. */
34
+ parentsOf(table: string): readonly string[];
35
+ };
36
+ /** A block. Only the root has `guide` (24 §2.1): what to do now and how, the page's words. */
37
+ export type BlockNode = {
38
+ kind: 'block';
39
+ key: string;
40
+ path: string;
41
+ title?: string;
42
+ description?: string;
43
+ list: boolean;
44
+ children: PageNode[];
45
+ guide?: string;
46
+ };
47
+ export type PageNode = BlockNode
48
+ /** `expand`: shown with its definition (24 §2.2). */
49
+ | {
50
+ kind: 'cell';
51
+ key: string;
52
+ path: string;
53
+ slotId: string;
54
+ readOnly: boolean;
55
+ expand?: boolean;
56
+ } | {
57
+ kind: 'text';
58
+ key: string;
59
+ path: string;
60
+ value: string | number | boolean | null;
61
+ } | {
62
+ kind: 'action';
63
+ key: string;
64
+ path: string;
65
+ actionId: string;
66
+ };
67
+ export type RenderedCell = {
68
+ slotId: string;
69
+ ref: SlotRef;
70
+ /** The row's page name, `table#n`. */
71
+ row: string;
72
+ label: string;
73
+ description?: string;
74
+ /** The schema's; the page's `$extraction` for its `table.field` replaces it (`RenderedPage.extractions`). */
75
+ extraction?: string;
76
+ /** The field's type; `ref` for a lookup (26 §16.2 #7), as a row argument's. */
77
+ type: RuntimeFieldDef['dataType'] | 'ref';
78
+ /** A `select` / `multi_select` field's options; null on every other type. */
79
+ choices: string[] | null;
80
+ /** For a lookup (`refField`): the rows the page offers, by page name, in its order. */
81
+ options?: string[];
82
+ /** For a lookup: what the AI sees of each row the page offered, by page name (26 §16.2 #7). */
83
+ optionLabels?: Record<string, string>;
84
+ value: unknown;
85
+ state: SlotState;
86
+ reason: string | null;
87
+ updatedAt: string | null;
88
+ /** Writable in at least one place on the page (schema allows, page did not tighten everywhere). */
89
+ writable: boolean;
90
+ paths: string[];
91
+ };
92
+ /**
93
+ * A field type a `schemaField` argument keeps, named as the field's definition names it and checked as a
94
+ * fill of the field is (`string`, `number` and `boolean` are the plain ones below).
95
+ */
96
+ export type FieldArgType = 'text' | 'phone' | 'email' | 'date' | 'datetime' | 'time' | 'select';
97
+ /**
98
+ * One argument as the AI fills it. Never sent to a model as a schema: the page shows it as `<arg>` and
99
+ * the platform checks what the AI passed against it. A `schemaField` argument has its field's type
100
+ * (26 §15.8: the same names as a field's definition); a row choice is `ref`, its `enum` the rows' page
101
+ * names, and the platform hands `run` the row's id. The rest is plain JSON Schema, as the action wrote it.
102
+ */
103
+ export type InputProperty = {
104
+ type: 'string';
105
+ description?: string;
106
+ enum?: Array<string | number>;
107
+ } | {
108
+ type: 'number' | 'integer' | 'boolean';
109
+ description?: string;
110
+ enum?: Array<string | number>;
111
+ } | {
112
+ type: FieldArgType;
113
+ description?: string;
114
+ enum?: string[];
115
+ } | {
116
+ type: 'multi_select';
117
+ enum: string[];
118
+ description?: string;
119
+ } | {
120
+ type: 'ref';
121
+ table: string;
122
+ enum: string[];
123
+ description?: string; /** What the AI sees of each row (`choose`), by page name. */
124
+ labels?: Record<string, string>;
125
+ } | {
126
+ type: 'array';
127
+ items: InputProperty;
128
+ description?: string;
129
+ } | {
130
+ type: 'object';
131
+ properties: Record<string, InputProperty>;
132
+ required?: string[];
133
+ description?: string;
134
+ /** May also be null. */
135
+ nullable?: true;
136
+ /** A field value with its own checks: the argument is validated as one (`contact_schedule`). */
137
+ 'x-type'?: 'contact_schedule';
138
+ };
139
+ export type InputSchema = {
140
+ type: 'object';
141
+ properties: Record<string, InputProperty>;
142
+ required: string[];
143
+ };
144
+ export type RenderedAction = {
145
+ id: string;
146
+ kind: PageAction['$action'];
147
+ name: string;
148
+ description: string;
149
+ /** JSON Schema of the arguments the AI fills (prefilled ones left out); null: nothing to fill. */
150
+ input: InputSchema | null;
151
+ /** Server-only: what running it needs. Never shown to the AI. */
152
+ server: {
153
+ kind: 'createRow';
154
+ table: string;
155
+ parentId: string | null;
156
+ set: Record<string, unknown>;
157
+ fields: string[];
158
+ required: string[];
159
+ } | {
160
+ kind: 'deleteRow';
161
+ table: string;
162
+ rowId: string;
163
+ reason?: string;
164
+ } | {
165
+ kind: 'custom';
166
+ name: string;
167
+ prefill: Record<string, unknown>;
168
+ } | {
169
+ kind: 'channel';
170
+ spec: ChannelAction;
171
+ }
172
+ /** A text or an email sent now (25 §8); `to` the contact (null: the conversation's). */
173
+ | {
174
+ kind: 'message';
175
+ channel: 'sms' | 'email';
176
+ key: string;
177
+ to: string | null;
178
+ body?: string;
179
+ subject?: string;
180
+ say?: string;
181
+ }
182
+ /** Book what the customer asked for, as an agreed follow-up (25 §5), on one of `channels`. */
183
+ | {
184
+ kind: 'followUp';
185
+ key: string;
186
+ channels: Array<'call' | 'sms' | 'email'>;
187
+ }
188
+ /** A company function (20 §6.2): run on the Worker by the platform, waited for, with the page's prefilled arguments. */
189
+ | {
190
+ kind: 'function';
191
+ name: string;
192
+ say?: string;
193
+ prefill?: Record<string, unknown>;
194
+ };
195
+ };
196
+ /**
197
+ * The page function returned an action to run now instead of a page (17b §9.8): `action` is rendered
198
+ * as a button would be (its rows checked), `key` names its runs.
199
+ */
200
+ export type AutoAction = {
201
+ action: RenderedAction;
202
+ key: string;
203
+ wait: boolean;
204
+ };
205
+ export type RenderedPage = {
206
+ root: BlockNode;
207
+ /** Set when the page function returned an action to run now: the page then has nothing else. */
208
+ auto?: AutoAction;
209
+ cells: Record<string, RenderedCell>;
210
+ actions: Record<string, RenderedAction>;
211
+ /**
212
+ * Set on a stand-in page when the page script failed (15 §10.9): the last good page marked stale and
213
+ * read-only, or an empty page. Nothing on it can be written, and it has no actions.
214
+ */
215
+ fallback?: {
216
+ reason: string;
217
+ stale: boolean;
218
+ };
219
+ /** Every row on the page, by page name; `parentId` is its parent. */
220
+ rows: Record<string, {
221
+ table: string;
222
+ id: string;
223
+ parentId: string | null;
224
+ }>;
225
+ /** The page's `$extraction` (26 §15.3): how to fill a field on this page, by `table.field`; replaces the schema's. */
226
+ extractions?: Record<string, string>;
227
+ warnings: string[];
228
+ };
229
+ export declare class PageDocumentError extends Error {
230
+ constructor(message: string);
231
+ }
232
+ export type RenderDocumentInput = {
233
+ document: unknown;
234
+ schema: CompiledSlotSchema;
235
+ reads: PageReads;
236
+ names: RowNames;
237
+ /** The conversation's channel: a button the channel cannot do (a transfer by text) is an error (20 §5.2). */
238
+ channel?: PageChannel;
239
+ };
240
+ export declare function renderDocument(input: RenderDocumentInput): RenderedPage;
241
+ /**
242
+ * The run key of a button on the page (17b §7): the action's own key, whoever runs it — the model
243
+ * pressing it, or the page function returning it — not its place on the page, which moves with rows.
244
+ */
245
+ export declare function runKeyOf(action: RenderedAction): string;
246
+ /** The run key of an action the page function returned, when it names none. */
247
+ export declare function actionKey(action: PageAction): string;
248
+ /**
249
+ * The page to show when the page script failed (15 §10.9): the last good page, every cell read-only
250
+ * and no actions, marked stale; without one, an empty page.
251
+ */
252
+ export declare function fallbackPage(last: RenderedPage | null, reason: string): RenderedPage;
253
+ //# sourceMappingURL=render.d.ts.map