@voctiv/agent-sdk 0.2.14 → 0.2.16
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 +312 -61
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/recall-utils.d.ts +8 -0
- package/dist/recall-utils.d.ts.map +1 -0
- package/dist/recall-utils.js +51 -0
- package/dist/recall-utils.js.map +1 -0
- package/dist/types/events.d.ts +9 -2
- package/dist/types/events.d.ts.map +1 -1
- package/dist/types/logger.d.ts +30 -0
- package/dist/types/logger.d.ts.map +1 -1
- package/dist/types/logger.js +12 -0
- package/dist/types/logger.js.map +1 -1
- package/dist/types/nlu.d.ts +5 -3
- package/dist/types/nlu.d.ts.map +1 -1
- package/dist/types/platform.d.ts +74 -17
- package/dist/types/platform.d.ts.map +1 -1
- package/dist/types/script-context.d.ts +20 -5
- package/dist/types/script-context.d.ts.map +1 -1
- package/dist/types/script-context.js.map +1 -1
- package/dist/types/sip.d.ts +20 -11
- package/dist/types/sip.d.ts.map +1 -1
- package/examples/README.md +43 -0
- package/examples/after-call-continuation.ts +47 -0
- package/examples/outbound-with-recall.ts +43 -0
- package/examples/read-recall-from-params.ts +41 -0
- package/examples/recall-routing-by-attempt.ts +55 -0
- package/examples/schedule-call-with-defaults.ts +31 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -70,10 +70,60 @@ export default defineScript(async ({ channel, logger, context }) => {
|
|
|
70
70
|
});
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
## Examples
|
|
74
|
+
|
|
75
|
+
The [`examples/`](./examples/) folder contains copy-paste-ready scripts:
|
|
76
|
+
|
|
77
|
+
| Example | Description |
|
|
78
|
+
|---------|-------------|
|
|
79
|
+
| [outbound-with-recall.ts](./examples/outbound-with-recall.ts) | Outbound with `recallCount` / `recallDelay` (automatic redial on failure) |
|
|
80
|
+
| [recall-routing-by-attempt.ts](./examples/recall-routing-by-attempt.ts) | Online recall: branch on `context.attempt` (`getScriptPhase` → `'online'`) |
|
|
81
|
+
| [schedule-call-with-defaults.ts](./examples/schedule-call-with-defaults.ts) | `platform.call()` without explicit recall — CMS defaults from `context` |
|
|
82
|
+
| [after-call-continuation.ts](./examples/after-call-continuation.ts) | `onSuccessCall` / `onFailedCall` vs recall (mutually exclusive) |
|
|
83
|
+
| [read-recall-from-params.ts](./examples/read-recall-from-params.ts) | `parseRecallDelaySeconds()` / `parseRecallCount()` on legacy params |
|
|
84
|
+
|
|
85
|
+
### Quick recall example
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { defineScript } from '@voctiv/agent-sdk';
|
|
89
|
+
|
|
90
|
+
export default defineScript(async ({ channel, context, platform, logger }) => {
|
|
91
|
+
channel.sip.answer();
|
|
92
|
+
|
|
93
|
+
if ((context.attempt ?? 0) > 0) {
|
|
94
|
+
logger.log('Online recall attempt', { attempt: context.attempt });
|
|
95
|
+
await channel.audio.say('Sorry we missed you earlier. Trying again now.');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Schedule first outbound with up to 3 retries, 5 min apart (no entryPoint — same defineScript runs each leg).
|
|
99
|
+
await platform.call(context.msisdn!, {
|
|
100
|
+
recallCount: context.recallCount ?? 3,
|
|
101
|
+
recallDelay: context.recallDelay ?? 300,
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Parse legacy time strings from params when needed:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { parseRecallDelaySeconds, parseRecallCount } from '@voctiv/agent-sdk';
|
|
110
|
+
|
|
111
|
+
const delaySec = parseRecallDelaySeconds(context.dialogParams?.recall_delay); // "00:05:00" → 300
|
|
112
|
+
const maxAttempts = parseRecallCount(context.dialogParams?.recall_count);
|
|
113
|
+
```
|
|
114
|
+
|
|
73
115
|
## What The SDK Contains
|
|
74
116
|
|
|
75
117
|
`defineScript(fn)` marks the default export as the script entry point. It returns the same function and exists to give TypeScript the correct `ScriptContext` shape.
|
|
76
118
|
|
|
119
|
+
**Three different “context” names:**
|
|
120
|
+
|
|
121
|
+
| Name | Meaning |
|
|
122
|
+
| --- | --- |
|
|
123
|
+
| `ScriptContext` | Top-level injection: `{ channel, logger, context, platform }` |
|
|
124
|
+
| `context` (`ScriptDialogContext`) | Dialog identity, params, routing snapshot, `env$`, headless — see [Dialog Context](#dialog-context-and-persisted-env) |
|
|
125
|
+
| `options.context` on `platform.nlu.extract` | Opaque NLU disambiguation string/JSON — **not** dialog context |
|
|
126
|
+
|
|
77
127
|
`ScriptContext` is the top-level object passed to a script:
|
|
78
128
|
|
|
79
129
|
- `channel` is the media channel for SIP, WS, ASR, TTS, audio playback, LLM, and structured data messages.
|
|
@@ -178,19 +228,43 @@ If the call terminates before media becomes available, deferred audio resolves a
|
|
|
178
228
|
On **SIP channels**, `channel.sip` exposes raw signalling beyond call state — useful for
|
|
179
229
|
carrier routing, diversion chains, and vendor SDP attributes.
|
|
180
230
|
|
|
231
|
+
#### When to use what
|
|
232
|
+
|
|
233
|
+
| Need | API | When |
|
|
234
|
+
| --- | --- | --- |
|
|
235
|
+
| Routing / identity / locale from the **inbound INVITE** (`Diversion`, `X-Trunk-Id`, `X-Neuro-UUID`, `X-language`, …) | `channel.sip.inviteSipHeaders` | Call **start** only (snapshot) |
|
|
236
|
+
| Peer signal **during** the call (e.g. mid-call language in INFO body) | `channel.sip.sipInfo$` | After subscribe; each INFO |
|
|
237
|
+
| DTMF digits | `channel.sip.dtmf$` | Prefer over parsing INFO |
|
|
238
|
+
| SDP / codec / connection | `remoteSdp` / `getRemoteSdpDetails()` | May change (183 / 200 / re-INVITE) |
|
|
239
|
+
| SIP response code / phrase (180, 486, …) | `sipSignal$` | Low-level; **no** response headers |
|
|
240
|
+
| Live SIP headers on 200 / re-INVITE / BYE | — | **Not exposed** |
|
|
241
|
+
|
|
242
|
+
Decision guide:
|
|
243
|
+
|
|
244
|
+
- Value from the inbound INVITE at call start → `inviteSipHeaders`
|
|
245
|
+
- Mid-call signal from peer INFO → `sipInfo$` (`contentType` + `body` only)
|
|
246
|
+
- DTMF → `dtmf$`
|
|
247
|
+
- Media description → `remoteSdp` / `getRemoteSdpDetails()`
|
|
248
|
+
- Live SIP response headers → not available (`sipSignal$` has status/SDP only)
|
|
249
|
+
|
|
250
|
+
**Locale pattern:** read start language from `inviteSipHeaders` (e.g. `X-language`). Mid-call changes only work if the peer puts the language in the INFO **body** — INFO SIP headers are not forwarded. Monolingual agents can ignore both and use `context.language` / config.
|
|
251
|
+
|
|
252
|
+
Outbound INVITE headers you **send** go through `platform.call({ protoAdditional })` or `makeCall` options — not `inviteSipHeaders` (read-only inbound snapshot). SIP metadata does not auto-update `context` or `platform.dialog`.
|
|
253
|
+
|
|
181
254
|
#### INVITE headers (`inviteSipHeaders`)
|
|
182
255
|
|
|
183
256
|
Snapshot of SIP headers from an **inbound INVITE** at call setup. Includes standard and
|
|
184
|
-
extension headers (`Diversion`, `P-Asserted-Identity`, `X-Trunk-Id`, `X-Neuro-UUID`, …).
|
|
257
|
+
extension headers (`Diversion`, `P-Asserted-Identity`, `X-Trunk-Id`, `X-Neuro-UUID`, `X-language`, …).
|
|
185
258
|
|
|
186
259
|
| Property | Updates during call? |
|
|
187
260
|
| --- | --- |
|
|
188
|
-
| `inviteSipHeaders` | **No** — INVITE snapshot only; outbound B-legs usually `undefined` |
|
|
261
|
+
| `inviteSipHeaders` | **No** — INVITE snapshot only; outbound B-legs / WS / headless usually `undefined` |
|
|
189
262
|
|
|
190
263
|
```ts
|
|
191
264
|
const h = channel.sip.inviteSipHeaders;
|
|
192
265
|
const diversion = h?.Diversion; // string | string[] when multiple hops
|
|
193
266
|
const trunkId = h?.['X-Trunk-Id'];
|
|
267
|
+
const lang = h?.['X-language'];
|
|
194
268
|
```
|
|
195
269
|
|
|
196
270
|
Header names match what the host stack exposes (case-sensitive). Duplicate headers become
|
|
@@ -217,7 +291,9 @@ attributes. It is not a full SDP validator — use `remoteSdp` when you need the
|
|
|
217
291
|
|
|
218
292
|
#### SIP INFO (`sipInfo$`)
|
|
219
293
|
|
|
220
|
-
Live stream of incoming SIP INFO messages
|
|
294
|
+
Live stream of incoming SIP INFO messages. Each event is `{ contentType, body }` only —
|
|
295
|
+
**INFO request headers are not exposed**. Prefer `dtmf$` for DTMF. Does not update
|
|
296
|
+
`inviteSipHeaders`.
|
|
221
297
|
|
|
222
298
|
```ts
|
|
223
299
|
channel.sip.sipInfo$.subscribe(({ contentType, body }) => {
|
|
@@ -251,11 +327,14 @@ the per-event `sdp` on `sipSignal$`.
|
|
|
251
327
|
- `bridge(other)` to cross-connect two SIP channels.
|
|
252
328
|
|
|
253
329
|
`makeCall()` and `bridge()` are supported on SIP channels. The returned B-leg is a full
|
|
254
|
-
`MediaChannel` with the same API as the main channel. WS and headless channels
|
|
330
|
+
`MediaChannel` with the same API as the main channel. WS and headless channels cannot create real SIP
|
|
331
|
+
legs, so both methods **throw** there rather than returning an inert leg you could talk into
|
|
332
|
+
unnoticed. Guard them with `context.headless` or `channel.type` when a script runs in both modes.
|
|
255
333
|
|
|
256
334
|
### `channel.sip` Reference
|
|
257
335
|
|
|
258
|
-
SIP-only unless noted. WS/headless: most methods are no-ops
|
|
336
|
+
SIP-only unless noted. WS/headless: most methods are no-ops and `state` behaves as synthetic
|
|
337
|
+
`active`, except `makeCall()` and `bridge()`, which throw.
|
|
259
338
|
|
|
260
339
|
| Member | Description |
|
|
261
340
|
| --- | --- |
|
|
@@ -266,10 +345,10 @@ SIP-only unless noted. WS/headless: most methods are no-ops; `state` behaves as
|
|
|
266
345
|
| `early$` | Emits once when RTP is up before final answer |
|
|
267
346
|
| `answered$` | Emits once on 200 OK |
|
|
268
347
|
| `dtmf$` | Remote DTMF digits (`DtmfEvent`: `digit`, `duration`) |
|
|
269
|
-
| `sipInfo$` |
|
|
270
|
-
| `sipSignal$` | Low-level
|
|
348
|
+
| `sipInfo$` | Mid-call SIP INFO (`contentType` + `body` only; INFO headers not exposed) |
|
|
349
|
+
| `sipSignal$` | Low-level stack events (`statusCode` / `statusPhrase` / optional `sdp`; no headers) |
|
|
271
350
|
| `remoteSdp` | Latest negotiated remote SDP body; updates when new SDP arrives |
|
|
272
|
-
| `inviteSipHeaders` |
|
|
351
|
+
| `inviteSipHeaders` | Start-of-call inbound INVITE header snapshot; does not update |
|
|
273
352
|
| `getRemoteSdpDetails()` | Parse `remoteSdp` → `ParsedSdpDetails` (session + `a=` attributes) |
|
|
274
353
|
| `sendProgress()` | Inbound: send 183 Session Progress → `early` |
|
|
275
354
|
| `waitForEarly()` | Await `early` or `active` (Promise) |
|
|
@@ -285,8 +364,8 @@ SIP-only unless noted. WS/headless: most methods are no-ops; `state` behaves as
|
|
|
285
364
|
|
|
286
365
|
Prefer `dtmf$` over `sipInfo$` for DTMF. Prefer `state$` / `early$` / `answered$` over raw
|
|
287
366
|
`sipSignal$` for call lifecycle. Use `remoteSdp` / `getRemoteSdpDetails()` for negotiated
|
|
288
|
-
media description; use `inviteSipHeaders` for
|
|
289
|
-
See **SIP Signalling Metadata
|
|
367
|
+
media description; use `inviteSipHeaders` for start-of-call INVITE headers and `sipInfo$`
|
|
368
|
+
for mid-call INFO body. See **When to use what** under SIP Signalling Metadata above.
|
|
290
369
|
|
|
291
370
|
### SIP Bridge
|
|
292
371
|
|
|
@@ -550,7 +629,7 @@ When phrase persistence is enabled, `preload()` can store decoded audio for late
|
|
|
550
629
|
|
|
551
630
|
`ttsStrategy` controls how text is chunked:
|
|
552
631
|
|
|
553
|
-
- `sentence`: split on sentence boundaries and synthesize each sentence. This is the default.
|
|
632
|
+
- `sentence`: split on sentence boundaries and synthesize each sentence. This is the default. Only one sentence is synthesized at a time; when synthesis of N finishes, N+1 starts immediately while N continues playing from the mixer queue. Sentence N is fired as soon as its text is complete — it never waits for sentence N+1. For ElevenLabs HTTP TTS, each request gets `previous_text` / `next_text` when those neighbor texts are already available (e.g. full string already split); on an LLM stream typically only `previous_text` is known at fire time. Scripts do not need to set these fields. `eleven_v3` does not support those fields (API 400), so they are omitted for that model. The TTS cache key is still the sentence text only (neighbors are not part of the key), so cache hits may replay audio synthesized under a different neighbor context.
|
|
554
633
|
- `streaming`: send chunks incrementally for streaming-capable vendors.
|
|
555
634
|
- `full`: accumulate the whole input and synthesize it as one segment after the input completes.
|
|
556
635
|
|
|
@@ -889,25 +968,82 @@ return {
|
|
|
889
968
|
};
|
|
890
969
|
```
|
|
891
970
|
|
|
892
|
-
- **`output`** — stored in dialog stats / host persistence.
|
|
971
|
+
- **`output`** — stored in dialog stats / host persistence. This is **not** the LE `dialog.result` lifecycle column — that is `platform.dialog.result` (see [Dialog State](#dialog-state)).
|
|
893
972
|
- **`error`** — optional; usually auto-populated on crash, but scripts may set it explicitly.
|
|
894
973
|
|
|
895
974
|
**Do not** return `env` from the script. Persist state via `context.env$`; the runtime snapshots it
|
|
896
975
|
after completion into **`PersistedScriptResult.env`**.
|
|
897
976
|
|
|
898
|
-
|
|
977
|
+
## Script Lifecycle (`getScriptPhase`)
|
|
978
|
+
|
|
979
|
+
The host always runs your single **`defineScript` export** — there is no separate runtime entry per
|
|
980
|
+
name (unlike logic-executor Python `run_unit(entry_point=...)`). Use **`getScriptPhase(context)`**
|
|
981
|
+
to tell *why* the script is running now: live call, pre-call queue, post-call continuation,
|
|
982
|
+
messaging, etc.
|
|
983
|
+
|
|
984
|
+
**`context.headless === true` only means “no live SIP/media”.** It does **not** tell you whether
|
|
985
|
+
the run is before or after a call. For that, use `getScriptPhase`.
|
|
986
|
+
|
|
987
|
+
The return value is the `ScriptPhase` union — one of the phases in the table below.
|
|
988
|
+
|
|
989
|
+
| Phase | `context.headless` | When | Typical `context.entryPoint` |
|
|
990
|
+
|-------|-------------------|------|--------------------------------|
|
|
991
|
+
| `before_call` | `true` | Dialog queue / bulk outbound **before** the first platform call (often schedules `platform.call`) | empty, `main`, `default` |
|
|
992
|
+
| `online` | `false` | Live SIP session (inbound, outbound, **and automatic recall redials**) | any (ignored for phase) |
|
|
993
|
+
| `after_call_success` | `true` | Headless run **after** a successful call | `on_success_call`, `after_call_success`, `on_done_call` |
|
|
994
|
+
| `after_call_failed` | `true` | Headless run **after** failed attempts (when `onFailedCall` was configured) | `on_failed_call`, `after_call_failed` |
|
|
995
|
+
| `messaging` | `true` | Inbound message triggered the run | `on_message_api_received`, or `context.inboundMessage` set |
|
|
996
|
+
| `recall` | `true` | Headless recall leg (legacy `entry_point`) | `on_recall`, `recall` |
|
|
997
|
+
| `headless_other` | `true` | Any other headless run with a custom `entry_point` | your custom name |
|
|
998
|
+
|
|
999
|
+
**Automatic recall** (`recallCount` + `recallDelay`) creates new **online** SIP legs with an
|
|
1000
|
+
incremented `context.attempt`. Branch with `(context.attempt ?? 0) > 0`, **not** `phase === 'recall'`.
|
|
1001
|
+
See [examples/recall-routing-by-attempt.ts](./examples/recall-routing-by-attempt.ts).
|
|
1002
|
+
|
|
1003
|
+
**After-call continuation** uses `onSuccessCall` / `onFailedCall` on `platform.call()`. When the call
|
|
1004
|
+
ends, the host sets `dialog.params.entry_point` to that handler name and runs the same `defineScript`
|
|
1005
|
+
headlessly. See [examples/after-call-continuation.ts](./examples/after-call-continuation.ts).
|
|
1006
|
+
|
|
1007
|
+
These two failure models are **mutually exclusive** on one scheduled outbound — see
|
|
1008
|
+
[Failed outbound: automatic recall vs after-call continuation](#failed-outbound-automatic-recall-vs-after-call-continuation).
|
|
899
1009
|
|
|
900
1010
|
```ts
|
|
901
1011
|
import { defineScript, getScriptPhase } from '@voctiv/agent-sdk';
|
|
902
1012
|
|
|
903
|
-
export default defineScript(async ({ context }) => {
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
1013
|
+
export default defineScript(async ({ channel, context, logger, platform }) => {
|
|
1014
|
+
const phase = getScriptPhase(context);
|
|
1015
|
+
|
|
1016
|
+
switch (phase) {
|
|
1017
|
+
case 'before_call':
|
|
1018
|
+
// Headless pre-call: queue worker, usually schedules outbound.
|
|
1019
|
+
await platform.call(context.msisdn!, { recallCount: 3, recallDelay: 300 });
|
|
1020
|
+
return { output: { phase } };
|
|
1021
|
+
|
|
1022
|
+
case 'after_call_success':
|
|
1023
|
+
logger.log('Post-call success branch', { entryPoint: context.entryPoint });
|
|
1024
|
+
return { output: { phase } };
|
|
1025
|
+
|
|
1026
|
+
case 'after_call_failed':
|
|
1027
|
+
logger.log('Post-call failure branch', { entryPoint: context.entryPoint });
|
|
1028
|
+
platform.dialog.result = 'done';
|
|
1029
|
+
return { output: { phase } };
|
|
1030
|
+
|
|
908
1031
|
case 'messaging':
|
|
909
|
-
|
|
910
|
-
|
|
1032
|
+
logger.log('Inbound message', { text: context.inboundMessage?.payload });
|
|
1033
|
+
return { output: { phase } };
|
|
1034
|
+
|
|
1035
|
+
case 'online':
|
|
1036
|
+
channel.sip.answer();
|
|
1037
|
+
if ((context.attempt ?? 0) > 0) {
|
|
1038
|
+
logger.log('Online recall leg', { attempt: context.attempt });
|
|
1039
|
+
}
|
|
1040
|
+
await channel.audio.say('Hello.');
|
|
1041
|
+
return;
|
|
1042
|
+
|
|
1043
|
+
default:
|
|
1044
|
+
// headless_other, recall (headless), etc.
|
|
1045
|
+
logger.log('Other headless run', { phase, entryPoint: context.entryPoint });
|
|
1046
|
+
return { output: { phase } };
|
|
911
1047
|
}
|
|
912
1048
|
});
|
|
913
1049
|
```
|
|
@@ -916,7 +1052,7 @@ export default defineScript(async ({ context }) => {
|
|
|
916
1052
|
|
|
917
1053
|
`platform` exposes platform operations.
|
|
918
1054
|
|
|
919
|
-
`platform.nlu.extract(utterance, options?)` runs intent/entity extraction. If `options.context` is omitted
|
|
1055
|
+
`platform.nlu.extract(utterance, options?)` runs intent/entity extraction. If `options.context` is omitted or `null`, the runtime sends **no** NLU context — there is no auto-fill from dialog params or `flag`. Pass it explicitly when needed (logic-executor scripts usually pass `context.flag`). Default NLU language comes from the LE agent (`_nlu.language`), not `context.lang`.
|
|
920
1056
|
|
|
921
1057
|
`platform.nlu.extract$()` is an Observable wrapper — one `extract()` call per subscription, not a streaming NLU session.
|
|
922
1058
|
|
|
@@ -924,20 +1060,64 @@ export default defineScript(async ({ context }) => {
|
|
|
924
1060
|
const result = await platform.nlu.extract('I want to reschedule', {
|
|
925
1061
|
intents: ['reschedule', 'cancel'],
|
|
926
1062
|
entities: ['date', 'time'],
|
|
1063
|
+
context: context.flag,
|
|
927
1064
|
use_synonyms: true,
|
|
928
1065
|
});
|
|
929
1066
|
```
|
|
930
1067
|
|
|
931
|
-
Platform APIs (`platform.nlu`, `platform.call`, dialog writes, messaging, phrase records) are available when the host enables platform integration.
|
|
1068
|
+
Platform APIs (`platform.nlu`, `platform.call`, dialog writes, messaging, phrase records) are available when the host enables platform integration (`context.legacyV3Compat`).
|
|
932
1069
|
|
|
933
1070
|
### Dialog State
|
|
934
1071
|
|
|
1072
|
+
`platform.dialog` reads and writes the LE **dialog row** — not SIP media and not the script return value.
|
|
1073
|
+
|
|
1074
|
+
#### What `platform.dialog.result` is
|
|
1075
|
+
|
|
1076
|
+
`platform.dialog.result` maps to the PostgreSQL column **`dialog.result`**: the **lifecycle status** of the dialog entity in the CMS / offline queue (in queue, in progress, closed). It is **not** the outcome of a SIP leg.
|
|
1077
|
+
|
|
1078
|
+
| Value | Meaning |
|
|
1079
|
+
| --- | --- |
|
|
1080
|
+
| `null` | Often after-call continuation: dialog re-enters queue-api, then becomes `queued` |
|
|
1081
|
+
| `queued` | In the offline queue, not yet claimed |
|
|
1082
|
+
| `pending` | In progress (live SIP/WS or claimed queue row) |
|
|
1083
|
+
| `done` | Dialog closed successfully (terminal for the pipeline) |
|
|
1084
|
+
| `error` | Dialog closed with a logic/runtime error |
|
|
1085
|
+
|
|
1086
|
+
The **host** also moves these statuses (live session → `pending`; shutdown without continuation → often `done` / `error`; automatic recall → `pending`; after-call chain → `null` + `entry_point` in params). Scripts set `platform.dialog.result` when they want to **explicitly** fix the LE dialog status (commonly `'done'` in a headless after-call handler). That does **not** replace `channel.sip.hangup()`.
|
|
1087
|
+
|
|
1088
|
+
#### Do not confuse
|
|
1089
|
+
|
|
1090
|
+
| API | Layer | Does | Does not |
|
|
1091
|
+
| --- | --- | --- | --- |
|
|
1092
|
+
| `platform.dialog.result` | LE `dialog` row | Lifecycle status (`done`, `pending`, …) | Hang up SIP; equal `call.result`; equal `ScriptResult.output` |
|
|
1093
|
+
| `platform.dialog.entryPoint` | LE `dialog.params` | Persist routing hint for later headless/queue runs | Change SIP state; select another script export |
|
|
1094
|
+
| `context.entryPoint` | `ScriptDialogContext` | **Snapshot** of `entry_point` at script start (`getScriptPhase`) | Persist if you assign it — write via `platform.dialog.entryPoint` |
|
|
1095
|
+
| `return { output }` / `ScriptResult` | Script return | dialog_stats / host dump | LE `dialog.result` column |
|
|
1096
|
+
| `channel.sip.hangup()` / `terminated$` | Media leg | End or observe SIP/WS media | Set `platform.dialog.result` by itself |
|
|
1097
|
+
| `call.result` (LE call row) | Per-call | SIP terminal code/phrase for CMS logs | Same as `dialog.result` |
|
|
1098
|
+
|
|
1099
|
+
There is no `context.result` field — read/write dialog lifecycle only through `platform.dialog.result`.
|
|
1100
|
+
|
|
1101
|
+
#### `entryPoint` write vs read
|
|
1102
|
+
|
|
1103
|
+
```ts
|
|
1104
|
+
// Persist routing for the next offline run (dialog.params.entry_point)
|
|
1105
|
+
platform.dialog.entryPoint = 'on_recall';
|
|
1106
|
+
|
|
1107
|
+
// Snapshot for this run — use with getScriptPhase(context)
|
|
1108
|
+
logger.log('branch', { entryPoint: context.entryPoint });
|
|
1109
|
+
```
|
|
1110
|
+
|
|
1111
|
+
`ScheduleCallOptions.entryPoint` on `platform.call()` is stored on the **call** row at schedule time — different from assigning `platform.dialog.entryPoint` mid-script.
|
|
1112
|
+
|
|
1113
|
+
#### Example
|
|
1114
|
+
|
|
935
1115
|
```ts
|
|
936
1116
|
platform.dialog.entryPoint = 'on_recall';
|
|
937
1117
|
platform.dialog.result = 'done';
|
|
938
1118
|
```
|
|
939
1119
|
|
|
940
|
-
Setters update the local value immediately and persist
|
|
1120
|
+
Setters update the local value immediately and persist asynchronously. They are not awaitable and should not be used as transactional writes. See [examples/after-call-continuation.ts](./examples/after-call-continuation.ts).
|
|
941
1121
|
|
|
942
1122
|
### Platform-Scheduled Calls
|
|
943
1123
|
|
|
@@ -956,23 +1136,10 @@ By default, the platform schedules the call for immediate processing. Use `date`
|
|
|
956
1136
|
```ts
|
|
957
1137
|
await platform.call('+12025551234', {
|
|
958
1138
|
date: new Date(Date.now() + 15 * 60_000),
|
|
959
|
-
entryPoint: 'on_callback',
|
|
960
1139
|
});
|
|
961
1140
|
```
|
|
962
1141
|
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
```ts
|
|
966
|
-
export default defineScript(async ({ context, channel }) => {
|
|
967
|
-
if (context.entryPoint === 'on_callback') {
|
|
968
|
-
channel.sip.answer();
|
|
969
|
-
await channel.audio.say('Hello, this is your scheduled callback.');
|
|
970
|
-
return;
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
await channel.audio.say('I will call you back in fifteen minutes.');
|
|
974
|
-
});
|
|
975
|
-
```
|
|
1142
|
+
When the scheduled call connects, the host runs your **`defineScript` export** again. Branch inside that handler if needed (there is no separate runtime entry per name, unlike logic-executor Python `run_unit(entry_point=...)`).
|
|
976
1143
|
|
|
977
1144
|
Use `dateEnd` to define the latest time when the call is still useful. If the platform cannot place the call before that deadline, it can skip the attempt.
|
|
978
1145
|
|
|
@@ -980,33 +1147,90 @@ Use `dateEnd` to define the latest time when the call is still useful. If the pl
|
|
|
980
1147
|
await platform.call('+12025551234', {
|
|
981
1148
|
date: new Date('2026-04-29T10:00:00Z'),
|
|
982
1149
|
dateEnd: new Date('2026-04-29T10:30:00Z'),
|
|
983
|
-
entryPoint: 'on_reminder',
|
|
984
1150
|
});
|
|
985
1151
|
```
|
|
986
1152
|
|
|
987
|
-
Retries are controlled with `recallCount` and `recallDelay
|
|
1153
|
+
Retries are controlled with `recallCount` and `recallDelay` (delay is always **seconds** in SDK options):
|
|
988
1154
|
|
|
989
1155
|
```ts
|
|
990
1156
|
await platform.call('+12025551234', {
|
|
991
|
-
entryPoint: 'on_follow_up',
|
|
992
1157
|
recallCount: 3,
|
|
993
|
-
recallDelay: 300,
|
|
1158
|
+
recallDelay: 300, // 5 minutes between failed outbound attempts
|
|
994
1159
|
});
|
|
995
1160
|
```
|
|
996
1161
|
|
|
997
|
-
This
|
|
1162
|
+
This schedules automatic redials: on each **failed outbound** the host creates a new platform call
|
|
1163
|
+
with `date_added = now + recallDelay`. The dialer runs the script again with an incremented
|
|
1164
|
+
`context.attempt`. See [examples/outbound-with-recall.ts](./examples/outbound-with-recall.ts).
|
|
1165
|
+
|
|
1166
|
+
### Failed outbound: automatic recall vs after-call continuation
|
|
1167
|
+
|
|
1168
|
+
After a failed **outbound** call the platform must choose **one** failure-handling strategy.
|
|
1169
|
+
`recallCount` + `recallDelay` and `onFailedCall` answer the same question in different ways, so
|
|
1170
|
+
they are **mutually exclusive** on `platform.call()` (logic-executor `nn.call` parity).
|
|
1171
|
+
|
|
1172
|
+
| Strategy | `platform.call()` options | What happens on failure | Next script run |
|
|
1173
|
+
|----------|---------------------------|-------------------------|-----------------|
|
|
1174
|
+
| **Automatic recall** | `recallCount` + `recallDelay` (both required on the `call` row) | Host schedules another outbound `call` after `recallDelay`; bumps `dialog.params.attempt` | **Online** SIP leg — same `defineScript`, branch on `context.attempt` |
|
|
1175
|
+
| **After-call continuation** | `onFailedCall` (and optionally `onSuccessCall`) | Host sets `dialog.params.entry_point` to the handler name and re-queues the dialog | **Headless** run — `getScriptPhase(context)` → `after_call_failed` |
|
|
1176
|
+
|
|
1177
|
+
**Why not both?** Recall is fully platform-driven (dialer redials without running your script between
|
|
1178
|
+
attempts). `onFailedCall` is script-driven (your handler decides logging, CRM, manual retry, etc.).
|
|
1179
|
+
If both were written to `call.params`, shutdown would be ambiguous. This host therefore **keeps
|
|
1180
|
+
`onFailedCall` and drops recall** at schedule time so the outbound still starts and the after-call
|
|
1181
|
+
branch runs on failure. (If both somehow land on an existing `call.params` row, recall still wins
|
|
1182
|
+
at shutdown — avoid writing both.)
|
|
998
1183
|
|
|
999
|
-
|
|
1000
|
-
(
|
|
1184
|
+
**Do not** pass `onFailedCall` together with `recallCount` and `recallDelay` in the same
|
|
1185
|
+
`platform.call()` invocation. If both are present (script options, dialog params, or CMS
|
|
1186
|
+
defaults), the host **keeps `onFailedCall` and drops recall** so the call still schedules —
|
|
1187
|
+
after-call continuation wins over automatic redial. Prefer configuring only one strategy
|
|
1188
|
+
explicitly.
|
|
1189
|
+
|
|
1190
|
+
**Host default resolution:** when you omit recall options, the host may default them from
|
|
1191
|
+
`context.recallCount` / `context.recallDelay` (CMS contact-rules). That auto-fill applies only when
|
|
1192
|
+
the script did **not** pass explicit `onFailedCall` in `platform.call()` options.
|
|
1193
|
+
`onFailedCall` / `onSuccessCall` are **never** invented from `dialog.params` or Omni
|
|
1194
|
+
`scheduleOutbound` defaults — they are script kwargs only (LE `nn.call` parity). Stale
|
|
1195
|
+
`on_failed_call` left in dialog params must not block CMS recall.
|
|
1196
|
+
|
|
1197
|
+
Diagram-style legacy outbound (Megafon converter) typically uses `onFailedCall` plus
|
|
1198
|
+
`on_failed_call_system` (sleep + call the main block again) — **not** CMS automatic recall.
|
|
1199
|
+
See [examples/after-call-continuation.ts](./examples/after-call-continuation.ts).
|
|
1200
|
+
|
|
1201
|
+
Use either automatic recall **or** offline `onFailedCall` continuation — not both on one scheduled
|
|
1202
|
+
outbound leg.
|
|
1203
|
+
|
|
1204
|
+
Branch inside the script on recall attempts (`context.attempt`, not a separate entry function):
|
|
1205
|
+
|
|
1206
|
+
```ts
|
|
1207
|
+
import { defineScript } from '@voctiv/agent-sdk';
|
|
1208
|
+
|
|
1209
|
+
export default defineScript(async ({ channel, context, logger }) => {
|
|
1210
|
+
channel.sip.answer();
|
|
1211
|
+
|
|
1212
|
+
if ((context.attempt ?? 0) > 0) {
|
|
1213
|
+
logger.log('Recall leg', { attempt: context.attempt });
|
|
1214
|
+
await channel.audio.say('Follow-up call. Please hold.');
|
|
1215
|
+
}
|
|
1216
|
+
});
|
|
1217
|
+
```
|
|
1218
|
+
|
|
1219
|
+
See [examples/recall-routing-by-attempt.ts](./examples/recall-routing-by-attempt.ts).
|
|
1220
|
+
|
|
1221
|
+
When you omit recall options, the host fills them from `context.recallCount` / `context.recallDelay`
|
|
1222
|
+
(effective values for the current dialog) **only when `onFailedCall` is not configured** for that
|
|
1223
|
+
scheduled call. Those values fall back to CMS agent contact-rules
|
|
1001
1224
|
(`context.agent?.recallCount` / `context.agent?.recallDelay`, legacy `nn.get_recall_count()` /
|
|
1002
|
-
`nn.get_recall_delay()`).
|
|
1225
|
+
`nn.get_recall_delay()`). See [Failed outbound: automatic recall vs after-call continuation](#failed-outbound-automatic-recall-vs-after-call-continuation).
|
|
1003
1226
|
|
|
1004
1227
|
Other scheduling options:
|
|
1005
1228
|
|
|
1006
1229
|
- `priority`: higher-priority calls can be processed earlier by the dialer.
|
|
1007
1230
|
- `timezone`: timezone offset used by the platform when interpreting scheduled dates.
|
|
1008
|
-
- `onSuccessCall`:
|
|
1009
|
-
- `onFailedCall`:
|
|
1231
|
+
- `onSuccessCall`: headless handler name after a successful call (e.g. `'on_success_call'` → `getScriptPhase` `'after_call_success'`).
|
|
1232
|
+
- `onFailedCall`: headless handler name after failed attempts (mutually exclusive with recall).
|
|
1233
|
+
- `entryPoint` (optional): stored as `entry_point` in call params for LE DB compatibility. The host still runs the same `defineScript` export; use `context.entryPoint` only if **you** branch on it inside the handler.
|
|
1010
1234
|
- `protoAdditional`: extra protocol-level parameters, such as SIP headers expected by your telephony setup.
|
|
1011
1235
|
|
|
1012
1236
|
### Messaging
|
|
@@ -1025,9 +1249,14 @@ await platform.messaging.send({
|
|
|
1025
1249
|
|
|
1026
1250
|
Offline, or headless, sessions run a script without a live SIP call, WebSocket audio stream, RTP pipeline, ASR, or TTS playback. They are used for platform-driven background logic, queued dialog processing, and messaging events.
|
|
1027
1251
|
|
|
1028
|
-
The script entry point is still the same `defineScript()` handler. Detect
|
|
1252
|
+
The script entry point is still the same `defineScript()` handler. Detect offline mode with
|
|
1253
|
+
`context.headless`, then use **`getScriptPhase(context)`** to distinguish pre-call queue runs
|
|
1254
|
+
(`before_call`) from post-call continuations (`after_call_success` / `after_call_failed`). See
|
|
1255
|
+
[Script Lifecycle (`getScriptPhase`)](#script-lifecycle-getscriptphase).
|
|
1029
1256
|
|
|
1030
1257
|
```ts
|
|
1258
|
+
import { defineScript, getScriptPhase } from '@voctiv/agent-sdk';
|
|
1259
|
+
|
|
1031
1260
|
export default defineScript(async ({ channel, context, logger, platform }) => {
|
|
1032
1261
|
if (!context.headless) {
|
|
1033
1262
|
channel.sip.answer();
|
|
@@ -1035,12 +1264,24 @@ export default defineScript(async ({ channel, context, logger, platform }) => {
|
|
|
1035
1264
|
return;
|
|
1036
1265
|
}
|
|
1037
1266
|
|
|
1267
|
+
const phase = getScriptPhase(context);
|
|
1038
1268
|
logger.log('Running offline logic', {
|
|
1269
|
+
phase,
|
|
1039
1270
|
dialogUuid: context.dialogUuid,
|
|
1040
1271
|
entryPoint: context.entryPoint,
|
|
1041
1272
|
});
|
|
1042
1273
|
|
|
1043
|
-
|
|
1274
|
+
if (phase === 'before_call') {
|
|
1275
|
+
await platform.call(context.msisdn!);
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
if (phase === 'after_call_success' || phase === 'after_call_failed') {
|
|
1280
|
+
// Post-call headless branch — see examples/after-call-continuation.ts
|
|
1281
|
+
return { output: { phase } };
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
// messaging, headless_other, etc.
|
|
1044
1285
|
});
|
|
1045
1286
|
```
|
|
1046
1287
|
|
|
@@ -1143,9 +1384,7 @@ export default defineScript(async ({ channel, context, platform }) => {
|
|
|
1143
1384
|
const text = String(context.inboundMessage?.payload?.text ?? '');
|
|
1144
1385
|
|
|
1145
1386
|
if (text.includes('call me')) {
|
|
1146
|
-
await platform.call(context.msisdn
|
|
1147
|
-
entryPoint: 'on_callback',
|
|
1148
|
-
});
|
|
1387
|
+
await platform.call(context.msisdn);
|
|
1149
1388
|
}
|
|
1150
1389
|
|
|
1151
1390
|
return { output: { handledOffline: true } };
|
|
@@ -1182,19 +1421,25 @@ Recall behavior uses **two layers** on `context`:
|
|
|
1182
1421
|
| Layer | Fields | Source | Use when |
|
|
1183
1422
|
|-------|--------|--------|----------|
|
|
1184
1423
|
| Agent defaults | `context.agent?.recallCount`, `context.agent?.recallDelay` | CMS contact-rules (`agent.recall_count`, `agent.delay` → seconds) | Compare with CMS settings; legacy `nn.get_recall_count()` / `get_recall_delay()` parity |
|
|
1185
|
-
| Effective for this run | `context.recallCount`, `context.recallDelay` | `dialog.params` / `call.params`, then agent defaults |
|
|
1424
|
+
| Effective for this run | `context.recallCount`, `context.recallDelay` | `dialog.params` / `call.params`, then agent defaults | Read in script; pass explicitly to `platform.call()` when using **automatic recall** |
|
|
1186
1425
|
|
|
1187
1426
|
Precedence for effective values: **dialog/call params** (`recall_count`, `recall_delay`) **>** agent CMS defaults.
|
|
1188
1427
|
|
|
1428
|
+
**Important:** CMS/effective recall on `context` does **not** mean every `platform.call()` gets
|
|
1429
|
+
automatic recall. The host copies recall onto the scheduled `call` row only when you omit recall
|
|
1430
|
+
options **and** `onFailedCall` is not configured (see
|
|
1431
|
+
[Failed outbound: automatic recall vs after-call continuation](#failed-outbound-automatic-recall-vs-after-call-continuation)).
|
|
1432
|
+
Agents with both CMS contact-rules and diagram `on_failed_call` handlers use the after-call path;
|
|
1433
|
+
recall fields on `context` are informational unless your script passes them explicitly.
|
|
1434
|
+
|
|
1189
1435
|
`context.attempt` is the current recall attempt counter from `dialog.params.attempt` (starts at 0).
|
|
1190
|
-
`context.entryPoint` is the routing branch for this run (
|
|
1436
|
+
`context.entryPoint` is the routing branch **snapshot** for this run (from `dialog.params.entry_point` at start). To persist a new value, assign `platform.dialog.entryPoint` — see [Dialog State](#dialog-state).
|
|
1191
1437
|
|
|
1192
1438
|
```ts
|
|
1193
1439
|
// Use effective values when scheduling the next outbound leg
|
|
1194
|
-
await
|
|
1440
|
+
await platform.call(context.msisdn!, {
|
|
1195
1441
|
recallCount: context.recallCount,
|
|
1196
1442
|
recallDelay: context.recallDelay,
|
|
1197
|
-
entryPoint: 'on_follow_up',
|
|
1198
1443
|
});
|
|
1199
1444
|
|
|
1200
1445
|
// Log CMS defaults vs per-dialog override
|
|
@@ -1235,14 +1480,16 @@ Important fields:
|
|
|
1235
1480
|
- `context.flag`: business flag.
|
|
1236
1481
|
- `context.initialData`: shallow snapshot of params at script start.
|
|
1237
1482
|
- `context.dialogParams`: live param map for the run.
|
|
1238
|
-
- `context.entryPoint`:
|
|
1239
|
-
- `context.attempt`: current recall attempt number (`dialog.params.attempt`).
|
|
1483
|
+
- `context.entryPoint`: routing entry point **snapshot** at script start (see [Script Lifecycle](#script-lifecycle-getscriptphase)); persist changes via `platform.dialog.entryPoint`.
|
|
1484
|
+
- `context.attempt`: current recall attempt number (`dialog.params.attempt`; use with `phase === 'online'`).
|
|
1240
1485
|
- `context.recallCount` / `context.recallDelay`: effective recall settings for this dialog/call.
|
|
1241
1486
|
- `context.agent?.recallCount` / `context.agent?.recallDelay`: CMS agent defaults (immutable snapshot).
|
|
1242
1487
|
- `context.headless`: true for offline/queue/messaging sessions without a real media channel.
|
|
1243
1488
|
- `context.runTime`: async execution budget helper.
|
|
1244
1489
|
- `context.env$`: persisted dialog environment as an RxJS `BehaviorSubject`.
|
|
1245
1490
|
|
|
1491
|
+
Dialog lifecycle status (`dialog.result`) is **not** on `context` — use `platform.dialog.result` ([Dialog State](#dialog-state)).
|
|
1492
|
+
|
|
1246
1493
|
Use `env$` for persisted script state:
|
|
1247
1494
|
|
|
1248
1495
|
```ts
|
|
@@ -1278,11 +1525,15 @@ WS channels behave like active media channels:
|
|
|
1278
1525
|
Headless channels are for offline, queue, or messaging sessions:
|
|
1279
1526
|
|
|
1280
1527
|
- Audio methods are no-ops that log warnings.
|
|
1281
|
-
- SIP methods are
|
|
1282
|
-
-
|
|
1528
|
+
- SIP methods are no-ops, except `makeCall()` and `bridge()`, which throw: there is no real leg to
|
|
1529
|
+
create, and a silent no-op would hide the mistake.
|
|
1530
|
+
- `createAsr()` returns an inert handle whose observables complete immediately.
|
|
1283
1531
|
- LLM, NLU, messaging, platform calls, dialog state, and `env$` still work.
|
|
1284
1532
|
|
|
1285
|
-
Use `context.headless`
|
|
1533
|
+
Use `context.headless` plus `getScriptPhase(context)` when a script must behave differently without a
|
|
1534
|
+
real media channel or across pre-call / post-call headless runs. See
|
|
1535
|
+
[Offline / Headless Logic](#offline--headless-logic) and
|
|
1536
|
+
[Script Lifecycle (`getScriptPhase`)](#script-lifecycle-getscriptphase).
|
|
1286
1537
|
|
|
1287
1538
|
## Text Input For Tests
|
|
1288
1539
|
|
package/dist/index.d.ts
CHANGED
|
@@ -33,6 +33,7 @@ export type { ScriptDialogContext, ScriptPhase, ScriptRunTime, ScriptResult, Per
|
|
|
33
33
|
export { getScriptPhase } from './types/script-context';
|
|
34
34
|
export type { NluScriptApi, PlatformApi, DialogApi, ScheduleCallOptions, SendMessageOptions, InboundMessage, MessagingApi, } from './types/platform';
|
|
35
35
|
export type { ScriptLogger } from './types/logger';
|
|
36
|
+
export { TranscriptionRole } from './types/logger';
|
|
36
37
|
export type { MediaChannel, ChannelAudio, ChannelEvents, } from './types/media-channel';
|
|
37
38
|
export type { ChannelLlm, LlmOptions, LlmStreamChunk, ExtractOptions, PersistentLlmStreamHandle, } from './types/llm';
|
|
38
39
|
export type { ChannelSip, SipState, SipProgressEvent, SipInviteHeaders, ParsedSdpDetails, } from './types/sip';
|
|
@@ -44,4 +45,5 @@ export { LEGACY_PHRASE_RECORD_BRAND, isLegacyPhraseRecord, } from './types/legac
|
|
|
44
45
|
export type { TextInput } from './types/text-input';
|
|
45
46
|
export type { DtmfEvent, SipInfo, SipSignal, DataMessage, } from './types/events';
|
|
46
47
|
export type { NluExtractOptions, NluInferResult } from './types/nlu';
|
|
48
|
+
export { parseRecallCount, parseRecallDelaySeconds } from './recall-utils';
|
|
47
49
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE/D,YAAY,EACV,mBAAmB,EACnB,WAAW,EACX,aAAa,EACb,YAAY,EACZ,qBAAqB,EACrB,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,YAAY,EACV,YAAY,EACZ,WAAW,EACX,SAAS,EACT,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,YAAY,GACb,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,cAAc,EACd,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,UAAU,EACV,QAAQ,EACR,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACjG,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC3H,YAAY,EACV,kBAAkB,EAClB,sBAAsB,EACtB,YAAY,GACb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,0BAA0B,EAC1B,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,YAAY,EACV,SAAS,EACT,OAAO,EACP,SAAS,EACT,WAAW,GACZ,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE/D,YAAY,EACV,mBAAmB,EACnB,WAAW,EACX,aAAa,EACb,YAAY,EACZ,qBAAqB,EACrB,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,YAAY,EACV,YAAY,EACZ,WAAW,EACX,SAAS,EACT,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,YAAY,GACb,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,cAAc,EACd,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,UAAU,EACV,QAAQ,EACR,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACjG,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC3H,YAAY,EACV,kBAAkB,EAClB,sBAAsB,EACtB,YAAY,GACb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,0BAA0B,EAC1B,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,YAAY,EACV,SAAS,EACT,OAAO,EACP,SAAS,EACT,WAAW,GACZ,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -29,12 +29,17 @@
|
|
|
29
29
|
* and live SIP INFO ({@link import('./types/events').SipInfo} on `sipInfo$`). See **`README.md`** → SIP Signalling Metadata.
|
|
30
30
|
*/
|
|
31
31
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
-
exports.isLegacyPhraseRecord = exports.LEGACY_PHRASE_RECORD_BRAND = exports.getScriptPhase = exports.defineScript = void 0;
|
|
32
|
+
exports.parseRecallDelaySeconds = exports.parseRecallCount = exports.isLegacyPhraseRecord = exports.LEGACY_PHRASE_RECORD_BRAND = exports.TranscriptionRole = exports.getScriptPhase = exports.defineScript = void 0;
|
|
33
33
|
var define_script_1 = require("./define-script");
|
|
34
34
|
Object.defineProperty(exports, "defineScript", { enumerable: true, get: function () { return define_script_1.defineScript; } });
|
|
35
35
|
var script_context_1 = require("./types/script-context");
|
|
36
36
|
Object.defineProperty(exports, "getScriptPhase", { enumerable: true, get: function () { return script_context_1.getScriptPhase; } });
|
|
37
|
+
var logger_1 = require("./types/logger");
|
|
38
|
+
Object.defineProperty(exports, "TranscriptionRole", { enumerable: true, get: function () { return logger_1.TranscriptionRole; } });
|
|
37
39
|
var legacy_phrase_1 = require("./types/legacy-phrase");
|
|
38
40
|
Object.defineProperty(exports, "LEGACY_PHRASE_RECORD_BRAND", { enumerable: true, get: function () { return legacy_phrase_1.LEGACY_PHRASE_RECORD_BRAND; } });
|
|
39
41
|
Object.defineProperty(exports, "isLegacyPhraseRecord", { enumerable: true, get: function () { return legacy_phrase_1.isLegacyPhraseRecord; } });
|
|
42
|
+
var recall_utils_1 = require("./recall-utils");
|
|
43
|
+
Object.defineProperty(exports, "parseRecallCount", { enumerable: true, get: function () { return recall_utils_1.parseRecallCount; } });
|
|
44
|
+
Object.defineProperty(exports, "parseRecallDelaySeconds", { enumerable: true, get: function () { return recall_utils_1.parseRecallDelaySeconds; } });
|
|
40
45
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;;;AAEH,iDAA+C;AAAtC,6GAAA,YAAY,OAAA;AAerB,yDAAwD;AAA/C,gHAAA,cAAc,OAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;;;AAEH,iDAA+C;AAAtC,6GAAA,YAAY,OAAA;AAerB,yDAAwD;AAA/C,gHAAA,cAAc,OAAA;AAavB,yCAAmD;AAA1C,2GAAA,iBAAiB,OAAA;AAgC1B,uDAG+B;AAF7B,2HAAA,0BAA0B,OAAA;AAC1B,qHAAA,oBAAoB,OAAA;AAUtB,+CAA2E;AAAlE,gHAAA,gBAAgB,OAAA;AAAE,uHAAA,uBAAuB,OAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse recall delay to seconds — parity with logic-executor `agent.delay` / `recall_delay`
|
|
3
|
+
* in call params (`HH:mm:ss`, integer seconds).
|
|
4
|
+
*/
|
|
5
|
+
export declare function parseRecallDelaySeconds(value: unknown): number | undefined;
|
|
6
|
+
/** Parse recall attempt limit from call/dialog params. */
|
|
7
|
+
export declare function parseRecallCount(value: unknown): number | undefined;
|
|
8
|
+
//# sourceMappingURL=recall-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recall-utils.d.ts","sourceRoot":"","sources":["../src/recall-utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CA4B1E;AAED,0DAA0D;AAC1D,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAWnE"}
|