@superpanel-sdk/runtime 0.2.3 → 0.7.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.
- package/README.md +30 -10
- package/dist/builder/codegen/emit.d.ts +25 -12
- package/dist/builder/codegen/emit.js +339 -78
- package/dist/builder/codegen/generate.d.ts +21 -2
- package/dist/builder/codegen/generate.js +147 -34
- package/dist/builder/company-import-graph.d.ts +2 -0
- package/dist/builder/company-import-graph.js +40 -8
- package/dist/builder/company-imports.d.ts +29 -0
- package/dist/builder/company-imports.js +122 -0
- package/dist/builder/compile/compile-sequence.d.ts +61 -8
- package/dist/builder/compile/compile-sequence.js +334 -80
- package/dist/builder/compile/function-code.d.ts +19 -3
- package/dist/builder/compile/function-code.js +123 -45
- package/dist/builder/compile/registry.d.ts +7 -3
- package/dist/builder/compile/registry.js +30 -27
- package/dist/builder/errors.d.ts +9 -0
- package/dist/builder/errors.js +17 -0
- package/dist/builder/function-params.d.ts +10 -0
- package/dist/builder/function-params.js +203 -0
- package/dist/builder/load.d.ts +70 -10
- package/dist/builder/load.js +258 -67
- package/dist/builder/paths.d.ts +9 -1
- package/dist/builder/paths.js +32 -2
- package/dist/builder/schedules.d.ts +25 -0
- package/dist/builder/schedules.js +101 -0
- package/dist/builder/slot-schema-validation.d.ts +4 -0
- package/dist/builder/slot-schema-validation.js +10 -0
- package/dist/builder/typecheck.d.ts +8 -0
- package/dist/builder/typecheck.js +102 -0
- package/dist/builder/types.d.ts +127 -19
- package/dist/builder/types.js +21 -1
- package/dist/cli/auth/auth.d.ts +37 -0
- package/dist/cli/auth/auth.js +211 -0
- package/dist/cli/auth/backend-url.d.ts +5 -0
- package/dist/cli/auth/backend-url.js +25 -0
- package/dist/cli/auth/clipboard.d.ts +9 -0
- package/dist/cli/auth/clipboard.js +38 -0
- package/dist/cli/auth/http.d.ts +20 -0
- package/dist/cli/auth/http.js +27 -0
- package/dist/cli/auth/index.d.ts +10 -0
- package/dist/cli/auth/index.js +27 -0
- package/dist/cli/auth/progress.d.ts +12 -0
- package/dist/cli/auth/progress.js +15 -0
- package/dist/cli/auth/serve-login.d.ts +8 -0
- package/dist/cli/auth/serve-login.js +24 -0
- package/dist/cli/calls/index.d.ts +177 -0
- package/dist/cli/calls/index.js +96 -0
- package/dist/cli/compile/index.js +3 -0
- package/dist/cli/config.d.ts +10 -0
- package/dist/cli/config.js +52 -0
- package/dist/cli/debug/index.d.ts +31 -0
- package/dist/cli/debug/index.js +119 -0
- package/dist/cli/exec/index.d.ts +39 -0
- package/dist/cli/exec/index.js +138 -0
- package/dist/cli/exec/session.d.ts +48 -0
- package/dist/cli/exec/session.js +82 -0
- package/dist/cli/exec/trace.d.ts +18 -0
- package/dist/cli/exec/trace.js +52 -0
- package/dist/cli/index.js +112 -9
- package/dist/cli/logs/index.d.ts +47 -0
- package/dist/cli/logs/index.js +113 -0
- package/dist/cli/mobile/index.d.ts +12 -0
- package/dist/cli/mobile/index.js +405 -0
- package/dist/cli/serve/index.d.ts +109 -3
- package/dist/cli/serve/index.js +506 -118
- package/dist/cli/turns/index.d.ts +105 -0
- package/dist/cli/turns/index.js +128 -0
- package/dist/cli/turns/run.d.ts +13 -0
- package/dist/cli/turns/run.js +57 -0
- package/dist/cli/turns/shadow.d.ts +112 -0
- package/dist/cli/turns/shadow.js +54 -0
- package/dist/cli/type-gen/index.js +9 -9
- package/dist/compiler.d.ts +7 -0
- package/dist/compiler.js +7 -0
- package/dist/compute-host/compute-host.d.ts +14 -23
- package/dist/compute-host/compute-host.js +18 -30
- package/dist/compute-host/index.d.ts +2 -4
- package/dist/compute-host/index.js +1 -2
- package/dist/compute-host/source-compute-host.d.ts +10 -10
- package/dist/compute-host/source-compute-host.js +33 -40
- package/dist/core/case-orchestrator/contact-hours.d.ts +70 -0
- package/dist/core/case-orchestrator/contact-hours.js +127 -0
- package/dist/core/case-orchestrator/index.d.ts +3 -0
- package/dist/core/case-orchestrator/index.js +3 -0
- package/dist/core/case-orchestrator/render.d.ts +75 -0
- package/dist/core/case-orchestrator/render.js +244 -0
- package/dist/core/case-orchestrator/time.d.ts +11 -0
- package/dist/core/case-orchestrator/time.js +29 -0
- package/dist/core/case-orchestrator/types.d.ts +708 -0
- package/dist/core/case-orchestrator/types.js +42 -0
- package/dist/core/context/call.d.ts +291 -0
- package/dist/core/context/call.js +94 -0
- package/dist/core/context/channels.d.ts +60 -0
- package/dist/core/context/channels.js +35 -0
- package/dist/core/context/contact.d.ts +96 -6
- package/dist/core/context/contact.js +48 -2
- package/dist/core/context/email-message.d.ts +198 -0
- package/dist/core/context/email-message.js +86 -0
- package/dist/core/context/email.d.ts +109 -0
- package/dist/core/context/email.js +90 -0
- package/dist/core/context/exchanges.d.ts +167 -0
- package/dist/core/context/exchanges.js +81 -0
- package/dist/core/context/instances.d.ts +307 -0
- package/dist/core/context/instances.js +137 -0
- package/dist/core/context/kv.d.ts +113 -0
- package/dist/core/context/kv.js +60 -0
- package/dist/core/context/platform-registry.d.ts +544 -4
- package/dist/core/context/platform-registry.js +14 -2
- package/dist/core/context/platform.d.ts +2 -1
- package/dist/core/context/sms.d.ts +177 -0
- package/dist/core/context/sms.js +77 -0
- package/dist/core/context/types.d.ts +79 -48
- package/dist/core/context/types.js +1 -7
- package/dist/core/conversation/index.d.ts +85 -0
- package/dist/core/conversation/index.js +133 -0
- package/dist/core/functions/errors.d.ts +74 -0
- package/dist/core/functions/errors.js +26 -0
- package/dist/core/functions/events.d.ts +192 -0
- package/dist/core/functions/events.js +23 -0
- package/dist/core/functions/schedules.d.ts +50 -0
- package/dist/core/functions/schedules.js +20 -0
- package/dist/core/functions/types.d.ts +29 -73
- package/dist/core/functions/types.js +1 -4
- package/dist/core/office-hours/index.d.ts +39 -0
- package/dist/core/office-hours/index.js +187 -0
- package/dist/core/page/define.d.ts +904 -0
- package/dist/core/page/define.js +518 -0
- package/dist/core/page/envelope.d.ts +55 -0
- package/dist/core/page/envelope.js +4 -0
- package/dist/core/page/fns.d.ts +448 -0
- package/dist/core/page/fns.js +539 -0
- package/dist/core/page/memory-reader.d.ts +27 -0
- package/dist/core/page/memory-reader.js +299 -0
- package/dist/core/page/ops.d.ts +58 -0
- package/dist/core/page/ops.js +220 -0
- package/dist/core/page/page-host.d.ts +20 -0
- package/dist/core/page/page-host.js +57 -0
- package/dist/core/page/records-query.d.ts +234 -0
- package/dist/core/page/records-query.js +780 -0
- package/dist/core/page/render.d.ts +295 -0
- package/dist/core/page/render.js +1060 -0
- package/dist/core/page/sandbox.d.ts +85 -0
- package/dist/core/page/sandbox.js +357 -0
- package/dist/core/page/time-format.d.ts +46 -0
- package/dist/core/page/time-format.js +125 -0
- package/dist/core/page/timeline.d.ts +40 -0
- package/dist/core/page/timeline.js +2 -0
- package/dist/core/page/typed.d.ts +648 -0
- package/dist/core/page/typed.js +2 -0
- package/dist/core/page/workspace.d.ts +57 -0
- package/dist/core/page/workspace.js +266 -0
- package/dist/core/party/index.d.ts +3 -0
- package/dist/core/party/index.js +3 -0
- package/dist/core/party/schema.d.ts +208 -0
- package/dist/core/party/schema.js +113 -0
- package/dist/core/party/types.d.ts +35 -0
- package/dist/core/party/types.js +15 -0
- package/dist/core/sequence/define.d.ts +56 -0
- package/dist/core/sequence/define.js +10 -0
- package/dist/core/sequence/index.d.ts +63 -0
- package/dist/core/sequence/index.js +231 -0
- package/dist/core/slot/binding.d.ts +40 -0
- package/dist/core/slot/binding.js +2 -0
- package/dist/core/slot/company-metadata.d.ts +102 -0
- package/dist/core/slot/company-metadata.js +536 -0
- package/dist/core/slot/compile-schema.d.ts +19 -13
- package/dist/core/slot/compile-schema.js +51 -248
- package/dist/core/slot/contact-timezone.d.ts +110 -0
- package/dist/core/slot/contact-timezone.js +186 -0
- package/dist/core/slot/field.d.ts +2 -25
- package/dist/core/slot/field.js +0 -71
- package/dist/core/slot/id-ref.d.ts +17 -2
- package/dist/core/slot/id-ref.js +16 -8
- package/dist/core/slot/index.d.ts +12 -13
- package/dist/core/slot/index.js +11 -12
- package/dist/core/slot/naming.d.ts +15 -0
- package/dist/core/slot/naming.js +96 -0
- package/dist/core/slot/platform-fields.d.ts +119 -0
- package/dist/core/slot/platform-fields.js +121 -0
- package/dist/core/slot/ref.d.ts +16 -0
- package/dist/core/slot/ref.js +14 -0
- package/dist/core/slot/row.d.ts +2 -9
- package/dist/core/slot/row.js +13 -23
- package/dist/core/slot/schema-compat.d.ts +17 -0
- package/dist/core/slot/schema-compat.js +103 -0
- package/dist/core/slot/schema.d.ts +353 -76
- package/dist/core/slot/schema.js +163 -10
- package/dist/core/slot/types.d.ts +30 -103
- package/dist/core/slot/value.d.ts +28 -3
- package/dist/core/slot/value.js +93 -57
- package/dist/dev-overlay/protocol.d.ts +74 -8
- package/dist/fn-context/build-context.d.ts +3 -1
- package/dist/fn-context/build-context.js +26 -10
- package/dist/fn-context/fake/empty-api.js +9 -28
- package/dist/fn-context/fake/index.d.ts +13 -4
- package/dist/fn-context/fake/index.js +29 -2
- package/dist/fn-context/fn-params.d.ts +3 -0
- package/dist/fn-context/fn-params.js +10 -0
- package/dist/fn-context/index.d.ts +5 -5
- package/dist/fn-context/index.js +4 -4
- package/dist/fn-context/log.js +2 -2
- package/dist/fn-context/make-ctx.d.ts +11 -0
- package/dist/fn-context/make-ctx.js +20 -9
- package/dist/fn-context/rpc/case-orchestrator-tools.d.ts +32 -0
- package/dist/fn-context/rpc/case-orchestrator-tools.js +12 -0
- package/dist/fn-context/rpc/errors.d.ts +13 -0
- package/dist/fn-context/rpc/errors.js +22 -0
- package/dist/fn-context/rpc/index.d.ts +4 -2
- package/dist/fn-context/rpc/index.js +4 -2
- package/dist/fn-context/rpc/integration/index.d.ts +15 -5
- package/dist/fn-context/rpc/integration/index.js +1 -1
- package/dist/fn-context/rpc/integration/list-surfaces.d.ts +21 -0
- package/dist/fn-context/rpc/integration/{list-bindings.js → list-surfaces.js} +4 -4
- package/dist/fn-context/rpc/log.d.ts +11 -1
- package/dist/fn-context/rpc/platform.d.ts +13 -3
- package/dist/fn-context/rpc/platform.js +1 -1
- package/dist/fn-context/rpc/records.d.ts +85 -0
- package/dist/fn-context/rpc/records.js +24 -0
- package/dist/fn-context/rpc/trpc-client.d.ts +44 -2
- package/dist/fn-context/rpc/trpc-client.js +222 -12
- package/dist/fn-context/rpc/trpc-init.d.ts +21 -3
- package/dist/fn-context/rpc/trpc-init.js +10 -4
- package/dist/fn-context/rpc/trpc-router-factory.d.ts +111 -7
- package/dist/fn-context/rpc/trpc-router-factory.js +2 -0
- package/dist/fn-context/run-scope.d.ts +4 -0
- package/dist/fn-context/run-scope.js +9 -0
- package/dist/fn-context/types.d.ts +52 -5
- package/dist/index.d.ts +36 -46
- package/dist/index.js +30 -33
- package/dist/logger.d.ts +11 -0
- package/dist/logger.js +49 -0
- package/dist/platform.d.ts +75 -0
- package/dist/platform.js +57 -0
- package/dist/testing-compile-child.d.ts +2 -0
- package/dist/testing-compile-child.js +20 -0
- package/dist/testing.d.ts +368 -0
- package/dist/testing.js +439 -0
- package/dist/voice-service/actions.d.ts +50 -6
- package/dist/voice-service/index.d.ts +2 -0
- package/dist/voice-service/index.js +2 -0
- package/dist/voice-service/protocol.d.ts +604 -0
- package/dist/voice-service/protocol.js +67 -0
- package/dist/voice-service/types.d.ts +55 -8
- package/dist/worker.d.ts +11 -0
- package/dist/worker.js +11 -0
- package/package.json +38 -15
- package/dist/builder/compile/compile-agenda.d.ts +0 -15
- package/dist/builder/compile/compile-agenda.js +0 -64
- package/dist/builder/merge.d.ts +0 -4
- package/dist/builder/merge.js +0 -19
- package/dist/compute-host/read-only-cache.d.ts +0 -20
- package/dist/compute-host/read-only-cache.js +0 -61
- package/dist/core/context/db.d.ts +0 -69
- package/dist/core/context/db.js +0 -44
- package/dist/core/context/docusign.d.ts +0 -134
- package/dist/core/context/docusign.js +0 -108
- package/dist/core/context/filevine.d.ts +0 -323
- package/dist/core/context/filevine.js +0 -254
- package/dist/core/context/http.d.ts +0 -9
- package/dist/core/context/http.js +0 -4
- package/dist/core/context/hubspot.d.ts +0 -250
- package/dist/core/context/hubspot.js +0 -191
- package/dist/core/context/twilio.d.ts +0 -50
- package/dist/core/context/twilio.js +0 -42
- package/dist/core/functions/define/case-context.d.ts +0 -14
- package/dist/core/functions/define/case-context.js +0 -15
- package/dist/core/functions/define/compute.d.ts +0 -7
- package/dist/core/functions/define/compute.js +0 -17
- package/dist/core/functions/define/custom.d.ts +0 -4
- package/dist/core/functions/define/custom.js +0 -8
- package/dist/core/functions/define/system.d.ts +0 -7
- package/dist/core/functions/define/system.js +0 -12
- package/dist/core/functions/func-ref.d.ts +0 -16
- package/dist/core/functions/func-ref.js +0 -20
- package/dist/core/slot/deps.d.ts +0 -15
- package/dist/core/slot/deps.js +0 -88
- package/dist/core/slot/derived.d.ts +0 -32
- package/dist/core/slot/derived.js +0 -115
- package/dist/core/slot/platform-session-fields.d.ts +0 -38
- package/dist/core/slot/platform-session-fields.js +0 -48
- package/dist/core/slot/sf-schema.d.ts +0 -23
- package/dist/core/slot/sf-schema.js +0 -125
- package/dist/core/slot/sf-validate.d.ts +0 -14
- package/dist/core/slot/sf-validate.js +0 -132
- package/dist/core/slot/snapshot.d.ts +0 -18
- package/dist/core/slot/snapshot.js +0 -138
- package/dist/core/slot/write.d.ts +0 -48
- package/dist/core/slot/write.js +0 -426
- package/dist/core/stage/builders.d.ts +0 -54
- package/dist/core/stage/builders.js +0 -31
- package/dist/core/stage/condition.d.ts +0 -17
- package/dist/core/stage/condition.js +0 -198
- package/dist/core/stage/drive.d.ts +0 -43
- package/dist/core/stage/drive.js +0 -78
- package/dist/core/stage/finish-when.d.ts +0 -20
- package/dist/core/stage/finish-when.js +0 -82
- package/dist/core/stage/flatten.d.ts +0 -27
- package/dist/core/stage/flatten.js +0 -466
- package/dist/core/stage/index.d.ts +0 -15
- package/dist/core/stage/index.js +0 -13
- package/dist/core/stage/interrupts.d.ts +0 -28
- package/dist/core/stage/interrupts.js +0 -120
- package/dist/core/stage/ivr-fields.d.ts +0 -9
- package/dist/core/stage/ivr-fields.js +0 -75
- package/dist/core/stage/simulate.d.ts +0 -24
- package/dist/core/stage/simulate.js +0 -33
- package/dist/core/stage/transfer-fields.d.ts +0 -19
- package/dist/core/stage/transfer-fields.js +0 -129
- package/dist/core/stage/transfer-spec.d.ts +0 -48
- package/dist/core/stage/transfer-spec.js +0 -113
- package/dist/core/stage/types.d.ts +0 -208
- package/dist/core/stage/types.js +0 -2
- package/dist/core/stage/validate.d.ts +0 -11
- package/dist/core/stage/validate.js +0 -330
- package/dist/core/stage/walk.d.ts +0 -39
- package/dist/core/stage/walk.js +0 -119
- package/dist/fn-context/rpc/integration/list-bindings.d.ts +0 -21
- package/dist/fn-context/system-args.d.ts +0 -6
- package/dist/fn-context/system-args.js +0 -14
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the AI reads of a page (24 §3, 26 §15.5): one layer, the whole page, like a rep's screen. The
|
|
3
|
+
* page decides what is on it; the platform works out nothing from it. Everything is an element; every
|
|
4
|
+
* attribute value is JSON (strings "…" with \" and \n, numbers, true/false, null, lists); free text is
|
|
5
|
+
* always a `value` attribute; flush left.
|
|
6
|
+
*
|
|
7
|
+
* <notes><note id about value/></notes> the model's own reminders (17b §8), first, all of them
|
|
8
|
+
* <next-step channel id name to at reason customer-quote booked-in/> the platform's, before the page
|
|
9
|
+
* (40 §2.2, 51 §2): the case's pending contacts, whatever the page
|
|
10
|
+
* shows; `value` "none" when nothing is booked
|
|
11
|
+
* <guide value/> the page's `$guide`: what to do now and how
|
|
12
|
+
* <page title description fallback> the page:
|
|
13
|
+
* <definitions> once for the page, a definition per `table.field` some field
|
|
14
|
+
* <definition for label type …/> on it shows expanded (`field(slot, { expand: true })`)
|
|
15
|
+
* <block key title description> a part of the page; inside a list, without `key`
|
|
16
|
+
* <list key title description> several things of one kind (an array on the page)
|
|
17
|
+
* <field id key readonly more type value value-label one-of state reason/> one value; `more`: its
|
|
18
|
+
* definition is not shown (its type is); a ref's one-of: its rows
|
|
19
|
+
* <text key value/> read-only text
|
|
20
|
+
* <button id title does><arg …/></button>
|
|
21
|
+
* Now: 2026-11-11T20:05Z the platform's, the last line (76 §2.19): the time now, in UTC,
|
|
22
|
+
* to the minute; the only time the AI is given as "now"
|
|
23
|
+
*/
|
|
24
|
+
import type { PageNextStep } from './define.js';
|
|
25
|
+
import type { BlockNode, RenderedPage } from './render.js';
|
|
26
|
+
export type WorkspaceNote = {
|
|
27
|
+
id: string;
|
|
28
|
+
text: string;
|
|
29
|
+
about?: string;
|
|
30
|
+
};
|
|
31
|
+
export type WorkspaceTextOptions = {
|
|
32
|
+
notes?: readonly WorkspaceNote[];
|
|
33
|
+
/**
|
|
34
|
+
* The case's next step (40 §2.2), shown before the page whatever the page shows: the AI knows what is
|
|
35
|
+
* booked before it reads the page. Times in `timeZone` (the contact's). Left out: no conversation (nothing is shown).
|
|
36
|
+
*/
|
|
37
|
+
nextSteps?: {
|
|
38
|
+
steps: readonly PageNextStep[];
|
|
39
|
+
timeZone: string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* The time now (76 §2.19): the page's last line, `Now: 2026-11-11T20:05Z`, in UTC, never the contact's
|
|
43
|
+
* zone. Every engine that shows the AI a page gives it; left out: no such line.
|
|
44
|
+
*/
|
|
45
|
+
now?: Date;
|
|
46
|
+
};
|
|
47
|
+
export declare function workspaceText(page: RenderedPage, options?: WorkspaceTextOptions): string;
|
|
48
|
+
/** The last line of every page the AI reads (76 §2.19): the time now in UTC, to the minute (`Now: 2026-11-11T20:05Z`). */
|
|
49
|
+
export declare function nowLine(now: Date): string;
|
|
50
|
+
/** Stable, short appointment handle; the service resolves it within the authorized case, rejecting ambiguity. */
|
|
51
|
+
export declare function nextStepReference(id: string): string;
|
|
52
|
+
export declare function nextStepLines(steps: readonly PageNextStep[], timeZone: string): string[];
|
|
53
|
+
/** The block at `path` (`''`: the root). */
|
|
54
|
+
export declare function blockAt(page: RenderedPage, path: string): BlockNode | null;
|
|
55
|
+
/** What `view` shows of one thing on the page (24 §3.2): a field with its definition, a button with its arguments. */
|
|
56
|
+
export declare function viewText(page: RenderedPage, id: string): string | null;
|
|
57
|
+
//# sourceMappingURL=workspace.d.ts.map
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { formatTime } from './time-format.js';
|
|
2
|
+
export function workspaceText(page, options = {}) {
|
|
3
|
+
const out = [];
|
|
4
|
+
const notes = options.notes ?? [];
|
|
5
|
+
if (notes.length) {
|
|
6
|
+
out.push('<notes>');
|
|
7
|
+
for (const n of notes)
|
|
8
|
+
out.push(element('note', { id: n.id, about: n.about, value: n.text }));
|
|
9
|
+
out.push('</notes>');
|
|
10
|
+
}
|
|
11
|
+
if (options.nextSteps)
|
|
12
|
+
out.push(...nextStepLines(options.nextSteps.steps, options.nextSteps.timeZone));
|
|
13
|
+
const root = page.root;
|
|
14
|
+
if (root.guide)
|
|
15
|
+
out.push(element('guide', { value: root.guide }));
|
|
16
|
+
out.push(open('page', { title: root.title, description: root.description, fallback: page.fallback ? (page.fallback.stale ? 'stale' : 'empty') : undefined }));
|
|
17
|
+
if (page.fallback) {
|
|
18
|
+
out.push(element('text', {
|
|
19
|
+
key: 'fallback',
|
|
20
|
+
value: page.fallback.stale
|
|
21
|
+
? 'This page could not be refreshed: its values may be out of date, and nothing on it can be changed now.'
|
|
22
|
+
: 'The case page could not be loaded: nothing is known about the case here, and nothing can be changed now.',
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
const defined = definedCells(page);
|
|
26
|
+
if (defined.size) {
|
|
27
|
+
out.push('<definitions>');
|
|
28
|
+
for (const [kind, cell] of defined)
|
|
29
|
+
out.push(element('definition', { for: kind, ...definitionAttrs(page, cell) }));
|
|
30
|
+
out.push('</definitions>');
|
|
31
|
+
}
|
|
32
|
+
for (const child of root.children)
|
|
33
|
+
walk(page, child, defined, false, out);
|
|
34
|
+
out.push('</page>');
|
|
35
|
+
if (options.now)
|
|
36
|
+
out.push(nowLine(options.now));
|
|
37
|
+
return out.join('\n');
|
|
38
|
+
}
|
|
39
|
+
/** The last line of every page the AI reads (76 §2.19): the time now in UTC, to the minute (`Now: 2026-11-11T20:05Z`). */
|
|
40
|
+
export function nowLine(now) {
|
|
41
|
+
return `Now: ${now.toISOString().slice(0, 16)}Z`;
|
|
42
|
+
}
|
|
43
|
+
/** Stable, short appointment handle; the service resolves it within the authorized case, rejecting ambiguity. */
|
|
44
|
+
export function nextStepReference(id) {
|
|
45
|
+
return `step-${id.replaceAll('-', '').slice(0, 12)}`;
|
|
46
|
+
}
|
|
47
|
+
export function nextStepLines(steps, timeZone) {
|
|
48
|
+
if (!steps.length)
|
|
49
|
+
return [element('next-step', { value: 'none: nothing is booked to contact anyone on this case' })];
|
|
50
|
+
const when = (at) => {
|
|
51
|
+
try {
|
|
52
|
+
return formatTime(at, { timeZone });
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return at;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
return steps.map((step) => element('next-step', {
|
|
59
|
+
channel: step.channel,
|
|
60
|
+
id: nextStepReference(step.id),
|
|
61
|
+
name: step.name ?? undefined,
|
|
62
|
+
to: step.contact.name ?? step.contact.id,
|
|
63
|
+
at: when(step.at),
|
|
64
|
+
reason: step.reason ?? undefined,
|
|
65
|
+
'customer-quote': step.customerQuote ?? undefined,
|
|
66
|
+
'booked-in': step.bookedIn ? `the ${step.bookedIn.channel === 'call' ? 'call' : step.bookedIn.channel === 'sms' ? 'texts' : 'email'} of ${when(step.bookedIn.at)}` : 'by the case\'s follow-up rules',
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
const kindOf = (cell) => `${cell.ref.table}.${cell.ref.field}`;
|
|
70
|
+
/** Each `table.field` some field on the page shows expanded, in page order: the page gives its definition once. */
|
|
71
|
+
function definedCells(page) {
|
|
72
|
+
const out = new Map();
|
|
73
|
+
const visit = (node) => {
|
|
74
|
+
if (node.kind === 'cell' && node.expand) {
|
|
75
|
+
const cell = page.cells[node.slotId];
|
|
76
|
+
if (!out.has(kindOf(cell)))
|
|
77
|
+
out.set(kindOf(cell), cell);
|
|
78
|
+
}
|
|
79
|
+
if (node.kind === 'block')
|
|
80
|
+
node.children.forEach(visit);
|
|
81
|
+
};
|
|
82
|
+
page.root.children.forEach(visit);
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
function walk(page, node, defined, inList, out) {
|
|
86
|
+
switch (node.kind) {
|
|
87
|
+
case 'block': {
|
|
88
|
+
const tag = node.list ? 'list' : 'block';
|
|
89
|
+
out.push(open(tag, { key: inList ? undefined : node.key || undefined, title: node.title, description: node.description }));
|
|
90
|
+
for (const child of node.children)
|
|
91
|
+
walk(page, child, defined, node.list, out);
|
|
92
|
+
out.push(`</${tag}>`);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
case 'cell': {
|
|
96
|
+
const cell = page.cells[node.slotId];
|
|
97
|
+
// A field the AI cannot change needs no definition: no `more` on it (26 §16.2 #5b).
|
|
98
|
+
out.push(element('field', fieldAttrs(page, node, cell, editable(node, cell) && !defined.has(kindOf(cell)), inList)));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
case 'text':
|
|
102
|
+
// null: the page put nothing here now (a region that does not apply yet, a value it has not got).
|
|
103
|
+
// In a list it has no key of its own, only its place, as a block there (26 §16.2 #10).
|
|
104
|
+
out.push(element('text', { key: inList ? undefined : node.key || undefined, value: node.value }));
|
|
105
|
+
return;
|
|
106
|
+
case 'action':
|
|
107
|
+
out.push(...buttonLines(page.actions[node.actionId]));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Whether the AI may change a field (30 §3): the field's final permission, the same wherever it is on the
|
|
112
|
+
* page. A place marked read-only cannot stop the AI writing a field writable elsewhere (it writes by id),
|
|
113
|
+
* so marking it there would only contradict the other place.
|
|
114
|
+
*/
|
|
115
|
+
const editable = (_node, cell) => cell.writable;
|
|
116
|
+
/**
|
|
117
|
+
* A field's value (26 §16.2): `key` always (#10; in a list, where it has only its place, none); `readonly`
|
|
118
|
+
* only on one the AI cannot change (#6a); `more` when its definition is not shown, with its type (#6);
|
|
119
|
+
* `state` only when it holds no value (#6a: a value is filled; `[]` too). A ref field (#7) writes the rows
|
|
120
|
+
* it may be set to as `one-of` {name: label}; read-only, who its value is as `value-label`, when the page
|
|
121
|
+
* labelled it.
|
|
122
|
+
*/
|
|
123
|
+
function fieldAttrs(page, node, cell, more, inList = false) {
|
|
124
|
+
const value = valueOf(cell);
|
|
125
|
+
const open = editable(node, cell);
|
|
126
|
+
const labels = cell.optionLabels ?? {};
|
|
127
|
+
return {
|
|
128
|
+
id: cell.slotId,
|
|
129
|
+
key: inList ? undefined : node.key || undefined,
|
|
130
|
+
readonly: !open,
|
|
131
|
+
more,
|
|
132
|
+
type: more ? cell.type : undefined,
|
|
133
|
+
value,
|
|
134
|
+
'value-label': !open && typeof value === 'string' && value in labels ? labels[value] : undefined,
|
|
135
|
+
'one-of': open && cell.options ? Object.fromEntries(cell.options.map((name) => [name, labels[name] ?? name])) : undefined,
|
|
136
|
+
state: cell.state === 'filled' ? undefined : cell.state,
|
|
137
|
+
reason: (cell.state === 'asked_unknown' || cell.state === 'declined') && cell.reason ? cell.reason : undefined,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/** The value as JSON holds it; a ref's is its row's name (33); null when not filled. */
|
|
141
|
+
function valueOf(cell) {
|
|
142
|
+
if (cell.state !== 'filled')
|
|
143
|
+
return null;
|
|
144
|
+
return cell.valueRow ?? cell.value ?? null;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* What a field means and takes (26 §15.3): label, type, allowed values (`one-of`; a ref field's rows are
|
|
148
|
+
* on the field itself, 26 §16.2 #7), and `help` — the schema's description and how to fill it, the
|
|
149
|
+
* page's `$extraction` for its `table.field` replacing the schema's (a ref field's too, #5). How each type
|
|
150
|
+
* is written is the system message's (`PAGE_FORMAT`), once for every field.
|
|
151
|
+
*/
|
|
152
|
+
function definitionAttrs(page, cell) {
|
|
153
|
+
const help = [];
|
|
154
|
+
if (cell.description)
|
|
155
|
+
help.push(cell.description);
|
|
156
|
+
const own = page.extractions?.[kindOf(cell)];
|
|
157
|
+
if (own !== undefined) {
|
|
158
|
+
if (own)
|
|
159
|
+
help.push(own);
|
|
160
|
+
}
|
|
161
|
+
else if (cell.extraction)
|
|
162
|
+
help.push(cell.extraction);
|
|
163
|
+
return {
|
|
164
|
+
label: cell.label,
|
|
165
|
+
type: cell.type,
|
|
166
|
+
'one-of': cell.choices ?? undefined,
|
|
167
|
+
help: help.length ? help.join(' · ') : undefined,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function buttonLines(action) {
|
|
171
|
+
const attrs = { id: action.id, title: action.name, does: action.description };
|
|
172
|
+
const props = action.input?.properties ?? {};
|
|
173
|
+
if (!Object.keys(props).length)
|
|
174
|
+
return [element('button', attrs)];
|
|
175
|
+
const out = [open('button', attrs)];
|
|
176
|
+
for (const [name, prop] of Object.entries(props))
|
|
177
|
+
argLines(name, prop, action.input.required.includes(name), out);
|
|
178
|
+
out.push('</button>');
|
|
179
|
+
return out;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* An argument, its type named as a field's (26 §15.8); a list's items are an `<item>`, an object's
|
|
183
|
+
* properties (a `contact_schedule`'s parts too) `<arg>`s inside it.
|
|
184
|
+
*/
|
|
185
|
+
function argLines(name, prop, required, out) {
|
|
186
|
+
const tag = name === null ? 'item' : 'arg';
|
|
187
|
+
const base = { name: name ?? undefined, required };
|
|
188
|
+
if (prop.type === 'array') {
|
|
189
|
+
out.push(open(tag, { ...base, type: 'list', help: prop.description }));
|
|
190
|
+
argLines(null, prop.items, false, out);
|
|
191
|
+
out.push(`</${tag}>`);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if (prop.type === 'object') {
|
|
195
|
+
out.push(open(tag, { ...base, type: prop['x-type'] ?? 'object', nullable: Boolean(prop.nullable), help: prop.description }));
|
|
196
|
+
for (const [key, inner] of Object.entries(prop.properties))
|
|
197
|
+
argLines(key, inner, (prop.required ?? []).includes(key), out);
|
|
198
|
+
out.push(`</${tag}>`);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
// A row choice: each row with its label (26 §16.2 #7), as a ref field's candidates.
|
|
202
|
+
const oneOf = prop.type === 'ref' && prop.labels ? Object.fromEntries(prop.enum.map((name) => [name, prop.labels[name] ?? name])) : prop.enum;
|
|
203
|
+
out.push(element(tag, { ...base, type: prop.type, 'one-of': oneOf, help: prop.description }));
|
|
204
|
+
}
|
|
205
|
+
/** The block at `path` (`''`: the root). */
|
|
206
|
+
export function blockAt(page, path) {
|
|
207
|
+
if (path === '')
|
|
208
|
+
return page.root;
|
|
209
|
+
let found = null;
|
|
210
|
+
const visit = (node) => {
|
|
211
|
+
if (found || node.kind !== 'block')
|
|
212
|
+
return;
|
|
213
|
+
if (node.path === path)
|
|
214
|
+
found = node;
|
|
215
|
+
else if (path.startsWith(`${node.path}.`) || node.path === '')
|
|
216
|
+
node.children.forEach(visit);
|
|
217
|
+
};
|
|
218
|
+
page.root.children.forEach(visit);
|
|
219
|
+
return found;
|
|
220
|
+
}
|
|
221
|
+
/** What `view` shows of one thing on the page (24 §3.2): a field with its definition, a button with its arguments. */
|
|
222
|
+
export function viewText(page, id) {
|
|
223
|
+
const cell = page.cells[id];
|
|
224
|
+
if (cell) {
|
|
225
|
+
const node = findCellNode(page, id);
|
|
226
|
+
if (!node)
|
|
227
|
+
return null;
|
|
228
|
+
const { type: _type, 'one-of': rows, ...own } = fieldAttrs(page, node, cell, false);
|
|
229
|
+
const definition = definitionAttrs(page, cell);
|
|
230
|
+
// The field, then its definition; a ref field's rows are its own (`one-of` on the field).
|
|
231
|
+
return element('field', { ...own, ...definition, 'one-of': rows ?? definition['one-of'] });
|
|
232
|
+
}
|
|
233
|
+
const action = page.actions[id];
|
|
234
|
+
return action ? buttonLines(action).join('\n') : null;
|
|
235
|
+
}
|
|
236
|
+
function findCellNode(page, slotId) {
|
|
237
|
+
let found = null;
|
|
238
|
+
const visit = (node) => {
|
|
239
|
+
if (found)
|
|
240
|
+
return;
|
|
241
|
+
if (node.kind === 'cell' && node.slotId === slotId)
|
|
242
|
+
found = node;
|
|
243
|
+
if (node.kind === 'block')
|
|
244
|
+
node.children.forEach(visit);
|
|
245
|
+
};
|
|
246
|
+
visit(page.root);
|
|
247
|
+
return found;
|
|
248
|
+
}
|
|
249
|
+
// ---------------------------------------------------------------------------------------------
|
|
250
|
+
// Writing elements
|
|
251
|
+
/** `true`: a bare flag; `false` / `undefined`: left out; anything else `name=<JSON>`. `value` always prints, null included. */
|
|
252
|
+
function attrText(attrs) {
|
|
253
|
+
const parts = [];
|
|
254
|
+
for (const [k, v] of Object.entries(attrs)) {
|
|
255
|
+
if (k === 'value')
|
|
256
|
+
parts.push(`value=${JSON.stringify(v ?? null)}`);
|
|
257
|
+
else if (v === true)
|
|
258
|
+
parts.push(k);
|
|
259
|
+
else if (v !== undefined && v !== false)
|
|
260
|
+
parts.push(`${k}=${JSON.stringify(v)}`);
|
|
261
|
+
}
|
|
262
|
+
return parts.length ? ` ${parts.join(' ')}` : '';
|
|
263
|
+
}
|
|
264
|
+
const open = (tag, attrs) => `<${tag}${attrText(attrs)}>`;
|
|
265
|
+
const element = (tag, attrs) => `<${tag}${attrText(attrs)}/>`;
|
|
266
|
+
//# sourceMappingURL=workspace.js.map
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** How a contact is reached: a phone number or an email address. */
|
|
3
|
+
export declare const partyAddress: z.ZodObject<{
|
|
4
|
+
kind: z.ZodEnum<{
|
|
5
|
+
email: "email";
|
|
6
|
+
phone: "phone";
|
|
7
|
+
}>;
|
|
8
|
+
value: z.ZodString;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
export type PartyAddress = z.infer<typeof partyAddress>;
|
|
11
|
+
/**
|
|
12
|
+
* The other side as a conversation arrives: a phone number or an email address, or the SIP URI of a
|
|
13
|
+
* SIP caller whose URI is not a phone number (`sip:alice@pbx.example.com`): no contact field holds it,
|
|
14
|
+
* so `resolve` finds the contact by what the call carries (`sip.headers`).
|
|
15
|
+
*/
|
|
16
|
+
export declare const arrivalAddress: z.ZodObject<{
|
|
17
|
+
kind: z.ZodEnum<{
|
|
18
|
+
email: "email";
|
|
19
|
+
phone: "phone";
|
|
20
|
+
sip: "sip";
|
|
21
|
+
}>;
|
|
22
|
+
value: z.ZodString;
|
|
23
|
+
}, z.core.$strip>;
|
|
24
|
+
export type ArrivalAddress = z.infer<typeof arrivalAddress>;
|
|
25
|
+
/**
|
|
26
|
+
* A call that came through our SIP Domain: its URIs as they came, the domain, and the headers the far
|
|
27
|
+
* end sent (`X-…` ones and `User-to-User`, by name: `X-Case-Id`). A system that puts the call through
|
|
28
|
+
* to us says in them what it is about.
|
|
29
|
+
*/
|
|
30
|
+
export declare const sipArrival: z.ZodObject<{
|
|
31
|
+
fromUri: z.ZodNullable<z.ZodString>;
|
|
32
|
+
toUri: z.ZodNullable<z.ZodString>;
|
|
33
|
+
domain: z.ZodNullable<z.ZodString>;
|
|
34
|
+
headers: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
35
|
+
}, z.core.$strip>;
|
|
36
|
+
export type SipArrival = z.infer<typeof sipArrival>;
|
|
37
|
+
/**
|
|
38
|
+
* What both resolves get (14-sequence-instance §18): the conversation as it arrives, no facts looked
|
|
39
|
+
* up. They look up what they need (`ctx.api.contact.find`, `ctx.api.instances.findForContact`,
|
|
40
|
+
* `ctx.api.exchanges`).
|
|
41
|
+
*/
|
|
42
|
+
/** A text of the batch the resolve decides for (64 §9), as the page gets it (`ctx.sms.inbound`), with the provider's id. */
|
|
43
|
+
export declare const arrivalSmsMessage: z.ZodObject<{
|
|
44
|
+
id: z.ZodString;
|
|
45
|
+
body: z.ZodString;
|
|
46
|
+
at: z.ZodString;
|
|
47
|
+
externalId: z.ZodNullable<z.ZodString>;
|
|
48
|
+
}, z.core.$strip>;
|
|
49
|
+
export type ArrivalSmsMessage = z.infer<typeof arrivalSmsMessage>;
|
|
50
|
+
/** An email of the batch the resolve decides for (64 §9), as the page gets it (`ctx.email.inbound`), with the provider's id. */
|
|
51
|
+
export declare const arrivalEmailMessage: z.ZodObject<{
|
|
52
|
+
id: z.ZodString;
|
|
53
|
+
from: z.ZodString;
|
|
54
|
+
to: z.ZodArray<z.ZodString>;
|
|
55
|
+
cc: z.ZodArray<z.ZodString>;
|
|
56
|
+
subject: z.ZodNullable<z.ZodString>;
|
|
57
|
+
body: z.ZodString;
|
|
58
|
+
at: z.ZodString;
|
|
59
|
+
attachments: z.ZodArray<z.ZodObject<{
|
|
60
|
+
name: z.ZodString;
|
|
61
|
+
contentType: z.ZodOptional<z.ZodString>;
|
|
62
|
+
}, z.core.$strip>>;
|
|
63
|
+
externalId: z.ZodNullable<z.ZodString>;
|
|
64
|
+
}, z.core.$strip>;
|
|
65
|
+
export type ArrivalEmailMessage = z.infer<typeof arrivalEmailMessage>;
|
|
66
|
+
/**
|
|
67
|
+
* What the company `resolve` is called with (§18.2, its `args`): an inbound conversation, before its sequence is known.
|
|
68
|
+
* `to.name` is our number's, SIP address's or mailbox's name in the environment (22 §7), the same in test and prod.
|
|
69
|
+
*/
|
|
70
|
+
export declare const companyResolveInput: z.ZodObject<{
|
|
71
|
+
channel: z.ZodEnum<{
|
|
72
|
+
call: "call";
|
|
73
|
+
email: "email";
|
|
74
|
+
sms: "sms";
|
|
75
|
+
}>;
|
|
76
|
+
from: z.ZodObject<{
|
|
77
|
+
kind: z.ZodEnum<{
|
|
78
|
+
email: "email";
|
|
79
|
+
phone: "phone";
|
|
80
|
+
sip: "sip";
|
|
81
|
+
}>;
|
|
82
|
+
value: z.ZodString;
|
|
83
|
+
}, z.core.$strip>;
|
|
84
|
+
threadId: z.ZodNullable<z.ZodString>;
|
|
85
|
+
sip: z.ZodOptional<z.ZodObject<{
|
|
86
|
+
fromUri: z.ZodNullable<z.ZodString>;
|
|
87
|
+
toUri: z.ZodNullable<z.ZodString>;
|
|
88
|
+
domain: z.ZodNullable<z.ZodString>;
|
|
89
|
+
headers: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
90
|
+
}, z.core.$strip>>;
|
|
91
|
+
externalId: z.ZodNullable<z.ZodString>;
|
|
92
|
+
messages: z.ZodOptional<z.ZodUnion<readonly [z.ZodArray<z.ZodObject<{
|
|
93
|
+
id: z.ZodString;
|
|
94
|
+
body: z.ZodString;
|
|
95
|
+
at: z.ZodString;
|
|
96
|
+
externalId: z.ZodNullable<z.ZodString>;
|
|
97
|
+
}, z.core.$strip>>, z.ZodArray<z.ZodObject<{
|
|
98
|
+
id: z.ZodString;
|
|
99
|
+
from: z.ZodString;
|
|
100
|
+
to: z.ZodArray<z.ZodString>;
|
|
101
|
+
cc: z.ZodArray<z.ZodString>;
|
|
102
|
+
subject: z.ZodNullable<z.ZodString>;
|
|
103
|
+
body: z.ZodString;
|
|
104
|
+
at: z.ZodString;
|
|
105
|
+
attachments: z.ZodArray<z.ZodObject<{
|
|
106
|
+
name: z.ZodString;
|
|
107
|
+
contentType: z.ZodOptional<z.ZodString>;
|
|
108
|
+
}, z.core.$strip>>;
|
|
109
|
+
externalId: z.ZodNullable<z.ZodString>;
|
|
110
|
+
}, z.core.$strip>>]>>;
|
|
111
|
+
to: z.ZodObject<{
|
|
112
|
+
kind: z.ZodEnum<{
|
|
113
|
+
email: "email";
|
|
114
|
+
phone: "phone";
|
|
115
|
+
sip: "sip";
|
|
116
|
+
}>;
|
|
117
|
+
value: z.ZodString;
|
|
118
|
+
name: z.ZodNullable<z.ZodString>;
|
|
119
|
+
}, z.core.$strip>;
|
|
120
|
+
}, z.core.$strip>;
|
|
121
|
+
export type CompanyResolveInput = z.infer<typeof companyResolveInput>;
|
|
122
|
+
/**
|
|
123
|
+
* What the company `resolve` returns: the sequence (its name) the conversation goes to, or `decline`
|
|
124
|
+
* (we do not take it; §18.5): a call is transferred to the environment's fallback number, a text or
|
|
125
|
+
* an email gets `reply` when given.
|
|
126
|
+
*/
|
|
127
|
+
export declare const companyResolveResult: z.ZodUnion<readonly [z.ZodObject<{
|
|
128
|
+
sequence: z.ZodString;
|
|
129
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
130
|
+
decline: z.ZodObject<{
|
|
131
|
+
reply: z.ZodOptional<z.ZodString>;
|
|
132
|
+
}, z.core.$strict>;
|
|
133
|
+
}, z.core.$strict>]>;
|
|
134
|
+
export type CompanyResolveResult = z.infer<typeof companyResolveResult>;
|
|
135
|
+
/** What a sequence's `resolve` is called with (§18.3, its `args`): the conversation, on this sequence. */
|
|
136
|
+
export declare const resolveInput: z.ZodObject<{
|
|
137
|
+
channel: z.ZodEnum<{
|
|
138
|
+
call: "call";
|
|
139
|
+
email: "email";
|
|
140
|
+
sms: "sms";
|
|
141
|
+
}>;
|
|
142
|
+
from: z.ZodObject<{
|
|
143
|
+
kind: z.ZodEnum<{
|
|
144
|
+
email: "email";
|
|
145
|
+
phone: "phone";
|
|
146
|
+
sip: "sip";
|
|
147
|
+
}>;
|
|
148
|
+
value: z.ZodString;
|
|
149
|
+
}, z.core.$strip>;
|
|
150
|
+
to: z.ZodObject<{
|
|
151
|
+
kind: z.ZodEnum<{
|
|
152
|
+
email: "email";
|
|
153
|
+
phone: "phone";
|
|
154
|
+
sip: "sip";
|
|
155
|
+
}>;
|
|
156
|
+
value: z.ZodString;
|
|
157
|
+
}, z.core.$strip>;
|
|
158
|
+
threadId: z.ZodNullable<z.ZodString>;
|
|
159
|
+
sip: z.ZodOptional<z.ZodObject<{
|
|
160
|
+
fromUri: z.ZodNullable<z.ZodString>;
|
|
161
|
+
toUri: z.ZodNullable<z.ZodString>;
|
|
162
|
+
domain: z.ZodNullable<z.ZodString>;
|
|
163
|
+
headers: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
164
|
+
}, z.core.$strip>>;
|
|
165
|
+
externalId: z.ZodNullable<z.ZodString>;
|
|
166
|
+
messages: z.ZodOptional<z.ZodUnion<readonly [z.ZodArray<z.ZodObject<{
|
|
167
|
+
id: z.ZodString;
|
|
168
|
+
body: z.ZodString;
|
|
169
|
+
at: z.ZodString;
|
|
170
|
+
externalId: z.ZodNullable<z.ZodString>;
|
|
171
|
+
}, z.core.$strip>>, z.ZodArray<z.ZodObject<{
|
|
172
|
+
id: z.ZodString;
|
|
173
|
+
from: z.ZodString;
|
|
174
|
+
to: z.ZodArray<z.ZodString>;
|
|
175
|
+
cc: z.ZodArray<z.ZodString>;
|
|
176
|
+
subject: z.ZodNullable<z.ZodString>;
|
|
177
|
+
body: z.ZodString;
|
|
178
|
+
at: z.ZodString;
|
|
179
|
+
attachments: z.ZodArray<z.ZodObject<{
|
|
180
|
+
name: z.ZodString;
|
|
181
|
+
contentType: z.ZodOptional<z.ZodString>;
|
|
182
|
+
}, z.core.$strip>>;
|
|
183
|
+
externalId: z.ZodNullable<z.ZodString>;
|
|
184
|
+
}, z.core.$strip>>]>>;
|
|
185
|
+
direction: z.ZodEnum<{
|
|
186
|
+
inbound: "inbound";
|
|
187
|
+
outbound: "outbound";
|
|
188
|
+
}>;
|
|
189
|
+
sequence: z.ZodString;
|
|
190
|
+
}, z.core.$strip>;
|
|
191
|
+
export type ResolveInput = z.infer<typeof resolveInput>;
|
|
192
|
+
/**
|
|
193
|
+
* What a sequence's `resolve` returns: the contact the conversation is with, and either an active
|
|
194
|
+
* instance of this sequence to join or a new one of this sequence to start (on a row of its subject
|
|
195
|
+
* table; when another start won the race for the same row, the conversation joins that one).
|
|
196
|
+
*/
|
|
197
|
+
export declare const resolveResult: z.ZodUnion<readonly [z.ZodObject<{
|
|
198
|
+
contactId: z.ZodString;
|
|
199
|
+
instanceId: z.ZodString;
|
|
200
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
201
|
+
contactId: z.ZodString;
|
|
202
|
+
start: z.ZodObject<{
|
|
203
|
+
subjectRecordId: z.ZodString;
|
|
204
|
+
variables: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
205
|
+
}, z.core.$strict>;
|
|
206
|
+
}, z.core.$strict>]>;
|
|
207
|
+
export type ResolveResult = z.infer<typeof resolveResult>;
|
|
208
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** How a contact is reached: a phone number or an email address. */
|
|
3
|
+
export const partyAddress = z.object({
|
|
4
|
+
kind: z.enum(['phone', 'email']),
|
|
5
|
+
value: z.string().min(1),
|
|
6
|
+
});
|
|
7
|
+
/**
|
|
8
|
+
* The other side as a conversation arrives: a phone number or an email address, or the SIP URI of a
|
|
9
|
+
* SIP caller whose URI is not a phone number (`sip:alice@pbx.example.com`): no contact field holds it,
|
|
10
|
+
* so `resolve` finds the contact by what the call carries (`sip.headers`).
|
|
11
|
+
*/
|
|
12
|
+
export const arrivalAddress = z.object({
|
|
13
|
+
kind: z.enum(['phone', 'email', 'sip']),
|
|
14
|
+
value: z.string().min(1),
|
|
15
|
+
});
|
|
16
|
+
/**
|
|
17
|
+
* A call that came through our SIP Domain: its URIs as they came, the domain, and the headers the far
|
|
18
|
+
* end sent (`X-…` ones and `User-to-User`, by name: `X-Case-Id`). A system that puts the call through
|
|
19
|
+
* to us says in them what it is about.
|
|
20
|
+
*/
|
|
21
|
+
export const sipArrival = z.object({
|
|
22
|
+
fromUri: z.string().nullable(),
|
|
23
|
+
toUri: z.string().nullable(),
|
|
24
|
+
domain: z.string().nullable(),
|
|
25
|
+
headers: z.record(z.string(), z.string()),
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* What both resolves get (14-sequence-instance §18): the conversation as it arrives, no facts looked
|
|
29
|
+
* up. They look up what they need (`ctx.api.contact.find`, `ctx.api.instances.findForContact`,
|
|
30
|
+
* `ctx.api.exchanges`).
|
|
31
|
+
*/
|
|
32
|
+
/** A text of the batch the resolve decides for (64 §9), as the page gets it (`ctx.sms.inbound`), with the provider's id. */
|
|
33
|
+
export const arrivalSmsMessage = z.object({
|
|
34
|
+
id: z.string(),
|
|
35
|
+
body: z.string(),
|
|
36
|
+
at: z.string(),
|
|
37
|
+
/** The provider's id of the text (Twilio's MessageSid). */
|
|
38
|
+
externalId: z.string().nullable(),
|
|
39
|
+
});
|
|
40
|
+
/** An email of the batch the resolve decides for (64 §9), as the page gets it (`ctx.email.inbound`), with the provider's id. */
|
|
41
|
+
export const arrivalEmailMessage = z.object({
|
|
42
|
+
id: z.string(),
|
|
43
|
+
from: z.string(),
|
|
44
|
+
to: z.array(z.string()),
|
|
45
|
+
cc: z.array(z.string()),
|
|
46
|
+
subject: z.string().nullable(),
|
|
47
|
+
/** Quoted history and signature taken out. */
|
|
48
|
+
body: z.string(),
|
|
49
|
+
at: z.string(),
|
|
50
|
+
/** Listed only: their contents are not read here. */
|
|
51
|
+
attachments: z.array(z.object({ name: z.string(), contentType: z.string().optional() })),
|
|
52
|
+
/** The provider's id of the email. */
|
|
53
|
+
externalId: z.string().nullable(),
|
|
54
|
+
});
|
|
55
|
+
const conversationArrival = z.object({
|
|
56
|
+
channel: z.enum(['call', 'sms', 'email']),
|
|
57
|
+
/** The other side: the caller or sender on inbound, the one called on outbound. Normalized. */
|
|
58
|
+
from: arrivalAddress,
|
|
59
|
+
/**
|
|
60
|
+
* Our side: the number or mailbox the conversation came in on (inbound) or goes out from; on a call
|
|
61
|
+
* through our SIP Domain to one of our SIP addresses, the SIP URI it dialed (`sip:sales@acme.sip.twilio.com`).
|
|
62
|
+
*/
|
|
63
|
+
to: arrivalAddress,
|
|
64
|
+
/** Email: the provider thread id, when the message belongs to one. */
|
|
65
|
+
threadId: z.string().nullable(),
|
|
66
|
+
/** A call through our SIP Domain; absent on any other conversation. */
|
|
67
|
+
sip: sipArrival.optional(),
|
|
68
|
+
/** A call: the provider's id of the call (Twilio's CallSid, 62), what a record written here can name it by. Null on a text or an email. */
|
|
69
|
+
externalId: z.string().nullable(),
|
|
70
|
+
/**
|
|
71
|
+
* Texts and emails: the batch this resolve decides for (64 §9), oldest first; each carries its own
|
|
72
|
+
* `externalId`. Absent on a call, which has said nothing yet, and on an outbound conversation.
|
|
73
|
+
*/
|
|
74
|
+
messages: z.union([z.array(arrivalSmsMessage), z.array(arrivalEmailMessage)]).optional(),
|
|
75
|
+
});
|
|
76
|
+
/**
|
|
77
|
+
* What the company `resolve` is called with (§18.2, its `args`): an inbound conversation, before its sequence is known.
|
|
78
|
+
* `to.name` is our number's, SIP address's or mailbox's name in the environment (22 §7), the same in test and prod.
|
|
79
|
+
*/
|
|
80
|
+
export const companyResolveInput = conversationArrival.extend({
|
|
81
|
+
to: arrivalAddress.extend({ name: z.string().nullable() }),
|
|
82
|
+
});
|
|
83
|
+
/**
|
|
84
|
+
* What the company `resolve` returns: the sequence (its name) the conversation goes to, or `decline`
|
|
85
|
+
* (we do not take it; §18.5): a call is transferred to the environment's fallback number, a text or
|
|
86
|
+
* an email gets `reply` when given.
|
|
87
|
+
*/
|
|
88
|
+
export const companyResolveResult = z.union([
|
|
89
|
+
z.strictObject({ sequence: z.string().min(1) }),
|
|
90
|
+
z.strictObject({ decline: z.strictObject({ reply: z.string().min(1).optional() }) }),
|
|
91
|
+
]);
|
|
92
|
+
/** What a sequence's `resolve` is called with (§18.3, its `args`): the conversation, on this sequence. */
|
|
93
|
+
export const resolveInput = conversationArrival.extend({
|
|
94
|
+
direction: z.enum(['inbound', 'outbound']),
|
|
95
|
+
/** This sequence (its name): the only one whose instances `resolve` may return or start. */
|
|
96
|
+
sequence: z.string(),
|
|
97
|
+
});
|
|
98
|
+
/**
|
|
99
|
+
* What a sequence's `resolve` returns: the contact the conversation is with, and either an active
|
|
100
|
+
* instance of this sequence to join or a new one of this sequence to start (on a row of its subject
|
|
101
|
+
* table; when another start won the race for the same row, the conversation joins that one).
|
|
102
|
+
*/
|
|
103
|
+
export const resolveResult = z.union([
|
|
104
|
+
z.strictObject({ contactId: z.string().min(1), instanceId: z.string().min(1) }),
|
|
105
|
+
z.strictObject({
|
|
106
|
+
contactId: z.string().min(1),
|
|
107
|
+
start: z.strictObject({
|
|
108
|
+
subjectRecordId: z.string().min(1),
|
|
109
|
+
variables: z.record(z.string(), z.unknown()).optional(),
|
|
110
|
+
}),
|
|
111
|
+
}),
|
|
112
|
+
]);
|
|
113
|
+
//# sourceMappingURL=schema.js.map
|