twilio-agent-connect 2.2.0 → 2.4.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 +15 -0
- package/dist/index.d.ts +2353 -619
- package/dist/index.js +3529 -746
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { z } from 'zod';
|
|
|
3
3
|
import pino from 'pino';
|
|
4
4
|
import { AxiosInstance } from 'axios';
|
|
5
5
|
import { WebSocket } from 'ws';
|
|
6
|
+
import Twilio from 'twilio';
|
|
6
7
|
import VoiceResponse from 'twilio/lib/twiml/VoiceResponse.js';
|
|
7
8
|
import { CallListInstanceCreateOptions } from 'twilio/lib/rest/api/v2010/account/call.js';
|
|
8
9
|
import { FastifyInstance, FastifyServerOptions } from 'fastify';
|
|
@@ -1649,6 +1650,19 @@ declare const InterruptMessageSchema: z.ZodObject<{
|
|
|
1649
1650
|
durationUntilInterruptMs: z.ZodOptional<z.ZodNumber>;
|
|
1650
1651
|
}, z.core.$strip>;
|
|
1651
1652
|
type InterruptMessage = z.infer<typeof InterruptMessageSchema>;
|
|
1653
|
+
/**
|
|
1654
|
+
* WebSocket DTMF message (caller pressed a key).
|
|
1655
|
+
*
|
|
1656
|
+
* Only sent when `dtmfDetection` is enabled on `<ConversationRelay>`, and one
|
|
1657
|
+
* message per keypress — digits are never batched.
|
|
1658
|
+
*
|
|
1659
|
+
* @see https://www.twilio.com/docs/voice/conversationrelay/websocket-messages#dtmf-message
|
|
1660
|
+
*/
|
|
1661
|
+
declare const DtmfMessageSchema: z.ZodObject<{
|
|
1662
|
+
type: z.ZodLiteral<"dtmf">;
|
|
1663
|
+
digit: z.ZodString;
|
|
1664
|
+
}, z.core.$strip>;
|
|
1665
|
+
type DtmfMessage = z.infer<typeof DtmfMessageSchema>;
|
|
1652
1666
|
/**
|
|
1653
1667
|
* Union of all WebSocket message types
|
|
1654
1668
|
*/
|
|
@@ -1676,6 +1690,9 @@ declare const WebSocketMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
1676
1690
|
type: z.ZodLiteral<"interrupt">;
|
|
1677
1691
|
utteranceUntilInterrupt: z.ZodOptional<z.ZodString>;
|
|
1678
1692
|
durationUntilInterruptMs: z.ZodOptional<z.ZodNumber>;
|
|
1693
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1694
|
+
type: z.ZodLiteral<"dtmf">;
|
|
1695
|
+
digit: z.ZodString;
|
|
1679
1696
|
}, z.core.$strip>]>;
|
|
1680
1697
|
type WebSocketMessage = z.infer<typeof WebSocketMessageSchema>;
|
|
1681
1698
|
/**
|
|
@@ -1721,7 +1738,8 @@ type InterruptMode = z.infer<typeof InterruptModeSchema>;
|
|
|
1721
1738
|
*
|
|
1722
1739
|
* Distinct from {@link LanguageAttributes} (the Twilio-SDK-shaped type used by
|
|
1723
1740
|
* `connectConversationRelay`): this is the customization-facing model used in
|
|
1724
|
-
* {@link
|
|
1741
|
+
* {@link VoiceTwiMLOptionsConversationRelay}, mirroring the Python SDK's
|
|
1742
|
+
* `LanguageConfig`.
|
|
1725
1743
|
*/
|
|
1726
1744
|
declare const LanguageConfigSchema: z.ZodObject<{
|
|
1727
1745
|
code: z.ZodString;
|
|
@@ -1731,6 +1749,25 @@ declare const LanguageConfigSchema: z.ZodObject<{
|
|
|
1731
1749
|
speechModel: z.ZodOptional<z.ZodString>;
|
|
1732
1750
|
}, z.core.$strip>;
|
|
1733
1751
|
type LanguageConfig = z.infer<typeof LanguageConfigSchema>;
|
|
1752
|
+
/**
|
|
1753
|
+
* Provider-agnostic base for a voice provider's inbound-call TwiML
|
|
1754
|
+
* customization options.
|
|
1755
|
+
*
|
|
1756
|
+
* Each provider answers the inbound-call webhook with its own TwiML shape
|
|
1757
|
+
* ({@link VoiceTwiMLOptionsConversationRelaySchema} for `<ConversationRelay>`,
|
|
1758
|
+
* {@link VoiceTwiMLOptionsMediaStreamsSchema} for `<Connect><Stream>`), so
|
|
1759
|
+
* `VoiceProvider.handleIncomingCall`'s
|
|
1760
|
+
* `hostTwimlOptions` is typed against this base rather than a specific
|
|
1761
|
+
* provider's options. It carries only what every provider shares: the
|
|
1762
|
+
* `<Connect action>` URL, the transport URL, and `<Parameter>` children.
|
|
1763
|
+
*
|
|
1764
|
+
* Mirrors the Python SDK's `VoiceTwiMLOptions`.
|
|
1765
|
+
*/
|
|
1766
|
+
declare const VoiceTwiMLOptionsSchema: z.ZodObject<{
|
|
1767
|
+
customParameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1768
|
+
actionUrl: z.ZodOptional<z.ZodString>;
|
|
1769
|
+
websocketUrl: z.ZodOptional<z.ZodString>;
|
|
1770
|
+
}, z.core.$strict>;
|
|
1734
1771
|
/**
|
|
1735
1772
|
* Options for the TwiML inside `<ConversationRelay>` (plus the
|
|
1736
1773
|
* `<Connect action>` URL).
|
|
@@ -1743,10 +1780,12 @@ type LanguageConfig = z.infer<typeof LanguageConfigSchema>;
|
|
|
1743
1780
|
*
|
|
1744
1781
|
* This is the customization-facing counterpart to {@link ConversationRelayConfig}
|
|
1745
1782
|
* (which is the Twilio-SDK-shaped emit model and carries the required `url`).
|
|
1746
|
-
* Mirrors the Python SDK's `
|
|
1783
|
+
* Mirrors the Python SDK's `VoiceTwiMLOptionsConversationRelay`.
|
|
1747
1784
|
*/
|
|
1748
|
-
declare const
|
|
1785
|
+
declare const VoiceTwiMLOptionsConversationRelaySchema: z.ZodObject<{
|
|
1749
1786
|
customParameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1787
|
+
actionUrl: z.ZodOptional<z.ZodString>;
|
|
1788
|
+
websocketUrl: z.ZodOptional<z.ZodString>;
|
|
1750
1789
|
welcomeGreeting: z.ZodOptional<z.ZodString>;
|
|
1751
1790
|
welcomeGreetingInterruptible: z.ZodOptional<z.ZodEnum<{
|
|
1752
1791
|
any: "any";
|
|
@@ -1754,9 +1793,108 @@ declare const TwiMLOptionsSchema: z.ZodObject<{
|
|
|
1754
1793
|
none: "none";
|
|
1755
1794
|
dtmf: "dtmf";
|
|
1756
1795
|
}>>;
|
|
1757
|
-
actionUrl: z.ZodOptional<z.ZodString>;
|
|
1758
1796
|
conversationConfiguration: z.ZodOptional<z.ZodString>;
|
|
1797
|
+
language: z.ZodOptional<z.ZodString>;
|
|
1798
|
+
ttsLanguage: z.ZodOptional<z.ZodString>;
|
|
1799
|
+
transcriptionLanguage: z.ZodOptional<z.ZodString>;
|
|
1800
|
+
voice: z.ZodOptional<z.ZodString>;
|
|
1801
|
+
ttsProvider: z.ZodOptional<z.ZodString>;
|
|
1802
|
+
transcriptionProvider: z.ZodOptional<z.ZodString>;
|
|
1803
|
+
speechModel: z.ZodOptional<z.ZodString>;
|
|
1804
|
+
elevenlabsTextNormalization: z.ZodOptional<z.ZodEnum<{
|
|
1805
|
+
on: "on";
|
|
1806
|
+
auto: "auto";
|
|
1807
|
+
off: "off";
|
|
1808
|
+
}>>;
|
|
1809
|
+
eotThreshold: z.ZodOptional<z.ZodNumber>;
|
|
1810
|
+
partialPrompts: z.ZodOptional<z.ZodBoolean>;
|
|
1811
|
+
deepgramSmartFormat: z.ZodOptional<z.ZodBoolean>;
|
|
1812
|
+
speechTimeout: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodLiteral<"auto">]>>;
|
|
1813
|
+
interruptible: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
1814
|
+
any: "any";
|
|
1815
|
+
speech: "speech";
|
|
1816
|
+
none: "none";
|
|
1817
|
+
dtmf: "dtmf";
|
|
1818
|
+
}>, z.ZodBoolean]>>;
|
|
1819
|
+
interruptSensitivity: z.ZodOptional<z.ZodEnum<{
|
|
1820
|
+
low: "low";
|
|
1821
|
+
medium: "medium";
|
|
1822
|
+
high: "high";
|
|
1823
|
+
}>>;
|
|
1824
|
+
reportInputDuringAgentSpeech: z.ZodOptional<z.ZodEnum<{
|
|
1825
|
+
any: "any";
|
|
1826
|
+
speech: "speech";
|
|
1827
|
+
none: "none";
|
|
1828
|
+
dtmf: "dtmf";
|
|
1829
|
+
}>>;
|
|
1830
|
+
ignoreBackchannel: z.ZodOptional<z.ZodBoolean>;
|
|
1831
|
+
preemptible: z.ZodOptional<z.ZodBoolean>;
|
|
1832
|
+
dtmfDetection: z.ZodOptional<z.ZodBoolean>;
|
|
1833
|
+
hints: z.ZodOptional<z.ZodString>;
|
|
1834
|
+
events: z.ZodOptional<z.ZodString>;
|
|
1835
|
+
debug: z.ZodOptional<z.ZodString>;
|
|
1836
|
+
intelligenceService: z.ZodOptional<z.ZodString>;
|
|
1837
|
+
languages: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
1838
|
+
code: z.ZodString;
|
|
1839
|
+
voice: z.ZodOptional<z.ZodString>;
|
|
1840
|
+
ttsProvider: z.ZodOptional<z.ZodString>;
|
|
1841
|
+
transcriptionProvider: z.ZodOptional<z.ZodString>;
|
|
1842
|
+
speechModel: z.ZodOptional<z.ZodString>;
|
|
1843
|
+
}, z.core.$strip>>>;
|
|
1844
|
+
extra: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodBoolean, z.ZodNumber]>>>;
|
|
1845
|
+
}, z.core.$strict>;
|
|
1846
|
+
type VoiceTwiMLOptions = z.infer<typeof VoiceTwiMLOptionsSchema>;
|
|
1847
|
+
type VoiceTwiMLOptionsConversationRelay = z.infer<typeof VoiceTwiMLOptionsConversationRelaySchema>;
|
|
1848
|
+
/**
|
|
1849
|
+
* Options for the TwiML inside `<Connect><Stream>`.
|
|
1850
|
+
*
|
|
1851
|
+
* Fields map to the attributes documented at
|
|
1852
|
+
* https://www.twilio.com/docs/voice/twiml/stream (the `<Stream>` verb) and
|
|
1853
|
+
* https://www.twilio.com/docs/voice/twiml/connect (the `<Connect>` verb it is
|
|
1854
|
+
* nested in). `track` is deliberately absent: a bidirectional `<Connect>`
|
|
1855
|
+
* stream only ever carries `inbound_track`, so it is not settable.
|
|
1856
|
+
*
|
|
1857
|
+
* Inherits `customParameters`, `actionUrl` and `websocketUrl` from the shared
|
|
1858
|
+
* base. Mirrors the Python SDK's `VoiceTwiMLOptionsMediaStreams`.
|
|
1859
|
+
*/
|
|
1860
|
+
declare const VoiceTwiMLOptionsMediaStreamsSchema: z.ZodObject<{
|
|
1861
|
+
customParameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1862
|
+
actionUrl: z.ZodOptional<z.ZodString>;
|
|
1863
|
+
websocketUrl: z.ZodOptional<z.ZodString>;
|
|
1864
|
+
name: z.ZodOptional<z.ZodString>;
|
|
1865
|
+
statusCallback: z.ZodOptional<z.ZodString>;
|
|
1866
|
+
statusCallbackMethod: z.ZodOptional<z.ZodEnum<{
|
|
1867
|
+
POST: "POST";
|
|
1868
|
+
GET: "GET";
|
|
1869
|
+
}>>;
|
|
1870
|
+
actionMethod: z.ZodOptional<z.ZodEnum<{
|
|
1871
|
+
POST: "POST";
|
|
1872
|
+
GET: "GET";
|
|
1873
|
+
}>>;
|
|
1874
|
+
}, z.core.$strict>;
|
|
1875
|
+
type VoiceTwiMLOptionsMediaStreams = z.infer<typeof VoiceTwiMLOptionsMediaStreamsSchema>;
|
|
1876
|
+
/** @deprecated Use {@link VoiceTwiMLOptionsConversationRelay} instead. */
|
|
1877
|
+
type TwiMLOptions = VoiceTwiMLOptionsConversationRelay;
|
|
1878
|
+
/**
|
|
1879
|
+
* Unlike Python, this emits no runtime warning. It is a plain alias so that
|
|
1880
|
+
* `TwiMLOptionsSchema === VoiceTwiMLOptionsConversationRelaySchema`; wrapping it
|
|
1881
|
+
* in a warning proxy would break that identity, and callers commonly compare or
|
|
1882
|
+
* `.extend()` the schema.
|
|
1883
|
+
*
|
|
1884
|
+
* @deprecated Use {@link VoiceTwiMLOptionsConversationRelaySchema} instead.
|
|
1885
|
+
*/
|
|
1886
|
+
declare const TwiMLOptionsSchema: z.ZodObject<{
|
|
1887
|
+
customParameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1888
|
+
actionUrl: z.ZodOptional<z.ZodString>;
|
|
1759
1889
|
websocketUrl: z.ZodOptional<z.ZodString>;
|
|
1890
|
+
welcomeGreeting: z.ZodOptional<z.ZodString>;
|
|
1891
|
+
welcomeGreetingInterruptible: z.ZodOptional<z.ZodEnum<{
|
|
1892
|
+
any: "any";
|
|
1893
|
+
speech: "speech";
|
|
1894
|
+
none: "none";
|
|
1895
|
+
dtmf: "dtmf";
|
|
1896
|
+
}>>;
|
|
1897
|
+
conversationConfiguration: z.ZodOptional<z.ZodString>;
|
|
1760
1898
|
language: z.ZodOptional<z.ZodString>;
|
|
1761
1899
|
ttsLanguage: z.ZodOptional<z.ZodString>;
|
|
1762
1900
|
transcriptionLanguage: z.ZodOptional<z.ZodString>;
|
|
@@ -1806,13 +1944,12 @@ declare const TwiMLOptionsSchema: z.ZodObject<{
|
|
|
1806
1944
|
}, z.core.$strip>>>;
|
|
1807
1945
|
extra: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodBoolean, z.ZodNumber]>>>;
|
|
1808
1946
|
}, z.core.$strict>;
|
|
1809
|
-
type TwiMLOptions = z.infer<typeof TwiMLOptionsSchema>;
|
|
1810
1947
|
/**
|
|
1811
1948
|
* Framework-neutral view of the Twilio TwiML webhook form.
|
|
1812
1949
|
*
|
|
1813
1950
|
* Populated by `TACServer` from the incoming Twilio webhook, then passed to a
|
|
1814
1951
|
* customizer registered via `VoiceChannel.onInboundCallTwiml(...)` so the
|
|
1815
|
-
* application can produce per-call {@link
|
|
1952
|
+
* application can produce per-call {@link VoiceTwiMLOptions} overrides without
|
|
1816
1953
|
* depending on Fastify types. Mirrors the Python SDK's `TwiMLRequest`.
|
|
1817
1954
|
*/
|
|
1818
1955
|
declare const TwiMLRequestSchema: z.ZodObject<{
|
|
@@ -1871,6 +2008,12 @@ declare const ConversationRelayCallbackPayloadSchema: z.ZodObject<{
|
|
|
1871
2008
|
SessionDuration: z.ZodOptional<z.ZodString>;
|
|
1872
2009
|
}, z.core.$strip>;
|
|
1873
2010
|
type ConversationRelayCallbackPayload = z.infer<typeof ConversationRelayCallbackPayloadSchema>;
|
|
2011
|
+
/** HTTP response a provider's out-of-band lifecycle webhook handler produces. */
|
|
2012
|
+
interface TwilioProviderCallbackResponse {
|
|
2013
|
+
status: number;
|
|
2014
|
+
content: string;
|
|
2015
|
+
contentType: string;
|
|
2016
|
+
}
|
|
1874
2017
|
/**
|
|
1875
2018
|
* A Twilio `statusCallback` webhook — call progress and disposition.
|
|
1876
2019
|
*
|
|
@@ -2105,10 +2248,17 @@ interface InitiateVoiceConversationOptions {
|
|
|
2105
2248
|
*/
|
|
2106
2249
|
websocketUrl?: string | undefined;
|
|
2107
2250
|
/**
|
|
2108
|
-
* Per-call overrides for the TwiML
|
|
2251
|
+
* Per-call overrides for the outbound TwiML. Merged over
|
|
2109
2252
|
* `VoiceChannelConfig.defaultTwimlOptions` and TAC defaults.
|
|
2253
|
+
*
|
|
2254
|
+
* A union of the provider subtypes rather than the provider-agnostic base:
|
|
2255
|
+
* the base type carries only the three shared fields, so TypeScript's
|
|
2256
|
+
* excess-property check would reject a fresh object literal carrying any
|
|
2257
|
+
* provider-specific field. Each provider still parses this against its own
|
|
2258
|
+
* schema at the channel boundary, so passing the wrong subtype for the
|
|
2259
|
+
* configured provider fails at runtime.
|
|
2110
2260
|
*/
|
|
2111
|
-
twimlOptions?:
|
|
2261
|
+
twimlOptions?: VoiceTwiMLOptionsConversationRelay | VoiceTwiMLOptionsMediaStreams | undefined;
|
|
2112
2262
|
/**
|
|
2113
2263
|
* Parameters for Twilio's `calls.create()` — AMD, recording, status
|
|
2114
2264
|
* callbacks, timeout (see {@link CallOptions}). Callback URLs auto-wire when
|
|
@@ -2116,7 +2266,94 @@ interface InitiateVoiceConversationOptions {
|
|
|
2116
2266
|
*/
|
|
2117
2267
|
callOptions?: CallOptions | undefined;
|
|
2118
2268
|
}
|
|
2269
|
+
/**
|
|
2270
|
+
* Validates outbound options for `ConversationRelayProvider`.
|
|
2271
|
+
*
|
|
2272
|
+
* Despite the union on {@link InitiateVoiceConversationOptions.twimlOptions},
|
|
2273
|
+
* this schema accepts only the ConversationRelay subtype — use
|
|
2274
|
+
* {@link InitiateVoiceConversationOptionsOpenAIRealtimeSchema} for
|
|
2275
|
+
* `<Connect><Stream>`.
|
|
2276
|
+
*/
|
|
2119
2277
|
declare const InitiateVoiceConversationOptionsSchema: z.ZodType<InitiateVoiceConversationOptions>;
|
|
2278
|
+
/**
|
|
2279
|
+
* Outbound options for `OpenAIRealtimeProvider`, adding a per-call
|
|
2280
|
+
* `sessionConfig` on top of {@link InitiateVoiceConversationOptionsSchema}.
|
|
2281
|
+
* Also narrows `twimlOptions` to {@link VoiceTwiMLOptionsMediaStreamsSchema}.
|
|
2282
|
+
*
|
|
2283
|
+
* Mirrors the Python SDK's `InitiateVoiceConversationOptionsOpenAIRealtime`.
|
|
2284
|
+
*/
|
|
2285
|
+
declare const InitiateVoiceConversationOptionsOpenAIRealtimeSchema: z.ZodObject<{
|
|
2286
|
+
to: z.ZodString;
|
|
2287
|
+
websocketUrl: z.ZodOptional<z.ZodURL>;
|
|
2288
|
+
callOptions: z.ZodOptional<z.ZodType<CallOptions, unknown, z.core.$ZodTypeInternals<CallOptions, unknown>>>;
|
|
2289
|
+
twimlOptions: z.ZodOptional<z.ZodObject<{
|
|
2290
|
+
customParameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
2291
|
+
actionUrl: z.ZodOptional<z.ZodString>;
|
|
2292
|
+
websocketUrl: z.ZodOptional<z.ZodString>;
|
|
2293
|
+
name: z.ZodOptional<z.ZodString>;
|
|
2294
|
+
statusCallback: z.ZodOptional<z.ZodString>;
|
|
2295
|
+
statusCallbackMethod: z.ZodOptional<z.ZodEnum<{
|
|
2296
|
+
POST: "POST";
|
|
2297
|
+
GET: "GET";
|
|
2298
|
+
}>>;
|
|
2299
|
+
actionMethod: z.ZodOptional<z.ZodEnum<{
|
|
2300
|
+
POST: "POST";
|
|
2301
|
+
GET: "GET";
|
|
2302
|
+
}>>;
|
|
2303
|
+
}, z.core.$strict>>;
|
|
2304
|
+
sessionConfig: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
2305
|
+
}, z.core.$strict>;
|
|
2306
|
+
type InitiateVoiceConversationOptionsOpenAIRealtime = z.infer<typeof InitiateVoiceConversationOptionsOpenAIRealtimeSchema>;
|
|
2307
|
+
/**
|
|
2308
|
+
* Outbound options for `GPTLiveProvider`, adding a per-call `sessionConfig` on
|
|
2309
|
+
* top of {@link InitiateVoiceConversationOptionsSchema}. Also narrows
|
|
2310
|
+
* `twimlOptions` to {@link VoiceTwiMLOptionsMediaStreamsSchema}.
|
|
2311
|
+
*
|
|
2312
|
+
* Mirrors the Python SDK's `InitiateVoiceConversationOptionsGPTLive`.
|
|
2313
|
+
*/
|
|
2314
|
+
declare const InitiateVoiceConversationOptionsGPTLiveSchema: z.ZodObject<{
|
|
2315
|
+
to: z.ZodString;
|
|
2316
|
+
websocketUrl: z.ZodOptional<z.ZodURL>;
|
|
2317
|
+
callOptions: z.ZodOptional<z.ZodType<CallOptions, unknown, z.core.$ZodTypeInternals<CallOptions, unknown>>>;
|
|
2318
|
+
twimlOptions: z.ZodOptional<z.ZodObject<{
|
|
2319
|
+
customParameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
2320
|
+
actionUrl: z.ZodOptional<z.ZodString>;
|
|
2321
|
+
websocketUrl: z.ZodOptional<z.ZodString>;
|
|
2322
|
+
name: z.ZodOptional<z.ZodString>;
|
|
2323
|
+
statusCallback: z.ZodOptional<z.ZodString>;
|
|
2324
|
+
statusCallbackMethod: z.ZodOptional<z.ZodEnum<{
|
|
2325
|
+
POST: "POST";
|
|
2326
|
+
GET: "GET";
|
|
2327
|
+
}>>;
|
|
2328
|
+
actionMethod: z.ZodOptional<z.ZodEnum<{
|
|
2329
|
+
POST: "POST";
|
|
2330
|
+
GET: "GET";
|
|
2331
|
+
}>>;
|
|
2332
|
+
}, z.core.$strict>>;
|
|
2333
|
+
sessionConfig: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
2334
|
+
}, z.core.$strict>;
|
|
2335
|
+
type InitiateVoiceConversationOptionsGPTLive = z.infer<typeof InitiateVoiceConversationOptionsGPTLiveSchema>;
|
|
2336
|
+
|
|
2337
|
+
/**
|
|
2338
|
+
* The `start` field of Twilio's Media Stream `start` event.
|
|
2339
|
+
*
|
|
2340
|
+
* This is an inbound, read-only message Twilio pushes over the
|
|
2341
|
+
* `<Connect><Stream>` WebSocket, so unlike the outbound TwiML options it
|
|
2342
|
+
* carries no snake_case alias layer — the wire names are parsed directly.
|
|
2343
|
+
*
|
|
2344
|
+
* Mirrors the Python SDK's `StreamStartMessage`. Python exposes a
|
|
2345
|
+
* `conversation_id` property aliasing `call_sid`; here callers read `callSid`
|
|
2346
|
+
* directly.
|
|
2347
|
+
*
|
|
2348
|
+
* @see https://www.twilio.com/docs/voice/media-streams/websocket-messages
|
|
2349
|
+
*/
|
|
2350
|
+
declare const StreamStartMessageSchema: z.ZodObject<{
|
|
2351
|
+
streamSid: z.ZodString;
|
|
2352
|
+
callSid: z.ZodString;
|
|
2353
|
+
mediaFormat: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
2354
|
+
customParameters: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
2355
|
+
}, z.core.$strip>;
|
|
2356
|
+
type StreamStartMessage = z.infer<typeof StreamStartMessageSchema>;
|
|
2120
2357
|
|
|
2121
2358
|
/**
|
|
2122
2359
|
* Structured payload generated during a handoff.
|
|
@@ -2215,6 +2452,33 @@ declare const AnthropicToolSchema: z.ZodObject<{
|
|
|
2215
2452
|
}, z.core.$strip>;
|
|
2216
2453
|
}, z.core.$strip>;
|
|
2217
2454
|
type AnthropicTool = z.infer<typeof AnthropicToolSchema>;
|
|
2455
|
+
/**
|
|
2456
|
+
* OpenAI Realtime tool format.
|
|
2457
|
+
*
|
|
2458
|
+
* Realtime's `session.tools` expects the fields flat on the tool object,
|
|
2459
|
+
* unlike Chat Completions ({@link OpenAIToolSchema}), which nests them under a
|
|
2460
|
+
* `function` key.
|
|
2461
|
+
*/
|
|
2462
|
+
declare const OpenAIRealtimeToolSchema: z.ZodObject<{
|
|
2463
|
+
type: z.ZodLiteral<"function">;
|
|
2464
|
+
name: z.ZodString;
|
|
2465
|
+
description: z.ZodString;
|
|
2466
|
+
parameters: z.ZodObject<{
|
|
2467
|
+
type: z.ZodEnum<{
|
|
2468
|
+
string: "string";
|
|
2469
|
+
number: "number";
|
|
2470
|
+
boolean: "boolean";
|
|
2471
|
+
object: "object";
|
|
2472
|
+
array: "array";
|
|
2473
|
+
}>;
|
|
2474
|
+
properties: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
2475
|
+
required: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
2476
|
+
items: z.ZodOptional<z.ZodAny>;
|
|
2477
|
+
enum: z.ZodOptional<z.ZodArray<z.ZodAny>>;
|
|
2478
|
+
description: z.ZodOptional<z.ZodString>;
|
|
2479
|
+
}, z.core.$strip>;
|
|
2480
|
+
}, z.core.$strip>;
|
|
2481
|
+
type OpenAIRealtimeTool = z.infer<typeof OpenAIRealtimeToolSchema>;
|
|
2218
2482
|
/**
|
|
2219
2483
|
* Tool execution context
|
|
2220
2484
|
*/
|
|
@@ -3166,6 +3430,22 @@ declare class TAC {
|
|
|
3166
3430
|
shutdown(): void;
|
|
3167
3431
|
}
|
|
3168
3432
|
|
|
3433
|
+
type EventProperties = {
|
|
3434
|
+
account_sid: string;
|
|
3435
|
+
} & Record<string, unknown>;
|
|
3436
|
+
/**
|
|
3437
|
+
* Record a telemetry event. Never throws.
|
|
3438
|
+
*
|
|
3439
|
+
* @internal
|
|
3440
|
+
*/
|
|
3441
|
+
declare function trackEvent(event: string, properties: EventProperties): void;
|
|
3442
|
+
/**
|
|
3443
|
+
* Flush pending events and close the client. Called by `TAC.shutdown()`.
|
|
3444
|
+
*
|
|
3445
|
+
* @internal
|
|
3446
|
+
*/
|
|
3447
|
+
declare function shutdownAnalytics(): Promise<void>;
|
|
3448
|
+
|
|
3169
3449
|
/**
|
|
3170
3450
|
* Messaging channel configuration options.
|
|
3171
3451
|
* Alias for BaseChannelOptions that can be extended by specific channel implementations.
|
|
@@ -3222,6 +3502,14 @@ declare abstract class MessagingChannel extends BaseChannel {
|
|
|
3222
3502
|
* per-conversation channelId) to build the address.
|
|
3223
3503
|
*/
|
|
3224
3504
|
protected abstract getAgentAddress(conversationId: ConversationId): ConversationAddress;
|
|
3505
|
+
/**
|
|
3506
|
+
* Report a delivered response.
|
|
3507
|
+
*
|
|
3508
|
+
* Each channel calls this from its own `sendResponse` rather than the base
|
|
3509
|
+
* wrapping the call: `sendResponse` is the public extension point, so making
|
|
3510
|
+
* it a template method would break subclasses defined outside this package.
|
|
3511
|
+
*/
|
|
3512
|
+
protected trackResponseSent(conversationId: ConversationId): void;
|
|
3225
3513
|
/**
|
|
3226
3514
|
* Check if a message is from the bot itself (2-tier).
|
|
3227
3515
|
*
|
|
@@ -3491,15 +3779,154 @@ declare class ChatChannel extends MessagingChannel {
|
|
|
3491
3779
|
}
|
|
3492
3780
|
|
|
3493
3781
|
/**
|
|
3494
|
-
*
|
|
3782
|
+
* Base class for a {@link VoiceChannel}'s real-time media provider.
|
|
3783
|
+
*
|
|
3784
|
+
* Holds the owning `channel` (Calls API lifecycle, conversation bookkeeping,
|
|
3785
|
+
* `TAC`). Every method here has a default that either declines the capability
|
|
3786
|
+
* or does nothing, so a provider only implements the transport it actually
|
|
3787
|
+
* supports — ConversationRelay serves inbound TwiML and a WebSocket, while a
|
|
3788
|
+
* provider with no inbound story simply inherits the refusal.
|
|
3789
|
+
*/
|
|
3790
|
+
declare class VoiceProvider {
|
|
3791
|
+
/** The `VoiceChannel` that owns this provider. */
|
|
3792
|
+
readonly channel: VoiceChannel;
|
|
3793
|
+
/** Logger named after the concrete provider class. */
|
|
3794
|
+
protected readonly logger: Logger;
|
|
3795
|
+
constructor(channel: VoiceChannel);
|
|
3796
|
+
/**
|
|
3797
|
+
* Stable snake_case identifier for this provider, reported on voice
|
|
3798
|
+
* telemetry events so emissions from different transports are
|
|
3799
|
+
* distinguishable. Built-in providers override it; a provider defined outside
|
|
3800
|
+
* the SDK inherits `"custom"`.
|
|
3801
|
+
*
|
|
3802
|
+
* @internal
|
|
3803
|
+
*/
|
|
3804
|
+
get providerId(): string;
|
|
3805
|
+
/**
|
|
3806
|
+
* Channel name identifier, e.g. `"VOICE"`.
|
|
3807
|
+
*
|
|
3808
|
+
* A label for this provider's transport; it does not change how
|
|
3809
|
+
* `VoiceChannel` reports its `ChannelType`.
|
|
3810
|
+
*/
|
|
3811
|
+
get channelName(): string;
|
|
3812
|
+
/**
|
|
3813
|
+
* Build the response for an inbound call. Default: not supported.
|
|
3814
|
+
*
|
|
3815
|
+
* @param _twimlRequest - Parsed Twilio webhook fields for the inbound call.
|
|
3816
|
+
* @param _options - Additional per-call inputs.
|
|
3817
|
+
* @param _options.hostTwimlOptions - Per-call TwiML supplied by a custom
|
|
3818
|
+
* in-process host.
|
|
3819
|
+
*/
|
|
3820
|
+
handleIncomingCall(_twimlRequest?: TwiMLRequest, _options?: {
|
|
3821
|
+
hostTwimlOptions?: VoiceTwiMLOptions;
|
|
3822
|
+
}): Promise<string>;
|
|
3823
|
+
/**
|
|
3824
|
+
* Handle this provider's own out-of-band lifecycle webhook, if it has one.
|
|
3825
|
+
*
|
|
3826
|
+
* Not every provider has an equivalent — Twilio's ConversationRelay posts to
|
|
3827
|
+
* `<Connect action=...>` when the session ends (`ConversationRelayProvider`
|
|
3828
|
+
* uses this as a WebSocket-disconnect backup); Media Streams instead has its
|
|
3829
|
+
* own independent `statusCallback` (`stream-started` / `stream-stopped` /
|
|
3830
|
+
* `stream-error`), which is purely informational and doesn't gate call flow.
|
|
3831
|
+
* Default acknowledges with an empty 200 for providers with nothing to do
|
|
3832
|
+
* here.
|
|
3833
|
+
*/
|
|
3834
|
+
handleTwilioProviderCallback(_payload: Record<string, unknown>): Promise<TwilioProviderCallbackResponse>;
|
|
3835
|
+
/**
|
|
3836
|
+
* Drive one WebSocket connection from accept to disconnect.
|
|
3837
|
+
*
|
|
3838
|
+
* Implementations may be synchronous or asynchronous: a provider that only
|
|
3839
|
+
* attaches event handlers can return `void`, while one that awaits an
|
|
3840
|
+
* upstream handshake before serving traffic returns a `Promise<void>`. The
|
|
3841
|
+
* owning `VoiceChannel` is responsible for handling a returned promise's
|
|
3842
|
+
* rejection, so an async override never produces an unhandled rejection.
|
|
3843
|
+
*/
|
|
3844
|
+
handleWebSocket(_websocket: WebSocket): void | Promise<void>;
|
|
3845
|
+
/** Place an outbound call. Default: not supported. */
|
|
3846
|
+
initiateOutboundConversation(_options: InitiateVoiceConversationOptions): Promise<InitiateVoiceConversationResult>;
|
|
3847
|
+
/** Send a text response back through this provider's transport, if supported. */
|
|
3848
|
+
sendResponse(_conversationId: ConversationId, _message: string, _metadata?: Record<string, unknown>): Promise<void>;
|
|
3849
|
+
/**
|
|
3850
|
+
* Stream a text response back through this provider's transport, token by
|
|
3851
|
+
* token, if supported. Default: not supported.
|
|
3852
|
+
*
|
|
3853
|
+
* @param _conversationId - Conversation whose transport receives the tokens.
|
|
3854
|
+
* @param _stream - Async iterable of text chunks to relay as they arrive.
|
|
3855
|
+
* @param _options - Additional per-call inputs.
|
|
3856
|
+
* @param _options.signal - Aborts the stream mid-flight, e.g. when the caller
|
|
3857
|
+
* interrupts.
|
|
3858
|
+
* @returns The accumulated response text.
|
|
3859
|
+
*/
|
|
3860
|
+
sendStreamingResponse(_conversationId: ConversationId, _stream: AsyncIterable<string>, _options?: {
|
|
3861
|
+
signal?: AbortSignal;
|
|
3862
|
+
}): Promise<string>;
|
|
3863
|
+
/** Return the Twilio-facing WebSocket for a conversation, if tracked. */
|
|
3864
|
+
getWebSocket(_conversationId: ConversationId): WebSocket | null;
|
|
3865
|
+
/**
|
|
3866
|
+
* Drop this provider's transport state on channel shutdown.
|
|
3867
|
+
*
|
|
3868
|
+
* Called by {@link VoiceChannel.shutdown} before the channel clears its own
|
|
3869
|
+
* conversation bookkeeping. Default no-op — providers override this to drop
|
|
3870
|
+
* whatever transport state they track. Live WebSocket connections are owned
|
|
3871
|
+
* and closed by the server, so an override only clears in-process tracking.
|
|
3872
|
+
*/
|
|
3873
|
+
shutdown(): void;
|
|
3874
|
+
/**
|
|
3875
|
+
* Set callback URLs on `callParams` for every registered call-event handler.
|
|
3876
|
+
*
|
|
3877
|
+
* A URL is derived only when its handler is registered — an unwanted
|
|
3878
|
+
* call-event URL would otherwise surface as silent 11200 alerts for a
|
|
3879
|
+
* feature nobody asked for. If TAC isn't serving these routes, set the URLs
|
|
3880
|
+
* explicitly via `CallOptions` (or the provider config's default call
|
|
3881
|
+
* options, where available). An explicit URL from either options layer is
|
|
3882
|
+
* never overwritten.
|
|
3883
|
+
*/
|
|
3884
|
+
protected applyCallEventCallbacks(callParams: Record<string, unknown>): Record<string, unknown>;
|
|
3885
|
+
}
|
|
3886
|
+
/**
|
|
3887
|
+
* Base configuration for a {@link VoiceChannel}'s real-time media provider.
|
|
3888
|
+
*
|
|
3889
|
+
* Subclasses add their provider's own settings and implement
|
|
3890
|
+
* {@link VoiceProviderConfig.createProvider} to build the provider they
|
|
3891
|
+
* configure.
|
|
3892
|
+
*/
|
|
3893
|
+
declare class VoiceProviderConfig {
|
|
3894
|
+
/** Memory retrieval mode for this channel. Defaults to `'never'`. */
|
|
3895
|
+
memoryMode: MemoryMode;
|
|
3896
|
+
/**
|
|
3897
|
+
* The {@link BaseChannelOptions} this config was constructed with, retained
|
|
3898
|
+
* verbatim so `VoiceChannel` can hand them to `BaseChannel`.
|
|
3899
|
+
*
|
|
3900
|
+
* A provider config carries channel-level options (`dedupCapacity` and
|
|
3901
|
+
* friends) alongside its own provider settings; without this they would be
|
|
3902
|
+
* dropped on the config path while still applying on the plain-object path,
|
|
3903
|
+
* which is the same channel configured two ways.
|
|
3904
|
+
*
|
|
3905
|
+
* @internal
|
|
3906
|
+
*/
|
|
3907
|
+
readonly channelOptions: BaseChannelOptions;
|
|
3908
|
+
constructor(options?: BaseChannelOptions);
|
|
3909
|
+
/**
|
|
3910
|
+
* Build the {@link VoiceProvider} this config configures.
|
|
3911
|
+
*
|
|
3912
|
+
* @param _channel - The owning `VoiceChannel`.
|
|
3913
|
+
* @param _tacConfig - `TACConfig` — providers that talk TwiML need it to
|
|
3914
|
+
* derive default URLs (`voicePublicDomain` etc.).
|
|
3915
|
+
*/
|
|
3916
|
+
createProvider(_channel: VoiceChannel, _tacConfig: TACConfig): VoiceProvider;
|
|
3917
|
+
}
|
|
3918
|
+
|
|
3919
|
+
/**
|
|
3920
|
+
* Options accepted by {@link ConversationRelayProviderConfig}.
|
|
3495
3921
|
*
|
|
3496
3922
|
* `defaultTwimlOptions` is one of several TwiML layers that merge per-field;
|
|
3497
|
-
* see `handleIncomingCall` (inbound) and
|
|
3498
|
-
* (outbound) for the
|
|
3923
|
+
* see `ConversationRelayProvider.handleIncomingCall` (inbound) and
|
|
3924
|
+
* `ConversationRelayProvider.initiateOutboundConversation` (outbound) for the
|
|
3925
|
+
* full precedence order.
|
|
3499
3926
|
*/
|
|
3500
|
-
interface
|
|
3927
|
+
interface ConversationRelayProviderConfigOptions extends BaseChannelOptions {
|
|
3501
3928
|
/**
|
|
3502
|
-
* Static `
|
|
3929
|
+
* Static `VoiceTwiMLOptionsConversationRelay` applied to every call (inbound and outbound).
|
|
3503
3930
|
* Controls the TwiML inside `<ConversationRelay>` — voice, language,
|
|
3504
3931
|
* transcription provider, welcomeGreeting, `<Language>` children, etc. Use
|
|
3505
3932
|
* this when the same ConversationRelay configuration is correct for every call.
|
|
@@ -3510,7 +3937,7 @@ interface VoiceChannelConfig extends BaseChannelOptions {
|
|
|
3510
3937
|
* Note: `customParameters` and `languages` replace wholesale when a
|
|
3511
3938
|
* higher-priority layer sets them.
|
|
3512
3939
|
*/
|
|
3513
|
-
defaultTwimlOptions?:
|
|
3940
|
+
defaultTwimlOptions?: VoiceTwiMLOptionsConversationRelay;
|
|
3514
3941
|
/**
|
|
3515
3942
|
* Static {@link CallOptions} applied to every outbound call — the
|
|
3516
3943
|
* `calls.create` parameters, including the call-event callback URLs. This is
|
|
@@ -3521,200 +3948,95 @@ interface VoiceChannelConfig extends BaseChannelOptions {
|
|
|
3521
3948
|
defaultCallOptions?: CallOptions;
|
|
3522
3949
|
}
|
|
3523
3950
|
/**
|
|
3524
|
-
*
|
|
3525
|
-
*
|
|
3526
|
-
*
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
*
|
|
3951
|
+
* Configuration for {@link ConversationRelayProvider}, the default
|
|
3952
|
+
* {@link VoiceChannel} provider.
|
|
3953
|
+
*
|
|
3954
|
+
* TwiML configuration layers (highest precedence first):
|
|
3955
|
+
*
|
|
3956
|
+
* Inbound calls (`handleIncomingCall`):
|
|
3957
|
+
* 1. Output of the customizer registered via
|
|
3958
|
+
* `VoiceChannel.onInboundCallTwiml(...)` [optional]
|
|
3959
|
+
* 2. `defaultTwimlOptions` [optional]
|
|
3960
|
+
* 3. `handleIncomingCall(hostTwimlOptions)` [optional]
|
|
3961
|
+
* 4. TAC defaults
|
|
3962
|
+
*
|
|
3963
|
+
* Outbound calls (`initiateOutboundConversation`):
|
|
3964
|
+
* 1. `InitiateVoiceConversationOptions.twimlOptions` [optional]
|
|
3965
|
+
* 2. `defaultTwimlOptions` [optional]
|
|
3966
|
+
* 3. TAC defaults
|
|
3967
|
+
*
|
|
3968
|
+
* Calls-API parameters (`initiateOutboundConversation`):
|
|
3969
|
+
* 1. `InitiateVoiceConversationOptions.callOptions` [optional]
|
|
3970
|
+
* 2. `defaultCallOptions` [optional]
|
|
3971
|
+
* 3. Callback URLs derived from `TACConfig.voicePublicDomain` +
|
|
3972
|
+
* `voiceCallEventPath`, for handlers that are registered
|
|
3973
|
+
*
|
|
3974
|
+
* All layers merge per-field via key presence — only fields a layer explicitly
|
|
3975
|
+
* sets override lower layers. Arrays (`languages`) and nested objects
|
|
3976
|
+
* (`customParameters`) replace wholesale when set.
|
|
3977
|
+
*
|
|
3978
|
+
* Per-call inbound customization is registered via
|
|
3979
|
+
* `VoiceChannel.onInboundCallTwiml(...)` (not on this config).
|
|
3537
3980
|
*/
|
|
3538
|
-
|
|
3539
|
-
onSetup?: (data: {
|
|
3540
|
-
callSid: string;
|
|
3541
|
-
from: string;
|
|
3542
|
-
to: string;
|
|
3543
|
-
customParameters: Record<string, unknown> | undefined;
|
|
3544
|
-
}) => void;
|
|
3545
|
-
onPrompt?: (data: {
|
|
3546
|
-
conversationId: ConversationId;
|
|
3547
|
-
transcript: string;
|
|
3548
|
-
userMemory?: TACMemoryResponse;
|
|
3549
|
-
session?: ConversationSession;
|
|
3550
|
-
abortSignal: AbortSignal;
|
|
3551
|
-
}) => Promise<void> | void;
|
|
3552
|
-
onInterrupt?: (data: {
|
|
3553
|
-
conversationId: ConversationId;
|
|
3554
|
-
utteranceUntilInterrupt: string | undefined;
|
|
3555
|
-
durationUntilInterruptMs: number | undefined;
|
|
3556
|
-
}) => void;
|
|
3981
|
+
declare class ConversationRelayProviderConfig extends VoiceProviderConfig {
|
|
3557
3982
|
/**
|
|
3558
|
-
*
|
|
3559
|
-
*
|
|
3983
|
+
* Static `VoiceTwiMLOptionsConversationRelay` for the TwiML inside `<ConversationRelay>`, applied
|
|
3984
|
+
* to every call (inbound and outbound).
|
|
3560
3985
|
*/
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
}) => void;
|
|
3986
|
+
readonly defaultTwimlOptions?: VoiceTwiMLOptionsConversationRelay;
|
|
3987
|
+
/** Static {@link CallOptions} applied to every outbound call. */
|
|
3988
|
+
readonly defaultCallOptions?: CallOptions;
|
|
3989
|
+
constructor(options?: ConversationRelayProviderConfigOptions);
|
|
3990
|
+
createProvider(channel: VoiceChannel, tacConfig: TACConfig): VoiceProvider;
|
|
3567
3991
|
}
|
|
3568
3992
|
/**
|
|
3569
|
-
*
|
|
3993
|
+
* Pre-provider-split name for {@link ConversationRelayProviderConfigOptions} —
|
|
3994
|
+
* the shape `new VoiceChannel(tac, {...})` accepts. Kept so the shipped public
|
|
3995
|
+
* export stays valid across the provider refactor.
|
|
3570
3996
|
*
|
|
3571
|
-
*
|
|
3572
|
-
|
|
3997
|
+
* @deprecated Use {@link ConversationRelayProviderConfigOptions} instead.
|
|
3998
|
+
*/
|
|
3999
|
+
type VoiceChannelConfig = ConversationRelayProviderConfigOptions;
|
|
4000
|
+
|
|
4001
|
+
/**
|
|
4002
|
+
* A single in-flight streaming response, with the {@link AbortController} that
|
|
4003
|
+
* cancels it and whether any token has been written to the transport yet.
|
|
3573
4004
|
*/
|
|
3574
4005
|
interface StreamTask {
|
|
3575
4006
|
controller: AbortController;
|
|
3576
4007
|
hasSentTokens: boolean;
|
|
3577
4008
|
}
|
|
3578
|
-
|
|
4009
|
+
/**
|
|
4010
|
+
* Twilio ConversationRelay: Twilio handles ASR/TTS and exchanges JSON
|
|
4011
|
+
* `setup`/`prompt`/`interrupt` messages over one WebSocket.
|
|
4012
|
+
*
|
|
4013
|
+
* This is the default provider {@link VoiceChannel} builds when none is passed
|
|
4014
|
+
* explicitly.
|
|
4015
|
+
*/
|
|
4016
|
+
declare class ConversationRelayProvider extends VoiceProvider {
|
|
4017
|
+
/** @internal */
|
|
4018
|
+
get providerId(): string;
|
|
4019
|
+
/**
|
|
4020
|
+
* The owning channel's logger, so relocated ConversationRelay logic keeps
|
|
4021
|
+
* logging exactly as it did when it lived on `VoiceChannel`.
|
|
4022
|
+
*/
|
|
4023
|
+
protected readonly logger: Logger;
|
|
4024
|
+
/** In-flight streaming responses, keyed by conversation. */
|
|
4025
|
+
protected readonly streamTasks: Map<ConversationId, StreamTask>;
|
|
4026
|
+
private readonly config;
|
|
4027
|
+
private readonly tacConfig;
|
|
4028
|
+
private readonly twimlBuilder;
|
|
3579
4029
|
private readonly webSocketConnections;
|
|
3580
|
-
private readonly voiceCallbacks;
|
|
3581
|
-
private readonly streamTasks;
|
|
3582
4030
|
private readonly promptQueues;
|
|
3583
4031
|
private readonly initializationRetries;
|
|
3584
4032
|
private readonly callSidToConversationId;
|
|
3585
4033
|
private readonly MAX_INITIALIZATION_RETRIES;
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
private onInboundCallTwimlHandler;
|
|
3589
|
-
private onCallStatusHandler;
|
|
3590
|
-
private onAmdHandler;
|
|
3591
|
-
private onRecordingHandler;
|
|
3592
|
-
constructor(tac: TAC, options?: VoiceChannelConfig);
|
|
3593
|
-
/**
|
|
3594
|
-
* Register a callback that produces per-call overrides for the TwiML inside
|
|
3595
|
-
* `<ConversationRelay>` on inbound calls.
|
|
3596
|
-
*
|
|
3597
|
-
* The callback receives a framework-neutral {@link TwiMLRequest} (parsed from
|
|
3598
|
-
* the Twilio webhook form) and returns {@link TwiMLOptions}. Fields the
|
|
3599
|
-
* callback explicitly sets override `defaultTwimlOptions` and TAC defaults;
|
|
3600
|
-
* unset fields fall through.
|
|
3601
|
-
*
|
|
3602
|
-
* @example
|
|
3603
|
-
* ```typescript
|
|
3604
|
-
* voiceChannel.onInboundCallTwiml(async req => {
|
|
3605
|
-
* if (req.callerCountry === 'MX') {
|
|
3606
|
-
* return { language: 'es-MX', welcomeGreeting: '¡Hola!' };
|
|
3607
|
-
* }
|
|
3608
|
-
* return {};
|
|
3609
|
-
* });
|
|
3610
|
-
* ```
|
|
3611
|
-
*
|
|
3612
|
-
* Outbound calls don't use this — pass per-call TwiML via
|
|
3613
|
-
* `InitiateVoiceConversationOptions.twimlOptions` directly.
|
|
3614
|
-
*/
|
|
3615
|
-
onInboundCallTwiml(callback: InboundCallTwimlHandler): void;
|
|
3616
|
-
/**
|
|
3617
|
-
* Register a handler for Twilio `statusCallback` webhooks.
|
|
3618
|
-
*
|
|
3619
|
-
* This is the Calls-API status callback (call disposition), not the
|
|
3620
|
-
* ConversationRelay session callback — see
|
|
3621
|
-
* {@link handleConversationRelayCallback}.
|
|
3622
|
-
*
|
|
3623
|
-
* Registering does two things: it stores the handler, and it makes later
|
|
3624
|
-
* outbound calls pass `statusCallback` to `calls.create`. With no handler
|
|
3625
|
-
* registered TAC omits that parameter, so Twilio has nowhere to post and the
|
|
3626
|
-
* event never arrives.
|
|
3627
|
-
*
|
|
3628
|
-
* Twilio reports only the terminal event by default, which covers every
|
|
3629
|
-
* disposition; set `CallOptions.statusCallbackEvent` for ringing/answered.
|
|
3630
|
-
*
|
|
3631
|
-
* @example
|
|
3632
|
-
* ```typescript
|
|
3633
|
-
* voiceChannel.onCallStatus(async event => {
|
|
3634
|
-
* if (event.isUnreached) {
|
|
3635
|
-
* // queue a retry
|
|
3636
|
-
* }
|
|
3637
|
-
* });
|
|
3638
|
-
* ```
|
|
3639
|
-
*/
|
|
3640
|
-
onCallStatus(callback: CallStatusHandler): void;
|
|
3641
|
-
/**
|
|
3642
|
-
* Register a handler for Twilio `asyncAmdStatusCallback` webhooks.
|
|
3643
|
-
*
|
|
3644
|
-
* Registering makes later outbound calls pass `asyncAmdStatusCallback` to
|
|
3645
|
-
* `calls.create`; without a handler TAC omits it and Twilio has nowhere to
|
|
3646
|
-
* post the result. It does not enable detection — that's per-call, via
|
|
3647
|
-
* `CallOptions.machineDetection` and `asyncAmd`, both of which are required
|
|
3648
|
-
* for this to fire (at most once per call).
|
|
3649
|
-
*
|
|
3650
|
-
* @example
|
|
3651
|
-
* ```typescript
|
|
3652
|
-
* voiceChannel.onAmd(async event => {
|
|
3653
|
-
* if (event.isMachine) {
|
|
3654
|
-
* await voiceChannel.endCall(event.callSid); // voicemail → hang up
|
|
3655
|
-
* }
|
|
3656
|
-
* });
|
|
3657
|
-
* ```
|
|
3658
|
-
*/
|
|
3659
|
-
onAmd(callback: AmdHandler): void;
|
|
3660
|
-
/**
|
|
3661
|
-
* Register a handler for Twilio `recordingStatusCallback` webhooks.
|
|
3662
|
-
*
|
|
3663
|
-
* Registering makes later outbound calls pass `recordingStatusCallback` to
|
|
3664
|
-
* `calls.create`; without a handler TAC omits it and Twilio has nowhere to
|
|
3665
|
-
* post. It does not start recording — that's `CallOptions.record`, which is
|
|
3666
|
-
* required for this to fire.
|
|
3667
|
-
*
|
|
3668
|
-
* @example
|
|
3669
|
-
* ```typescript
|
|
3670
|
-
* voiceChannel.onRecording(async event => {
|
|
3671
|
-
* if (event.recordingStatus === 'completed') {
|
|
3672
|
-
* // store event.recordingUrl
|
|
3673
|
-
* }
|
|
3674
|
-
* });
|
|
3675
|
-
* ```
|
|
3676
|
-
*/
|
|
3677
|
-
onRecording(callback: RecordingHandler): void;
|
|
3678
|
-
/**
|
|
3679
|
-
* Resolve the public WebSocket URL from `TACConfig.voicePublicDomain` +
|
|
3680
|
-
* `TACConfig.voiceWebsocketPath`. Throws if `voicePublicDomain` isn't set.
|
|
3681
|
-
*/
|
|
3682
|
-
private resolveWebsocketUrl;
|
|
3683
|
-
/**
|
|
3684
|
-
* Resolve the default `<Connect action=...>` cleanup URL.
|
|
3685
|
-
*
|
|
3686
|
-
* Returns undefined if `voicePublicDomain` isn't set; that's fine because
|
|
3687
|
-
* actionUrl has higher-priority layers (customizer, twimlOptions, Studio
|
|
3688
|
-
* handoff) above this fallback.
|
|
3689
|
-
*/
|
|
3690
|
-
private resolveDefaultActionUrl;
|
|
3691
|
-
private getTwilioClient;
|
|
3692
|
-
get channelType(): ChannelType;
|
|
3693
|
-
/**
|
|
3694
|
-
* Register event callbacks (override for Voice-specific events)
|
|
3695
|
-
*/
|
|
3696
|
-
on(event: string, callback: (...args: any[]) => void): void;
|
|
3697
|
-
/**
|
|
3698
|
-
* Process conversation webhooks for cleanup.
|
|
3699
|
-
*
|
|
3700
|
-
* Voice channel processes CONVERSATION_UPDATED events:
|
|
3701
|
-
* - CLOSED status: Clean up local session state
|
|
3702
|
-
*
|
|
3703
|
-
* Note: Conversation tracking uses instance-local memory. In multi-instance
|
|
3704
|
-
* deployments, webhooks may route to a different instance, preventing cleanup.
|
|
3705
|
-
*
|
|
3706
|
-
* @param payload - Raw webhook event data from Twilio
|
|
3707
|
-
* @param idempotencyToken - Optional Twilio idempotency token from request headers
|
|
3708
|
-
*/
|
|
3709
|
-
processWebhook(payload: unknown, idempotencyToken?: string): Promise<void>;
|
|
3710
|
-
/**
|
|
3711
|
-
* Handle conversation updated event
|
|
3712
|
-
*/
|
|
3713
|
-
private handleConversationUpdated;
|
|
4034
|
+
constructor(channel: VoiceChannel, tacConfig: TACConfig, config: ConversationRelayProviderConfig);
|
|
4035
|
+
get channelName(): string;
|
|
3714
4036
|
/**
|
|
3715
4037
|
* Get active WebSocket connection for a conversation
|
|
3716
4038
|
*/
|
|
3717
|
-
|
|
4039
|
+
getWebSocket(conversationId: ConversationId): WebSocket | null;
|
|
3718
4040
|
/**
|
|
3719
4041
|
* Poll Conversation Orchestrator for the conversation ConversationRelay
|
|
3720
4042
|
* created for `callSid`, then register the local session and WebSocket.
|
|
@@ -3725,7 +4047,7 @@ declare class VoiceChannel extends BaseChannel {
|
|
|
3725
4047
|
/**
|
|
3726
4048
|
* Handle WebSocket connection from ConversationRelay
|
|
3727
4049
|
*/
|
|
3728
|
-
|
|
4050
|
+
handleWebSocket(ws: WebSocket): void;
|
|
3729
4051
|
/**
|
|
3730
4052
|
* Handle WebSocket prompt message (user speech)
|
|
3731
4053
|
*/
|
|
@@ -3734,6 +4056,10 @@ declare class VoiceChannel extends BaseChannel {
|
|
|
3734
4056
|
* Handle WebSocket interrupt message
|
|
3735
4057
|
*/
|
|
3736
4058
|
private handleInterruptMessage;
|
|
4059
|
+
/**
|
|
4060
|
+
* Handle WebSocket DTMF message (caller keypress)
|
|
4061
|
+
*/
|
|
4062
|
+
private handleDtmfMessage;
|
|
3737
4063
|
/**
|
|
3738
4064
|
* Handle WebSocket disconnection. In orchestrated mode the conversation stays
|
|
3739
4065
|
* tracked until the CLOSED webhook (so a follow-up call can reuse it); in
|
|
@@ -3758,6 +4084,33 @@ declare class VoiceChannel extends BaseChannel {
|
|
|
3758
4084
|
sendStreamingResponse(conversationId: ConversationId, stream: AsyncIterable<string>, options?: {
|
|
3759
4085
|
signal?: AbortSignal;
|
|
3760
4086
|
}): Promise<string>;
|
|
4087
|
+
/**
|
|
4088
|
+
* Start tracking a streaming task for a conversation
|
|
4089
|
+
*
|
|
4090
|
+
* @param conversationId - The conversation ID
|
|
4091
|
+
* @returns The stream task with its AbortController
|
|
4092
|
+
*/
|
|
4093
|
+
startStreamTask(conversationId: ConversationId): StreamTask;
|
|
4094
|
+
/**
|
|
4095
|
+
* Cancel an active streaming task
|
|
4096
|
+
*
|
|
4097
|
+
* @param conversationId - The conversation ID
|
|
4098
|
+
* @returns true if a task was cancelled, false otherwise
|
|
4099
|
+
*/
|
|
4100
|
+
cancelStreamTask(conversationId: ConversationId): boolean;
|
|
4101
|
+
/**
|
|
4102
|
+
* Complete a streaming task (remove from tracking)
|
|
4103
|
+
*
|
|
4104
|
+
* @param conversationId - The conversation ID
|
|
4105
|
+
*/
|
|
4106
|
+
completeStreamTask(conversationId: ConversationId): void;
|
|
4107
|
+
/**
|
|
4108
|
+
* Check if a stream task is active
|
|
4109
|
+
*
|
|
4110
|
+
* @param conversationId - The conversation ID
|
|
4111
|
+
* @returns true if an active task exists
|
|
4112
|
+
*/
|
|
4113
|
+
hasActiveStreamTask(conversationId: ConversationId): boolean;
|
|
3761
4114
|
/**
|
|
3762
4115
|
* Generate the TwiML response for an incoming voice call.
|
|
3763
4116
|
*
|
|
@@ -3772,7 +4125,8 @@ declare class VoiceChannel extends BaseChannel {
|
|
|
3772
4125
|
* 1. Output of the customizer registered via
|
|
3773
4126
|
* `VoiceChannel.onInboundCallTwiml(...)` if configured and `twimlRequest`
|
|
3774
4127
|
* is given. (Application-owned.)
|
|
3775
|
-
* 2. `
|
|
4128
|
+
* 2. `ConversationRelayProviderConfig.defaultTwimlOptions` — per-channel
|
|
4129
|
+
* defaults.
|
|
3776
4130
|
* 3. `hostTwimlOptions` — per-call transport facts supplied by the host (the
|
|
3777
4131
|
* code owning the route), e.g. a per-call `websocketUrl` with an affinity
|
|
3778
4132
|
* token.
|
|
@@ -3795,73 +4149,42 @@ declare class VoiceChannel extends BaseChannel {
|
|
|
3795
4149
|
* `websocketUrl`), layered below `defaultTwimlOptions` and the application
|
|
3796
4150
|
* customizer but above the TAC defaults.
|
|
3797
4151
|
* @returns TwiML XML string for call connection.
|
|
4152
|
+
* @throws {Error} if either options layer isn't a
|
|
4153
|
+
* {@link VoiceTwiMLOptionsConversationRelay}.
|
|
3798
4154
|
*/
|
|
3799
4155
|
handleIncomingCall(twimlRequest?: TwiMLRequest, options?: {
|
|
3800
|
-
hostTwimlOptions?:
|
|
4156
|
+
hostTwimlOptions?: VoiceTwiMLOptions;
|
|
3801
4157
|
}): Promise<string>;
|
|
3802
4158
|
/**
|
|
3803
|
-
*
|
|
3804
|
-
*
|
|
3805
|
-
*
|
|
3806
|
-
*
|
|
3807
|
-
*/
|
|
3808
|
-
private buildTwimlOptions;
|
|
3809
|
-
/**
|
|
3810
|
-
* Apply fields explicitly present on `source` onto `target`.
|
|
3811
|
-
*
|
|
3812
|
-
* Nested objects (`customParameters`), arrays (`languages`), and dicts
|
|
3813
|
-
* (`extra`) replace wholesale — there's no per-key merging.
|
|
3814
|
-
*
|
|
3815
|
-
* `actionUrl` is skipped here on purpose — it's resolved once via
|
|
3816
|
-
* `resolveActionUrl` looking at every layer at once, and that resolved value
|
|
3817
|
-
* is written into `target` before this overlay runs. Letting it through here
|
|
3818
|
-
* would let a higher-priority layer that didn't set actionUrl silently clobber
|
|
3819
|
-
* a lower layer that did.
|
|
3820
|
-
*
|
|
3821
|
-
* "Explicitly present" is detected via key presence (`key in source`), which
|
|
3822
|
-
* mirrors Python's `model_fields_set`: a key set to `undefined` is still
|
|
3823
|
-
* "present" and overrides lower layers, while an absent key falls through.
|
|
3824
|
-
*/
|
|
3825
|
-
private overlayFields;
|
|
3826
|
-
/**
|
|
3827
|
-
* Resolve the TwiML `<Connect action=...>` URL.
|
|
4159
|
+
* Narrow provider-agnostic {@link VoiceTwiMLOptions} to this provider's
|
|
4160
|
+
* concrete shape. `VoiceProvider.handleIncomingCall` is typed against the
|
|
4161
|
+
* base so every provider can accept its own TwiML options, so the
|
|
4162
|
+
* ConversationRelay shape has to be established at runtime.
|
|
3828
4163
|
*
|
|
3829
|
-
*
|
|
3830
|
-
*
|
|
3831
|
-
* 2. channel `defaultTwimlOptions`
|
|
3832
|
-
* 3. `host` (calling host's per-call options)
|
|
3833
|
-
* 4. Studio handoff (when `studioHandoffFlowSid` is configured)
|
|
3834
|
-
* 5. Channel default — derived from `TACConfig.voicePublicDomain` +
|
|
3835
|
-
* `TACConfig.voiceActionPath`.
|
|
3836
|
-
*
|
|
3837
|
-
* User-expressed intent (Studio handoff is configured explicitly on
|
|
3838
|
-
* `TACConfig`) beats the SDK's generated cleanup default.
|
|
3839
|
-
*
|
|
3840
|
-
* Explicit `actionUrl: undefined` on a layer (key present, value undefined)
|
|
3841
|
-
* suppresses `<Connect action=...>` entirely — all lower layers are skipped.
|
|
3842
|
-
* `actionUrl` left absent (key not present) falls through to the next layer.
|
|
4164
|
+
* @param value - Options from a caller or the application customizer.
|
|
4165
|
+
* @param label - What produced `value`, for the error message.
|
|
3843
4166
|
*/
|
|
3844
|
-
private
|
|
4167
|
+
private narrowTwimlOptions;
|
|
3845
4168
|
/**
|
|
3846
|
-
* Overlay `perCall` onto `
|
|
4169
|
+
* Overlay `perCall` onto `ConversationRelayProviderConfig.defaultCallOptions`.
|
|
3847
4170
|
*
|
|
3848
|
-
* Per-field via key presence, the same convention
|
|
3849
|
-
* for TwiML options — so a per-call `{ machineDetection: undefined }`
|
|
4171
|
+
* Per-field via key presence, the same convention `TwiMLBuilderBase.overlayFields`
|
|
4172
|
+
* uses for TwiML options — so a per-call `{ machineDetection: undefined }`
|
|
3850
4173
|
* explicitly clears the channel default rather than falling through to it.
|
|
3851
4174
|
*
|
|
3852
4175
|
* The result is always validated, for two reasons: a combination only
|
|
3853
4176
|
* reachable by layering — per-call clearing `machineDetection` while the
|
|
3854
4177
|
* default set `asyncAmd` — must still fail instead of reaching Twilio, and
|
|
3855
|
-
* `
|
|
3856
|
-
* no runtime validation of its own.
|
|
4178
|
+
* `ConversationRelayProviderConfigOptions` is a plain interface, so
|
|
4179
|
+
* `defaultCallOptions` has had no runtime validation of its own.
|
|
3857
4180
|
*/
|
|
3858
4181
|
private mergeCallOptions;
|
|
3859
4182
|
/**
|
|
3860
4183
|
* Build the extra arguments for `client.calls.create`.
|
|
3861
4184
|
*
|
|
3862
4185
|
* Layers, highest precedence first: this call's `callOptions`,
|
|
3863
|
-
* `
|
|
3864
|
-
* `voicePublicDomain` + `voiceCallEventPath`.
|
|
4186
|
+
* `ConversationRelayProviderConfig.defaultCallOptions`, then callback URLs
|
|
4187
|
+
* derived from `voicePublicDomain` + `voiceCallEventPath`.
|
|
3865
4188
|
*
|
|
3866
4189
|
* A URL is derived only when its handler is registered. That's a deliberate
|
|
3867
4190
|
* deviation from `websocketUrl` / `actionUrl`, which derive unconditionally:
|
|
@@ -3881,14 +4204,16 @@ declare class VoiceChannel extends BaseChannel {
|
|
|
3881
4204
|
*
|
|
3882
4205
|
* TwiML fields are merged per-field, highest precedence first:
|
|
3883
4206
|
* 1. `options.twimlOptions` — per-call overrides
|
|
3884
|
-
* 2. `
|
|
4207
|
+
* 2. `ConversationRelayProviderConfig.defaultTwimlOptions` — channel-wide
|
|
4208
|
+
* defaults
|
|
3885
4209
|
* 3. TAC defaults: welcome greeting, `conversationConfiguration` from
|
|
3886
4210
|
* `TACConfig`, and `actionUrl` from Studio handoff (if configured), else
|
|
3887
4211
|
* derived from `TACConfig.voicePublicDomain` + `voiceActionPath`.
|
|
3888
4212
|
*
|
|
3889
4213
|
* Calls-API parameters merge the same way:
|
|
3890
4214
|
* 1. `options.callOptions` — per-call overrides
|
|
3891
|
-
* 2. `
|
|
4215
|
+
* 2. `ConversationRelayProviderConfig.defaultCallOptions` — channel-wide
|
|
4216
|
+
* defaults
|
|
3892
4217
|
* 3. Callback URLs derived from `TACConfig.voicePublicDomain` +
|
|
3893
4218
|
* `voiceCallEventPath`, for handlers that are registered
|
|
3894
4219
|
*
|
|
@@ -3901,203 +4226,1849 @@ declare class VoiceChannel extends BaseChannel {
|
|
|
3901
4226
|
* Handle ConversationRelay callback from Twilio. Cleans up on call completion
|
|
3902
4227
|
* in voice-only mode; in orchestrated mode the CO webhook owns cleanup.
|
|
3903
4228
|
*
|
|
3904
|
-
* @param
|
|
4229
|
+
* @param rawPayload - Callback payload from Twilio
|
|
3905
4230
|
* @returns Response with status, content, and content type
|
|
3906
4231
|
*/
|
|
3907
|
-
|
|
3908
|
-
status: number;
|
|
3909
|
-
content: string;
|
|
3910
|
-
contentType: string;
|
|
3911
|
-
}>;
|
|
4232
|
+
handleTwilioProviderCallback(rawPayload: Record<string, unknown>): Promise<TwilioProviderCallbackResponse>;
|
|
3912
4233
|
/**
|
|
3913
|
-
*
|
|
3914
|
-
*
|
|
3915
|
-
* Twilio signature validation already gates the route; this is defense in
|
|
3916
|
-
* depth. A payload with no `AccountSid` is allowed through.
|
|
4234
|
+
* Generate TwiML to connect a call to ConversationRelay.
|
|
4235
|
+
* Validates configuration with Zod before generating TwiML.
|
|
3917
4236
|
*
|
|
3918
|
-
*
|
|
3919
|
-
*
|
|
4237
|
+
* @param config - ConversationRelay configuration (url, transcription, TTS, etc.)
|
|
4238
|
+
* @param options - Optional settings for parameters and the Connect verb
|
|
4239
|
+
* @returns TwiML XML string
|
|
4240
|
+
* @throws {Error} if config validation fails
|
|
3920
4241
|
*/
|
|
3921
|
-
|
|
4242
|
+
connectConversationRelay(config: ConversationRelayConfig, options?: {
|
|
4243
|
+
parameters?: CustomParameters;
|
|
4244
|
+
actionUrl?: string;
|
|
4245
|
+
}): string;
|
|
3922
4246
|
/**
|
|
3923
|
-
*
|
|
4247
|
+
* Drop this provider's ConversationRelay transport state on channel shutdown.
|
|
3924
4248
|
*
|
|
3925
|
-
*
|
|
3926
|
-
*
|
|
3927
|
-
* processed. Everything else, including no handler registered and an
|
|
3928
|
-
* account mismatch, is a 200 no-op.
|
|
4249
|
+
* Note: WebSocket connections are managed by the server and closed there.
|
|
4250
|
+
* This method only cleans up internal provider state.
|
|
3929
4251
|
*/
|
|
3930
|
-
|
|
4252
|
+
shutdown(): void;
|
|
4253
|
+
}
|
|
4254
|
+
|
|
4255
|
+
/**
|
|
4256
|
+
* Callback that produces per-call overrides for the TwiML inside
|
|
4257
|
+
* `<ConversationRelay>` on inbound calls. Receives a framework-neutral
|
|
4258
|
+
* {@link TwiMLRequest} and returns {@link VoiceTwiMLOptionsConversationRelay}.
|
|
4259
|
+
*
|
|
4260
|
+
* Stays typed against the ConversationRelay subtype rather than the
|
|
4261
|
+
* provider-agnostic base ({@link VoiceProvider.handleIncomingCall} is widened
|
|
4262
|
+
* to the base, this consumer-facing surface is not): the base has only
|
|
4263
|
+
* optional shared fields, so TypeScript's object-literal freshness check
|
|
4264
|
+
* rejects the documented inline form `async () => ({ voice: '...' })` for
|
|
4265
|
+
* having no properties in common with it. It widens once a second
|
|
4266
|
+
* inbound-capable provider exists.
|
|
4267
|
+
*/
|
|
4268
|
+
type InboundCallTwimlHandler = (req: TwiMLRequest) => Promise<VoiceTwiMLOptionsConversationRelay>;
|
|
4269
|
+
/** Handler for Twilio `statusCallback` webhooks. */
|
|
4270
|
+
type CallStatusHandler = (event: CallStatusEvent) => Promise<void> | void;
|
|
4271
|
+
/** Handler for Twilio `asyncAmdStatusCallback` webhooks. */
|
|
4272
|
+
type AmdHandler = (event: AmdEvent) => Promise<void> | void;
|
|
4273
|
+
/** Handler for Twilio `recordingStatusCallback` webhooks. */
|
|
4274
|
+
type RecordingHandler = (event: RecordingEvent) => Promise<void> | void;
|
|
4275
|
+
/** One ConversationRelay keypress, as delivered to a {@link DtmfHandler}. */
|
|
4276
|
+
interface DtmfEvent {
|
|
4277
|
+
/**
|
|
4278
|
+
* Undefined only when the keypress beat conversation setup: `dtmf` before
|
|
4279
|
+
* ConversationRelay's `setup`, or an orchestrated-mode lookup that failed.
|
|
4280
|
+
*/
|
|
4281
|
+
conversationId: ConversationId | undefined;
|
|
4282
|
+
/** Undefined only before ConversationRelay's `setup` message. */
|
|
4283
|
+
callSid: string | undefined;
|
|
4284
|
+
/** The key pressed: `0`-`9`, `*`, `#`, or `A`-`D`. */
|
|
4285
|
+
digit: string;
|
|
4286
|
+
/** Present whenever `conversationId` is. */
|
|
4287
|
+
session?: ConversationSession;
|
|
4288
|
+
}
|
|
4289
|
+
/** Handler for ConversationRelay `dtmf` messages (caller keypresses). */
|
|
4290
|
+
type DtmfHandler = (event: DtmfEvent) => Promise<void> | void;
|
|
4291
|
+
/**
|
|
4292
|
+
* Voice channel event callbacks extending base callbacks
|
|
4293
|
+
*/
|
|
4294
|
+
interface VoiceChannelEvents extends BaseChannelEvents {
|
|
4295
|
+
onSetup?: (data: {
|
|
4296
|
+
callSid: string;
|
|
4297
|
+
from: string;
|
|
4298
|
+
to: string;
|
|
4299
|
+
customParameters: Record<string, unknown> | undefined;
|
|
4300
|
+
}) => void;
|
|
4301
|
+
onPrompt?: (data: {
|
|
4302
|
+
conversationId: ConversationId;
|
|
4303
|
+
transcript: string;
|
|
4304
|
+
userMemory?: TACMemoryResponse;
|
|
4305
|
+
session?: ConversationSession;
|
|
4306
|
+
abortSignal: AbortSignal;
|
|
4307
|
+
}) => Promise<void> | void;
|
|
4308
|
+
onInterrupt?: (data: {
|
|
4309
|
+
conversationId: ConversationId;
|
|
4310
|
+
utteranceUntilInterrupt: string | undefined;
|
|
4311
|
+
durationUntilInterruptMs: number | undefined;
|
|
4312
|
+
}) => void;
|
|
4313
|
+
/** Caller keypress. See {@link VoiceChannel.onDtmf}. */
|
|
4314
|
+
onDtmf?: DtmfHandler;
|
|
3931
4315
|
/**
|
|
3932
|
-
*
|
|
3933
|
-
*
|
|
3934
|
-
* The developer routes the request here (`TACServer` does this automatically
|
|
3935
|
-
* for its `/status` call-event route). Parsed into a {@link CallStatusEvent}
|
|
3936
|
-
* and dispatched to the {@link onCallStatus} handler. No-op if no handler is
|
|
3937
|
-
* registered.
|
|
3938
|
-
*
|
|
3939
|
-
* @param form - Raw form data from the webhook request.
|
|
4316
|
+
* Fired once the session and WebSocket registration exist — in orchestrated
|
|
4317
|
+
* mode possibly before the first prompt, since the lookup starts at setup.
|
|
3940
4318
|
*/
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
4319
|
+
onWebSocketConnected?: (data: {
|
|
4320
|
+
conversationId: ConversationId;
|
|
4321
|
+
}) => void;
|
|
4322
|
+
onWebSocketDisconnected?: (data: {
|
|
4323
|
+
conversationId: ConversationId;
|
|
4324
|
+
}) => void;
|
|
4325
|
+
}
|
|
4326
|
+
/**
|
|
4327
|
+
* Voice Channel for handling voice-based conversations over a WebSocket.
|
|
4328
|
+
*
|
|
4329
|
+
* The real-time media transport lives on a {@link VoiceProvider} — by default
|
|
4330
|
+
* {@link ConversationRelayProvider}. `VoiceChannel` keeps the Calls-API
|
|
4331
|
+
* lifecycle (call events, hangup), conversation bookkeeping and webhook
|
|
4332
|
+
* processing, and delegates everything transport-shaped to the provider.
|
|
4333
|
+
*/
|
|
4334
|
+
declare class VoiceChannel extends BaseChannel {
|
|
4335
|
+
private readonly provider;
|
|
4336
|
+
private readonly voiceCallbacks;
|
|
4337
|
+
private twilioClient;
|
|
4338
|
+
private onInboundCallTwimlHandler;
|
|
4339
|
+
private onCallStatusHandler;
|
|
4340
|
+
private onAmdHandler;
|
|
4341
|
+
private onRecordingHandler;
|
|
4342
|
+
/**
|
|
4343
|
+
* @param tac - The owning {@link TAC} instance.
|
|
4344
|
+
* @param options - Either a {@link VoiceProviderConfig} selecting the media
|
|
4345
|
+
* provider, or a plain object — shorthand for
|
|
4346
|
+
* {@link ConversationRelayProviderConfig}, which is what TAC builds when no
|
|
4347
|
+
* provider config is given.
|
|
3954
4348
|
*/
|
|
3955
|
-
|
|
3956
|
-
status: number;
|
|
3957
|
-
content: string;
|
|
3958
|
-
contentType: string;
|
|
3959
|
-
}>;
|
|
4349
|
+
constructor(tac: TAC, options?: VoiceProviderConfig | ConversationRelayProviderConfigOptions);
|
|
3960
4350
|
/**
|
|
3961
|
-
*
|
|
4351
|
+
* The {@link BaseChannelOptions} to hand `BaseChannel`. A provider config
|
|
4352
|
+
* replays the options it retained (with its resolved `memoryMode`, which is
|
|
4353
|
+
* writable after construction); a plain options object is passed through. Both
|
|
4354
|
+
* paths therefore honour `dedupCapacity` and friends identically.
|
|
4355
|
+
*/
|
|
4356
|
+
private static toBaseOptions;
|
|
4357
|
+
/**
|
|
4358
|
+
* Resolve the provider config: an explicit {@link VoiceProviderConfig} as-is,
|
|
4359
|
+
* anything else wrapped as a {@link ConversationRelayProviderConfig}.
|
|
4360
|
+
*/
|
|
4361
|
+
private static toProviderConfig;
|
|
4362
|
+
/**
|
|
4363
|
+
* Register a callback that produces per-call overrides for the TwiML inside
|
|
4364
|
+
* `<ConversationRelay>` on inbound calls.
|
|
3962
4365
|
*
|
|
3963
|
-
* The
|
|
3964
|
-
*
|
|
3965
|
-
* {@link
|
|
3966
|
-
*
|
|
4366
|
+
* The callback receives a framework-neutral {@link TwiMLRequest} (parsed from
|
|
4367
|
+
* the Twilio webhook form) and returns
|
|
4368
|
+
* {@link VoiceTwiMLOptionsConversationRelay}. Fields the
|
|
4369
|
+
* callback explicitly sets override `defaultTwimlOptions` and TAC defaults;
|
|
4370
|
+
* unset fields fall through.
|
|
3967
4371
|
*
|
|
3968
|
-
* @
|
|
4372
|
+
* @example
|
|
4373
|
+
* ```typescript
|
|
4374
|
+
* voiceChannel.onInboundCallTwiml(async req => {
|
|
4375
|
+
* if (req.callerCountry === 'MX') {
|
|
4376
|
+
* return { language: 'es-MX', welcomeGreeting: '¡Hola!' };
|
|
4377
|
+
* }
|
|
4378
|
+
* return {};
|
|
4379
|
+
* });
|
|
4380
|
+
* ```
|
|
4381
|
+
*
|
|
4382
|
+
* Outbound calls don't use this — pass per-call TwiML via
|
|
4383
|
+
* `InitiateVoiceConversationOptions.twimlOptions` directly.
|
|
3969
4384
|
*/
|
|
3970
|
-
|
|
3971
|
-
status: number;
|
|
3972
|
-
content: string;
|
|
3973
|
-
contentType: string;
|
|
3974
|
-
}>;
|
|
4385
|
+
onInboundCallTwiml(callback: InboundCallTwimlHandler): void;
|
|
3975
4386
|
/**
|
|
3976
|
-
*
|
|
4387
|
+
* Register a handler for Twilio `statusCallback` webhooks.
|
|
3977
4388
|
*
|
|
3978
|
-
*
|
|
3979
|
-
* session
|
|
4389
|
+
* This is the Calls-API status callback (call disposition), not the
|
|
4390
|
+
* ConversationRelay session callback — see
|
|
4391
|
+
* {@link handleTwilioProviderCallback}.
|
|
3980
4392
|
*
|
|
3981
|
-
*
|
|
3982
|
-
*
|
|
3983
|
-
*
|
|
4393
|
+
* Registering does two things: it stores the handler, and it makes later
|
|
4394
|
+
* outbound calls pass `statusCallback` to `calls.create`. With no handler
|
|
4395
|
+
* registered TAC omits that parameter, so Twilio has nowhere to post and the
|
|
4396
|
+
* event never arrives.
|
|
3984
4397
|
*
|
|
3985
|
-
*
|
|
3986
|
-
*
|
|
3987
|
-
*
|
|
3988
|
-
*
|
|
4398
|
+
* Twilio reports only the terminal event by default, which covers every
|
|
4399
|
+
* disposition; set `CallOptions.statusCallbackEvent` for ringing/answered.
|
|
4400
|
+
*
|
|
4401
|
+
* @example
|
|
4402
|
+
* ```typescript
|
|
4403
|
+
* voiceChannel.onCallStatus(async event => {
|
|
4404
|
+
* if (event.isUnreached) {
|
|
4405
|
+
* // queue a retry
|
|
4406
|
+
* }
|
|
4407
|
+
* });
|
|
4408
|
+
* ```
|
|
3989
4409
|
*/
|
|
3990
|
-
|
|
4410
|
+
onCallStatus(callback: CallStatusHandler): void;
|
|
3991
4411
|
/**
|
|
3992
|
-
*
|
|
4412
|
+
* Register a handler for Twilio `asyncAmdStatusCallback` webhooks.
|
|
3993
4413
|
*
|
|
3994
|
-
*
|
|
3995
|
-
* a
|
|
3996
|
-
*
|
|
3997
|
-
*
|
|
4414
|
+
* Registering makes later outbound calls pass `asyncAmdStatusCallback` to
|
|
4415
|
+
* `calls.create`; without a handler TAC omits it and Twilio has nowhere to
|
|
4416
|
+
* post the result. It does not enable detection — that's per-call, via
|
|
4417
|
+
* `CallOptions.machineDetection` and `asyncAmd`, both of which are required
|
|
4418
|
+
* for this to fire (at most once per call).
|
|
3998
4419
|
*
|
|
3999
|
-
*
|
|
4000
|
-
*
|
|
4001
|
-
*
|
|
4002
|
-
*
|
|
4420
|
+
* @example
|
|
4421
|
+
* ```typescript
|
|
4422
|
+
* voiceChannel.onAmd(async event => {
|
|
4423
|
+
* if (event.isMachine) {
|
|
4424
|
+
* await voiceChannel.endCall(event.callSid); // voicemail → hang up
|
|
4425
|
+
* }
|
|
4426
|
+
* });
|
|
4427
|
+
* ```
|
|
4428
|
+
*/
|
|
4429
|
+
onAmd(callback: AmdHandler): void;
|
|
4430
|
+
/**
|
|
4431
|
+
* Register a handler for Twilio `recordingStatusCallback` webhooks.
|
|
4003
4432
|
*
|
|
4004
|
-
*
|
|
4005
|
-
*
|
|
4006
|
-
*
|
|
4007
|
-
*
|
|
4433
|
+
* Registering makes later outbound calls pass `recordingStatusCallback` to
|
|
4434
|
+
* `calls.create`; without a handler TAC omits it and Twilio has nowhere to
|
|
4435
|
+
* post. It does not start recording — that's `CallOptions.record`, which is
|
|
4436
|
+
* required for this to fire.
|
|
4008
4437
|
*
|
|
4009
4438
|
* @example
|
|
4010
4439
|
* ```typescript
|
|
4011
|
-
* async
|
|
4012
|
-
*
|
|
4013
|
-
*
|
|
4014
|
-
* await voiceChannel.sendResponse(session.conversationId, 'Still there?');
|
|
4440
|
+
* voiceChannel.onRecording(async event => {
|
|
4441
|
+
* if (event.recordingStatus === 'completed') {
|
|
4442
|
+
* // store event.recordingUrl
|
|
4015
4443
|
* }
|
|
4016
|
-
* }
|
|
4444
|
+
* });
|
|
4017
4445
|
* ```
|
|
4446
|
+
*/
|
|
4447
|
+
onRecording(callback: RecordingHandler): void;
|
|
4448
|
+
/**
|
|
4449
|
+
* Register a handler for DTMF keypresses, called once per key in order.
|
|
4018
4450
|
*
|
|
4019
|
-
*
|
|
4020
|
-
*
|
|
4021
|
-
*
|
|
4022
|
-
*
|
|
4023
|
-
*
|
|
4451
|
+
* Requires `dtmfDetection: true` on the ConversationRelay config — without it
|
|
4452
|
+
* Twilio sends nothing and this never fires. Digits aren't buffered, so
|
|
4453
|
+
* accumulating a multi-digit entry is the handler's job.
|
|
4454
|
+
*
|
|
4455
|
+
* A keypress initializes the conversation just as a prompt does, since a
|
|
4456
|
+
* caller can type without ever speaking; if that fails the digit still
|
|
4457
|
+
* arrives, with `conversationId` and `session` undefined. Keypresses don't
|
|
4458
|
+
* cancel in-flight streaming on their own — that's a separate `interrupt`
|
|
4459
|
+
* message, sent when `interruptible` includes `dtmf`.
|
|
4460
|
+
*
|
|
4461
|
+
* @example
|
|
4462
|
+
* ```typescript
|
|
4463
|
+
* const digits = new Map<string, string>();
|
|
4464
|
+
*
|
|
4465
|
+
* voiceChannel.onDtmf(({ conversationId, digit }) => {
|
|
4466
|
+
* if (!conversationId) return;
|
|
4467
|
+
* digits.set(conversationId, (digits.get(conversationId) ?? '') + digit);
|
|
4468
|
+
* });
|
|
4469
|
+
* ```
|
|
4024
4470
|
*/
|
|
4025
|
-
|
|
4471
|
+
onDtmf(callback: DtmfHandler): void;
|
|
4026
4472
|
/**
|
|
4027
|
-
*
|
|
4473
|
+
* The registered call-event handlers, for a `VoiceProvider` deciding which
|
|
4474
|
+
* callback URLs to derive. A provider is not a subclass of `VoiceChannel`,
|
|
4475
|
+
* so the `private` fields are genuinely out of reach without this.
|
|
4028
4476
|
*
|
|
4029
|
-
* @
|
|
4030
|
-
* @returns The stream task with its AbortController
|
|
4477
|
+
* @internal
|
|
4031
4478
|
*/
|
|
4032
|
-
|
|
4479
|
+
getCallEventHandlers(): {
|
|
4480
|
+
status: CallStatusHandler | undefined;
|
|
4481
|
+
amd: AmdHandler | undefined;
|
|
4482
|
+
recording: RecordingHandler | undefined;
|
|
4483
|
+
};
|
|
4033
4484
|
/**
|
|
4034
|
-
*
|
|
4485
|
+
* This channel's `TACConfig`, for a `VoiceProvider` deriving default URLs.
|
|
4486
|
+
* `BaseChannel.config` is `protected`, and a provider is not a subclass.
|
|
4035
4487
|
*
|
|
4036
|
-
* @
|
|
4037
|
-
* @returns true if a task was cancelled, false otherwise
|
|
4488
|
+
* @internal
|
|
4038
4489
|
*/
|
|
4039
|
-
|
|
4490
|
+
getTacConfig(): TACConfig;
|
|
4040
4491
|
/**
|
|
4041
|
-
*
|
|
4492
|
+
* This channel's logger, so a provider's relocated logic keeps logging under
|
|
4493
|
+
* the same name it did when it lived on `VoiceChannel`.
|
|
4042
4494
|
*
|
|
4043
|
-
* @
|
|
4495
|
+
* @internal
|
|
4044
4496
|
*/
|
|
4045
|
-
|
|
4497
|
+
getLoggerInternal(): Logger;
|
|
4046
4498
|
/**
|
|
4047
|
-
*
|
|
4499
|
+
* The Conversation Orchestrator client, or `null` in ConversationRelay-only
|
|
4500
|
+
* mode.
|
|
4501
|
+
*
|
|
4502
|
+
* @internal
|
|
4503
|
+
*/
|
|
4504
|
+
getConversationClientInternal(): ConversationClient | null;
|
|
4505
|
+
/**
|
|
4506
|
+
* The lazily built Twilio REST client, for a provider placing outbound calls.
|
|
4507
|
+
*
|
|
4508
|
+
* @internal
|
|
4509
|
+
*/
|
|
4510
|
+
getTwilioClientInternal(): ReturnType<typeof Twilio>;
|
|
4511
|
+
/**
|
|
4512
|
+
* Whether Conversation Orchestrator is configured. Providers branch on this
|
|
4513
|
+
* to decide who owns conversation cleanup.
|
|
4514
|
+
*
|
|
4515
|
+
* @internal
|
|
4516
|
+
*/
|
|
4517
|
+
isOrchestratorEnabledInternal(): boolean;
|
|
4518
|
+
/**
|
|
4519
|
+
* Voice event callbacks registered via {@link on}, for a provider to fire.
|
|
4520
|
+
*
|
|
4521
|
+
* @internal
|
|
4522
|
+
*/
|
|
4523
|
+
getVoiceCallbacks(): VoiceChannelEvents;
|
|
4524
|
+
/**
|
|
4525
|
+
* The inbound-TwiML customizer registered via {@link onInboundCallTwiml}, for
|
|
4526
|
+
* a provider building the inbound response.
|
|
4527
|
+
*
|
|
4528
|
+
* @internal
|
|
4529
|
+
*/
|
|
4530
|
+
getInboundCallTwimlHandler(): InboundCallTwimlHandler | undefined;
|
|
4531
|
+
/**
|
|
4532
|
+
* Start tracking a conversation session. Forwards to
|
|
4533
|
+
* `BaseChannel.startConversation`.
|
|
4534
|
+
*
|
|
4535
|
+
* @internal
|
|
4536
|
+
*/
|
|
4537
|
+
startConversationInternal(conversationId: ConversationId, profileId?: ProfileId): ConversationSession;
|
|
4538
|
+
/**
|
|
4539
|
+
* End a tracked conversation session. Forwards to
|
|
4540
|
+
* `BaseChannel.endConversation`.
|
|
4541
|
+
*
|
|
4542
|
+
* @internal
|
|
4543
|
+
*/
|
|
4544
|
+
endConversationInternal(conversationId: ConversationId): Promise<void>;
|
|
4545
|
+
/**
|
|
4546
|
+
* Retrieve memory when `memoryMode` calls for it. Forwards to
|
|
4547
|
+
* `BaseChannel.retrieveMemoryIfEnabled`.
|
|
4548
|
+
*
|
|
4549
|
+
* @internal
|
|
4550
|
+
*/
|
|
4551
|
+
retrieveMemoryInternal(session: ConversationSession, query?: string): Promise<TACMemoryResponse | undefined>;
|
|
4552
|
+
/**
|
|
4553
|
+
* Report an error through the channel's `onError` callback and logger.
|
|
4554
|
+
* Forwards to `BaseChannel.handleError`.
|
|
4555
|
+
*
|
|
4556
|
+
* @internal
|
|
4557
|
+
*/
|
|
4558
|
+
handleErrorInternal(error: Error, context?: Record<string, unknown>): void;
|
|
4559
|
+
private getTwilioClient;
|
|
4560
|
+
get channelType(): ChannelType;
|
|
4561
|
+
/**
|
|
4562
|
+
* Register event callbacks (override for Voice-specific events)
|
|
4563
|
+
*/
|
|
4564
|
+
on(event: string, callback: (...args: any[]) => void): void;
|
|
4565
|
+
/**
|
|
4566
|
+
* Process conversation webhooks for cleanup.
|
|
4567
|
+
*
|
|
4568
|
+
* Voice channel processes CONVERSATION_UPDATED events:
|
|
4569
|
+
* - CLOSED status: Clean up local session state
|
|
4570
|
+
*
|
|
4571
|
+
* Note: Conversation tracking uses instance-local memory. In multi-instance
|
|
4572
|
+
* deployments, webhooks may route to a different instance, preventing cleanup.
|
|
4573
|
+
*
|
|
4574
|
+
* @param payload - Raw webhook event data from Twilio
|
|
4575
|
+
* @param idempotencyToken - Optional Twilio idempotency token from request headers
|
|
4576
|
+
*/
|
|
4577
|
+
processWebhook(payload: unknown, idempotencyToken?: string): Promise<void>;
|
|
4578
|
+
/**
|
|
4579
|
+
* Handle conversation updated event
|
|
4580
|
+
*/
|
|
4581
|
+
private handleConversationUpdated;
|
|
4582
|
+
/**
|
|
4583
|
+
* Get active WebSocket connection for a conversation
|
|
4584
|
+
*/
|
|
4585
|
+
getWebsocket(conversationId: ConversationId): WebSocket | null;
|
|
4586
|
+
/**
|
|
4587
|
+
* Hand one WebSocket connection to the active provider, which drives its
|
|
4588
|
+
* lifecycle from accept to disconnect.
|
|
4589
|
+
*
|
|
4590
|
+
* @param ws - The accepted WebSocket, from ConversationRelay or whatever
|
|
4591
|
+
* transport the active provider serves.
|
|
4592
|
+
*/
|
|
4593
|
+
handleWebSocketConnection(ws: WebSocket): void;
|
|
4594
|
+
/**
|
|
4595
|
+
* Send voice response via WebSocket
|
|
4596
|
+
*/
|
|
4597
|
+
sendResponse(conversationId: ConversationId, message: string, metadata?: Record<string, unknown>): Promise<void>;
|
|
4598
|
+
/**
|
|
4599
|
+
* Send a streaming voice response through the active provider's transport,
|
|
4600
|
+
* token by token. Delegates to the active provider — see
|
|
4601
|
+
* {@link ConversationRelayProvider.sendStreamingResponse} for the token
|
|
4602
|
+
* protocol and abort semantics.
|
|
4603
|
+
*
|
|
4604
|
+
* @param conversationId - Conversation whose transport receives the tokens.
|
|
4605
|
+
* @param stream - Async iterable of text chunks to relay as they arrive.
|
|
4606
|
+
* @param options - Additional per-call inputs.
|
|
4607
|
+
* @param options.signal - Aborts the stream mid-flight, e.g. when the caller
|
|
4608
|
+
* interrupts.
|
|
4609
|
+
* @returns The accumulated full response text.
|
|
4610
|
+
*/
|
|
4611
|
+
sendStreamingResponse(conversationId: ConversationId, stream: AsyncIterable<string>, options?: {
|
|
4612
|
+
signal?: AbortSignal;
|
|
4613
|
+
}): Promise<string>;
|
|
4614
|
+
/**
|
|
4615
|
+
* Generate the response for an incoming voice call. Delegates to the active
|
|
4616
|
+
* provider — see {@link ConversationRelayProvider.handleIncomingCall} for the
|
|
4617
|
+
* full TwiML merge/precedence rules (only meaningful for that provider; a
|
|
4618
|
+
* provider with no inbound story declines instead).
|
|
4619
|
+
*
|
|
4620
|
+
* @param twimlRequest - Parsed Twilio webhook fields. Passed to the customizer
|
|
4621
|
+
* registered via {@link onInboundCallTwiml}, if one is configured.
|
|
4622
|
+
* @param options - Additional per-call inputs.
|
|
4623
|
+
* @param options.hostTwimlOptions - Per-call TwiML supplied by a custom
|
|
4624
|
+
* in-process host (e.g. an affinity-routed deployment injecting a per-call
|
|
4625
|
+
* `websocketUrl`). Typed against the ConversationRelay subtype for the same
|
|
4626
|
+
* reason as {@link InboundCallTwimlHandler}.
|
|
4627
|
+
* @returns TwiML XML string for call connection.
|
|
4628
|
+
*/
|
|
4629
|
+
handleIncomingCall(twimlRequest?: TwiMLRequest, options?: {
|
|
4630
|
+
hostTwimlOptions?: VoiceTwiMLOptionsConversationRelay;
|
|
4631
|
+
}): Promise<string>;
|
|
4632
|
+
/**
|
|
4633
|
+
* Initiate an outbound voice conversation. Delegates to the active provider —
|
|
4634
|
+
* see {@link ConversationRelayProvider.initiateOutboundConversation} for the
|
|
4635
|
+
* TwiML and Calls-API merge/precedence rules.
|
|
4636
|
+
*
|
|
4637
|
+
* {@link ConversationRelayProvider} and `OpenAIRealtimeProvider` place
|
|
4638
|
+
* outbound calls; any other provider declines.
|
|
4639
|
+
*
|
|
4640
|
+
* @param options - Destination, per-call TwiML and Calls-API overrides.
|
|
4641
|
+
* `OpenAIRealtimeProvider` additionally accepts a per-call `sessionConfig`.
|
|
4642
|
+
* Each provider validates against its own schema and rejects the other's.
|
|
4643
|
+
* @returns The placed call's `callSid`.
|
|
4644
|
+
*/
|
|
4645
|
+
initiateOutboundConversation(options: InitiateVoiceConversationOptions): Promise<InitiateVoiceConversationResult>;
|
|
4646
|
+
/**
|
|
4647
|
+
* Handle the provider's own out-of-band lifecycle webhook from Twilio.
|
|
4648
|
+
*
|
|
4649
|
+
* Not every provider has one; those that don't inherit a plain 200
|
|
4650
|
+
* acknowledgement. ConversationRelay posts here when a session ends, and
|
|
4651
|
+
* cleans up on call completion in voice-only mode — in orchestrated mode the
|
|
4652
|
+
* CO webhook owns cleanup.
|
|
4653
|
+
*
|
|
4654
|
+
* @param payload - Raw callback payload from Twilio; the provider validates it.
|
|
4655
|
+
* @returns Response with status, content, and content type
|
|
4656
|
+
*/
|
|
4657
|
+
handleTwilioProviderCallback(payload: Record<string, unknown>): Promise<TwilioProviderCallbackResponse>;
|
|
4658
|
+
/**
|
|
4659
|
+
* @deprecated Use {@link VoiceChannel.handleTwilioProviderCallback} instead.
|
|
4660
|
+
*/
|
|
4661
|
+
handleConversationRelayCallback(payload: ConversationRelayCallbackPayload): Promise<TwilioProviderCallbackResponse>;
|
|
4662
|
+
/**
|
|
4663
|
+
* Whether a call-webhook payload belongs to the configured account.
|
|
4664
|
+
*
|
|
4665
|
+
* Twilio signature validation already gates the route; this is defense in
|
|
4666
|
+
* depth. A payload with no `AccountSid` is allowed through.
|
|
4667
|
+
*
|
|
4668
|
+
* Subaccounts: events carry the SID the call was placed on, so configure TAC
|
|
4669
|
+
* with that account or its events get dropped here.
|
|
4670
|
+
*/
|
|
4671
|
+
private callEventAccountOk;
|
|
4672
|
+
/**
|
|
4673
|
+
* Parse a call-event webhook form and dispatch it to its handler.
|
|
4674
|
+
*
|
|
4675
|
+
* Returns 400 when the payload can't be parsed (no `CallSid`) or the handler
|
|
4676
|
+
* throws — better than handing Twilio a 200 for an event that wasn't
|
|
4677
|
+
* processed. Everything else, including no handler registered and an
|
|
4678
|
+
* account mismatch, is a 200 no-op.
|
|
4679
|
+
*/
|
|
4680
|
+
private dispatchCallEvent;
|
|
4681
|
+
/**
|
|
4682
|
+
* Handle a Twilio `statusCallback` webhook.
|
|
4683
|
+
*
|
|
4684
|
+
* The developer routes the request here (`TACServer` does this automatically
|
|
4685
|
+
* for its `/status` call-event route). Parsed into a {@link CallStatusEvent}
|
|
4686
|
+
* and dispatched to the {@link onCallStatus} handler. No-op if no handler is
|
|
4687
|
+
* registered.
|
|
4688
|
+
*
|
|
4689
|
+
* @param form - Raw form data from the webhook request.
|
|
4690
|
+
*/
|
|
4691
|
+
handleCallStatusEvent(form: Record<string, string>): Promise<{
|
|
4692
|
+
status: number;
|
|
4693
|
+
content: string;
|
|
4694
|
+
contentType: string;
|
|
4695
|
+
}>;
|
|
4696
|
+
/**
|
|
4697
|
+
* Handle a Twilio `asyncAmdStatusCallback` webhook.
|
|
4698
|
+
*
|
|
4699
|
+
* The developer routes the request here (`TACServer` does this automatically
|
|
4700
|
+
* for its `/amd` call-event route). Parsed into an {@link AmdEvent} and
|
|
4701
|
+
* dispatched to the {@link onAmd} handler. No-op if no handler is registered.
|
|
4702
|
+
*
|
|
4703
|
+
* @param form - Raw form data from the webhook request.
|
|
4704
|
+
*/
|
|
4705
|
+
handleAmdEvent(form: Record<string, string>): Promise<{
|
|
4706
|
+
status: number;
|
|
4707
|
+
content: string;
|
|
4708
|
+
contentType: string;
|
|
4709
|
+
}>;
|
|
4710
|
+
/**
|
|
4711
|
+
* Handle a Twilio `recordingStatusCallback` webhook.
|
|
4712
|
+
*
|
|
4713
|
+
* The developer routes the request here (`TACServer` does this automatically
|
|
4714
|
+
* for its `/recording` call-event route). Parsed into a
|
|
4715
|
+
* {@link RecordingEvent} and dispatched to the {@link onRecording} handler.
|
|
4716
|
+
* No-op if no handler is registered.
|
|
4717
|
+
*
|
|
4718
|
+
* @param form - Raw form data from the webhook request.
|
|
4719
|
+
*/
|
|
4720
|
+
handleRecordingEvent(form: Record<string, string>): Promise<{
|
|
4721
|
+
status: number;
|
|
4722
|
+
content: string;
|
|
4723
|
+
contentType: string;
|
|
4724
|
+
}>;
|
|
4725
|
+
/**
|
|
4726
|
+
* Hang up a call and clean up its ConversationRelay session.
|
|
4727
|
+
*
|
|
4728
|
+
* Works on `callSid` alone, whether or not a session exists yet. No-ops the
|
|
4729
|
+
* session cleanup if none is tracked.
|
|
4730
|
+
*
|
|
4731
|
+
* Does not throw — hanging up an already-ended call is routine (the callee
|
|
4732
|
+
* hangs up while AMD is still resolving), and handlers shouldn't have to
|
|
4733
|
+
* guard against it.
|
|
4734
|
+
*
|
|
4735
|
+
* @param callSid - Twilio Call SID (from a call event, the outbound result, or
|
|
4736
|
+
* `ConversationSession.callSid`).
|
|
4737
|
+
* @returns True if Twilio accepted the hangup, false if it failed (logged).
|
|
4738
|
+
* Session cleanup runs either way.
|
|
4739
|
+
*/
|
|
4740
|
+
endCall(callSid: string): Promise<boolean>;
|
|
4741
|
+
/**
|
|
4742
|
+
* Look up the active voice session for a Twilio Call SID.
|
|
4743
|
+
*
|
|
4744
|
+
* Out-of-band code holding a CallSid — a dashboard route, an operator action,
|
|
4745
|
+
* a call-event handler — can't reach the session-facing methods, which are
|
|
4746
|
+
* keyed by conversation id: the Orchestrator conversation id in orchestrator
|
|
4747
|
+
* mode, the CallSid only in ConversationRelay-only mode.
|
|
4748
|
+
*
|
|
4749
|
+
* Relay-only mode creates the session on the first prompt; orchestrated
|
|
4750
|
+
* mode creates it when the lookup started at setup finishes, so it may
|
|
4751
|
+
* exist before the caller speaks — including before `onAmd` fires. Treat it
|
|
4752
|
+
* as racy and hang up with {@link endCall}, which needs no session.
|
|
4753
|
+
*
|
|
4754
|
+
* At the other end, orchestrator mode keeps the session until Conversation
|
|
4755
|
+
* Orchestrator's CLOSED webhook, so it outlives the call and `onCallStatus` /
|
|
4756
|
+
* `onRecording` do resolve. Relay-only mode tears down on the
|
|
4757
|
+
* ConversationRelay callback instead, which races them.
|
|
4758
|
+
*
|
|
4759
|
+
* @example
|
|
4760
|
+
* ```typescript
|
|
4761
|
+
* async function nudge(callSid: string): Promise<void> {
|
|
4762
|
+
* const session = voiceChannel.getConversationSessionByCallSid(callSid);
|
|
4763
|
+
* if (session) {
|
|
4764
|
+
* await voiceChannel.sendResponse(session.conversationId, 'Still there?');
|
|
4765
|
+
* }
|
|
4766
|
+
* }
|
|
4767
|
+
* ```
|
|
4768
|
+
*
|
|
4769
|
+
* @param callSid - Twilio Call SID, e.g. from
|
|
4770
|
+
* `InitiateVoiceConversationResult.callSid` or a call event.
|
|
4771
|
+
* @returns The session, or `undefined` — not created yet, the call ended, or
|
|
4772
|
+
* it landed on another instance (see the horizontal-scaling note in
|
|
4773
|
+
* CLAUDE.md).
|
|
4774
|
+
*/
|
|
4775
|
+
getConversationSessionByCallSid(callSid: string): ConversationSession | undefined;
|
|
4776
|
+
/**
|
|
4777
|
+
* Narrow `provider` to the ConversationRelay implementation for the
|
|
4778
|
+
* ConversationRelay-only forwarders on this channel.
|
|
4779
|
+
*
|
|
4780
|
+
* Throws whenever a consumer supplies a non-ConversationRelay provider, which
|
|
4781
|
+
* is the point of the guard. The provider callback used to narrow here too; it
|
|
4782
|
+
* now rides {@link VoiceProvider.handleTwilioProviderCallback}'s
|
|
4783
|
+
* base-compatible signature instead, which is the eventual shape for these
|
|
4784
|
+
* forwarders.
|
|
4785
|
+
*
|
|
4786
|
+
* @throws {Error} if this channel's provider is not ConversationRelay-based.
|
|
4787
|
+
*/
|
|
4788
|
+
private requireConversationRelayProvider;
|
|
4789
|
+
/**
|
|
4790
|
+
* Start tracking a streaming task for a conversation
|
|
4791
|
+
*
|
|
4792
|
+
* @param conversationId - The conversation ID
|
|
4793
|
+
* @returns The stream task with its AbortController
|
|
4794
|
+
*/
|
|
4795
|
+
startStreamTask(conversationId: ConversationId): StreamTask;
|
|
4796
|
+
/**
|
|
4797
|
+
* Cancel an active streaming task
|
|
4798
|
+
*
|
|
4799
|
+
* @param conversationId - The conversation ID
|
|
4800
|
+
* @returns true if a task was cancelled, false otherwise
|
|
4801
|
+
*/
|
|
4802
|
+
cancelStreamTask(conversationId: ConversationId): boolean;
|
|
4803
|
+
/**
|
|
4804
|
+
* Complete a streaming task (remove from tracking)
|
|
4805
|
+
*
|
|
4806
|
+
* @param conversationId - The conversation ID
|
|
4807
|
+
*/
|
|
4808
|
+
completeStreamTask(conversationId: ConversationId): void;
|
|
4809
|
+
/**
|
|
4810
|
+
* Check if a stream task is active
|
|
4811
|
+
*
|
|
4812
|
+
* @param conversationId - The conversation ID
|
|
4813
|
+
* @returns true if an active task exists
|
|
4814
|
+
*/
|
|
4815
|
+
hasActiveStreamTask(conversationId: ConversationId): boolean;
|
|
4816
|
+
/**
|
|
4817
|
+
* Generate TwiML to connect a call to ConversationRelay. Delegates to
|
|
4818
|
+
* {@link ConversationRelayProvider.connectConversationRelay}, which validates
|
|
4819
|
+
* the configuration with Zod before generating TwiML.
|
|
4820
|
+
*
|
|
4821
|
+
* @param config - ConversationRelay configuration (url, transcription, TTS, etc.)
|
|
4822
|
+
* @param options - Optional settings for parameters and the Connect verb
|
|
4823
|
+
* @returns TwiML XML string
|
|
4824
|
+
* @throws {Error} if config validation fails, or if this channel's provider is
|
|
4825
|
+
* not ConversationRelay-based.
|
|
4826
|
+
*/
|
|
4827
|
+
connectConversationRelay(config: ConversationRelayConfig, options?: {
|
|
4828
|
+
parameters?: CustomParameters;
|
|
4829
|
+
actionUrl?: string;
|
|
4830
|
+
}): string;
|
|
4831
|
+
/**
|
|
4832
|
+
* Cleanup channel state on shutdown
|
|
4833
|
+
*
|
|
4834
|
+
* Note: WebSocket connections are managed by the server and closed there.
|
|
4835
|
+
* This method only cleans up internal channel state.
|
|
4836
|
+
*/
|
|
4837
|
+
shutdown(): void;
|
|
4838
|
+
}
|
|
4839
|
+
|
|
4840
|
+
/**
|
|
4841
|
+
* Common construction and option-layering helpers shared by every provider's
|
|
4842
|
+
* TwiML builder.
|
|
4843
|
+
*
|
|
4844
|
+
* Subclasses take `TACConfig` and their provider's channel config wholesale
|
|
4845
|
+
* (not individual derived values) so a later change to either — a new field, a
|
|
4846
|
+
* new default — is a change to the builder alone, not a change to what
|
|
4847
|
+
* `VoiceChannel` has to compute and hand over.
|
|
4848
|
+
*
|
|
4849
|
+
* @internal
|
|
4850
|
+
*/
|
|
4851
|
+
declare abstract class TwiMLBuilderBase<TChannelConfig = unknown> {
|
|
4852
|
+
protected readonly tacConfig: TACConfig;
|
|
4853
|
+
protected readonly channelConfig: TChannelConfig;
|
|
4854
|
+
protected readonly logger: Logger;
|
|
4855
|
+
constructor(tacConfig: TACConfig, channelConfig: TChannelConfig, logger: Logger);
|
|
4856
|
+
/**
|
|
4857
|
+
* Apply fields explicitly present on `source` onto `target`, except those
|
|
4858
|
+
* named in `skip`.
|
|
4859
|
+
*
|
|
4860
|
+
* Nested objects, arrays, and dicts replace wholesale — there's no per-key
|
|
4861
|
+
* merging.
|
|
4862
|
+
*
|
|
4863
|
+
* "Explicitly present" is detected via key presence (`Object.keys`), which
|
|
4864
|
+
* mirrors Python's `model_fields_set`: a key set to `undefined` is still
|
|
4865
|
+
* "present" and overrides lower layers, while an absent key falls through.
|
|
4866
|
+
*/
|
|
4867
|
+
protected overlayFields(target: Record<string, unknown>, source: Record<string, unknown>, skip?: readonly string[]): void;
|
|
4868
|
+
/**
|
|
4869
|
+
* The error thrown when no layer and no `TACConfig`-derived default supplies
|
|
4870
|
+
* a WebSocket URL. `caller` names the API the developer actually called.
|
|
4871
|
+
*/
|
|
4872
|
+
protected missingWebsocketUrlError(caller: string): Error;
|
|
4873
|
+
/**
|
|
4874
|
+
* The WebSocket URL derived from `TACConfig.voicePublicDomain` +
|
|
4875
|
+
* `TACConfig.voiceWebsocketPath`, or undefined when `voicePublicDomain` is
|
|
4876
|
+
* unset.
|
|
4877
|
+
*/
|
|
4878
|
+
protected defaultWebsocketUrl(): string | undefined;
|
|
4879
|
+
/**
|
|
4880
|
+
* Resolve the default `<Connect action=...>` cleanup URL from
|
|
4881
|
+
* `TACConfig.voicePublicDomain` + `TACConfig.voiceActionPath`.
|
|
4882
|
+
*
|
|
4883
|
+
* Returns undefined if `voicePublicDomain` isn't set; that's fine because
|
|
4884
|
+
* actionUrl has higher-priority layers (customizer, twimlOptions, Studio
|
|
4885
|
+
* handoff) above this fallback.
|
|
4886
|
+
*/
|
|
4887
|
+
protected defaultActionUrl(): string | undefined;
|
|
4888
|
+
}
|
|
4889
|
+
|
|
4890
|
+
/**
|
|
4891
|
+
* The slice of a Media Streams provider's config this builder reads. Declared
|
|
4892
|
+
* structurally rather than importing the provider's config class, so the
|
|
4893
|
+
* builder does not depend on which Media Streams provider owns it.
|
|
4894
|
+
*/
|
|
4895
|
+
interface MediaStreamsTwiMLBuilderConfig {
|
|
4896
|
+
defaultTwimlOptions?: VoiceTwiMLOptionsMediaStreams | undefined;
|
|
4897
|
+
}
|
|
4898
|
+
/**
|
|
4899
|
+
* Generate TwiML that connects the call to a bidirectional Media Stream.
|
|
4900
|
+
*
|
|
4901
|
+
* See https://www.twilio.com/docs/voice/twiml/stream for the `<Stream>` verb.
|
|
4902
|
+
*
|
|
4903
|
+
* The WebSocket URL may be passed positionally or as `options.websocketUrl`
|
|
4904
|
+
* (positional wins when both are given), so a caller can pass everything in one
|
|
4905
|
+
* object: `generateStreamTwiml(undefined, { websocketUrl: ... })`.
|
|
4906
|
+
*
|
|
4907
|
+
* @param websocketUrl - Public `wss://` URL of the WebSocket endpoint Twilio
|
|
4908
|
+
* should stream call audio to (the `<Stream url=...>` attribute). Optional if
|
|
4909
|
+
* `options.websocketUrl` is set.
|
|
4910
|
+
* @param options - Optional Media Streams TwiML options.
|
|
4911
|
+
* @returns TwiML XML string ready to return to Twilio.
|
|
4912
|
+
* @throws {Error} if no WebSocket URL is provided via either source.
|
|
4913
|
+
*/
|
|
4914
|
+
declare function generateStreamTwiml(websocketUrl?: string, options?: VoiceTwiMLOptionsMediaStreams): string;
|
|
4915
|
+
/** Per-call inputs to {@link TwiMLBuilderMediaStreams.build}. */
|
|
4916
|
+
interface BuildStreamTwiMLInputs {
|
|
4917
|
+
/**
|
|
4918
|
+
* Per-call overrides from the host owning the route (e.g. a per-call
|
|
4919
|
+
* `websocketUrl` with an affinity token). Lowest of the option layers.
|
|
4920
|
+
*/
|
|
4921
|
+
host?: VoiceTwiMLOptionsMediaStreams | undefined;
|
|
4922
|
+
/**
|
|
4923
|
+
* Per-call overrides — the `onInboundCallTwiml` customizer's output for
|
|
4924
|
+
* inbound, or `InitiateVoiceConversationOptions.twimlOptions` for outbound.
|
|
4925
|
+
* Highest layer.
|
|
4926
|
+
*/
|
|
4927
|
+
perCall?: VoiceTwiMLOptionsMediaStreams | undefined;
|
|
4928
|
+
/**
|
|
4929
|
+
* Dedicated per-call WebSocket override that wins over any `websocketUrl`
|
|
4930
|
+
* coming through the option layers. Used by outbound, which takes it as its
|
|
4931
|
+
* own argument.
|
|
4932
|
+
*/
|
|
4933
|
+
websocketUrl?: string | undefined;
|
|
4934
|
+
}
|
|
4935
|
+
/**
|
|
4936
|
+
* Builds the TwiML for a Media Streams call, owning the layering and WebSocket
|
|
4937
|
+
* URL resolution so the provider doesn't have to.
|
|
4938
|
+
*/
|
|
4939
|
+
declare class TwiMLBuilderMediaStreams extends TwiMLBuilderBase<MediaStreamsTwiMLBuilderConfig> {
|
|
4940
|
+
/**
|
|
4941
|
+
* Build the TwiML XML for one call.
|
|
4942
|
+
*
|
|
4943
|
+
* TwiML fields are merged per-field, highest precedence first:
|
|
4944
|
+
* 1. `perCall` — the `onInboundCallTwiml` customizer's output for inbound,
|
|
4945
|
+
* or `InitiateVoiceConversationOptions.twimlOptions` for outbound
|
|
4946
|
+
* 2. the provider config's `defaultTwimlOptions` — channel-wide defaults
|
|
4947
|
+
* 3. `host` — per-call transport facts supplied by the host
|
|
4948
|
+
* 4. TAC defaults: the WebSocket URL derived from
|
|
4949
|
+
* `TACConfig.voicePublicDomain` + `voiceWebsocketPath`
|
|
4950
|
+
*
|
|
4951
|
+
* @param caller - Name of the calling method, used in the "no WebSocket URL"
|
|
4952
|
+
* error so it points at the API the developer actually called.
|
|
4953
|
+
* @param options - Per-call option layers and WebSocket override.
|
|
4954
|
+
* @throws {Error} if no layer and no `TACConfig`-derived default supplies a
|
|
4955
|
+
* WebSocket URL.
|
|
4956
|
+
*/
|
|
4957
|
+
build(caller: string, options?: BuildStreamTwiMLInputs): string;
|
|
4958
|
+
/**
|
|
4959
|
+
* Layer TwiML options, lowest precedence first: `host` →
|
|
4960
|
+
* `defaultTwimlOptions` → `perCall`.
|
|
4961
|
+
*
|
|
4962
|
+
* `customParameters` replaces wholesale when set at a higher-priority layer —
|
|
4963
|
+
* there's no per-key merging.
|
|
4964
|
+
*/
|
|
4965
|
+
protected buildTwimlOptions(host: VoiceTwiMLOptionsMediaStreams | undefined, perCall: VoiceTwiMLOptionsMediaStreams | undefined): VoiceTwiMLOptionsMediaStreams;
|
|
4966
|
+
}
|
|
4967
|
+
|
|
4968
|
+
/** Options accepted by {@link MediaStreamsProviderConfig}. */
|
|
4969
|
+
interface MediaStreamsProviderConfigOptions extends BaseChannelOptions {
|
|
4970
|
+
/**
|
|
4971
|
+
* Static `VoiceTwiMLOptionsMediaStreams` applied to every inbound call.
|
|
4972
|
+
* Per-call customization is registered via
|
|
4973
|
+
* `VoiceChannel.onInboundCallTwiml(...)`, which takes precedence over this.
|
|
4974
|
+
*/
|
|
4975
|
+
defaultTwimlOptions?: VoiceTwiMLOptionsMediaStreams;
|
|
4976
|
+
}
|
|
4977
|
+
/**
|
|
4978
|
+
* Base configuration for a Media Streams (`<Connect><Stream>`) provider.
|
|
4979
|
+
*
|
|
4980
|
+
* Holds the transport-level settings every Media Streams provider shares,
|
|
4981
|
+
* independent of which model or protocol runs over the stream.
|
|
4982
|
+
*/
|
|
4983
|
+
declare class MediaStreamsProviderConfig extends VoiceProviderConfig {
|
|
4984
|
+
/**
|
|
4985
|
+
* Static `VoiceTwiMLOptionsMediaStreams` applied to every inbound call.
|
|
4986
|
+
* Per-call customization is registered via
|
|
4987
|
+
* `VoiceChannel.onInboundCallTwiml(...)`, which takes precedence over this.
|
|
4988
|
+
*/
|
|
4989
|
+
readonly defaultTwimlOptions?: VoiceTwiMLOptionsMediaStreams;
|
|
4990
|
+
constructor(options?: MediaStreamsProviderConfigOptions);
|
|
4991
|
+
}
|
|
4992
|
+
|
|
4993
|
+
/**
|
|
4994
|
+
* TAC Tool class with helper methods for LLM integration
|
|
4995
|
+
*
|
|
4996
|
+
* Matches Python's TACTool dataclass with conversion methods.
|
|
4997
|
+
*/
|
|
4998
|
+
declare class TACTool<TParams = unknown, TResult = unknown> {
|
|
4999
|
+
readonly name: string;
|
|
5000
|
+
readonly description: string;
|
|
5001
|
+
readonly parameters: JSONSchema;
|
|
5002
|
+
readonly implementation: ToolFunction<TParams, TResult>;
|
|
5003
|
+
constructor(name: string, description: string, parameters: JSONSchema, implementation: ToolFunction<TParams, TResult>);
|
|
5004
|
+
/**
|
|
5005
|
+
* Convert to OpenAI function calling format
|
|
5006
|
+
*/
|
|
5007
|
+
toOpenAIFormat(): OpenAITool;
|
|
5008
|
+
/**
|
|
5009
|
+
* Convert to OpenAI Realtime function calling format.
|
|
5010
|
+
*
|
|
5011
|
+
* Unlike {@link TACTool.toOpenAIFormat} (Chat Completions, which nests the
|
|
5012
|
+
* schema under a `function` key), Realtime's `session.tools` expects the
|
|
5013
|
+
* fields flat on the tool object.
|
|
5014
|
+
*/
|
|
5015
|
+
toRealtimeFormat(): OpenAIRealtimeTool;
|
|
5016
|
+
/**
|
|
5017
|
+
* Convert to Anthropic tool calling format
|
|
5018
|
+
*/
|
|
5019
|
+
toAnthropicFormat(): AnthropicTool;
|
|
5020
|
+
/**
|
|
5021
|
+
* Convert to JSON string (OpenAI format by default)
|
|
5022
|
+
*/
|
|
5023
|
+
toJSON(): string;
|
|
5024
|
+
/**
|
|
5025
|
+
* Convert this tool to an OpenAI Agents SDK `FunctionTool` instance.
|
|
5026
|
+
*
|
|
5027
|
+
* Unlike `toOpenAIFormat` and `toAnthropicFormat` (which return plain
|
|
5028
|
+
* objects consumed by HTTP APIs), the OpenAI Agents SDK dispatches on tool
|
|
5029
|
+
* *type*, so this returns a live `tool(...)` object with an invoke callback
|
|
5030
|
+
* that calls this tool and JSON-encodes the result.
|
|
5031
|
+
*
|
|
5032
|
+
* Requires the `@openai/agents` package:
|
|
5033
|
+
*
|
|
5034
|
+
* npm install @openai/agents
|
|
5035
|
+
*
|
|
5036
|
+
* @returns A FunctionTool ready to pass to `new Agent({ tools: [...] })`.
|
|
5037
|
+
*/
|
|
5038
|
+
toOpenAIAgentsSDKTool(): Promise<any>;
|
|
5039
|
+
}
|
|
5040
|
+
/**
|
|
5041
|
+
* Create a tool directly with all parameters
|
|
5042
|
+
*
|
|
5043
|
+
* Simplified approach matching Python's create_tool function.
|
|
5044
|
+
* No builder pattern - just a simple function call.
|
|
5045
|
+
*/
|
|
5046
|
+
declare function defineTool<TParams = unknown, TResult = unknown>(name: string, description: string, parameters: JSONSchema, implementation: ToolFunction<TParams, TResult>): TACTool<TParams, TResult>;
|
|
5047
|
+
|
|
5048
|
+
/**
|
|
5049
|
+
* Parameters for memory retrieval tool
|
|
5050
|
+
*/
|
|
5051
|
+
interface MemoryRetrievalParams {
|
|
5052
|
+
query?: string;
|
|
5053
|
+
beginDate?: string;
|
|
5054
|
+
endDate?: string;
|
|
5055
|
+
observationsLimit?: number;
|
|
5056
|
+
summariesLimit?: number;
|
|
5057
|
+
communicationsLimit?: number;
|
|
5058
|
+
relevanceThreshold?: number;
|
|
5059
|
+
}
|
|
5060
|
+
/**
|
|
5061
|
+
* Create memory retrieval tool.
|
|
5062
|
+
*
|
|
5063
|
+
* @param memoryClient - Memory client instance (must be initialized with storeId)
|
|
5064
|
+
* @param profileId - Optional profile ID for memory retrieval
|
|
5065
|
+
* @param conversationId - Optional conversation ID for memory retrieval
|
|
5066
|
+
* @param options - Optional overrides for tool metadata.
|
|
5067
|
+
* @param options.name - Tool name exposed to the LLM. Defaults to `retrieve_profile_memory`.
|
|
5068
|
+
* @param options.description - Tool description exposed to the LLM. Defaults to a
|
|
5069
|
+
* generic "retrieve memories" prompt.
|
|
5070
|
+
*/
|
|
5071
|
+
declare function createMemoryRetrievalTool(memoryClient: MemoryClient, profileId?: string, conversationId?: string, options?: {
|
|
5072
|
+
name?: string;
|
|
5073
|
+
description?: string;
|
|
5074
|
+
}): TACTool<MemoryRetrievalParams, MemoryRetrievalResponse>;
|
|
5075
|
+
/**
|
|
5076
|
+
* Create factory function for memory tools
|
|
5077
|
+
*
|
|
5078
|
+
* @param memoryClient - Memory client instance (must be initialized with storeId)
|
|
5079
|
+
*/
|
|
5080
|
+
declare function createMemoryTools(memoryClient: MemoryClient): {
|
|
5081
|
+
forProfile: (profileId: string, conversationId?: string) => TACTool<MemoryRetrievalParams, MemoryRetrievalResponse>;
|
|
5082
|
+
forSession: (profileId?: string, conversationId?: string) => TACTool<MemoryRetrievalParams, MemoryRetrievalResponse>;
|
|
5083
|
+
};
|
|
5084
|
+
|
|
5085
|
+
/**
|
|
5086
|
+
* Parameters for send message tool
|
|
5087
|
+
*/
|
|
5088
|
+
interface SendMessageParams {
|
|
5089
|
+
message: string;
|
|
5090
|
+
metadata?: Record<string, unknown>;
|
|
5091
|
+
}
|
|
5092
|
+
/**
|
|
5093
|
+
* Result from send message tool
|
|
5094
|
+
*/
|
|
5095
|
+
interface SendMessageResult {
|
|
5096
|
+
success: boolean;
|
|
5097
|
+
message_id?: string;
|
|
5098
|
+
error?: string;
|
|
5099
|
+
}
|
|
5100
|
+
/**
|
|
5101
|
+
* Create send message tool
|
|
5102
|
+
*/
|
|
5103
|
+
declare function createSendMessageTool(channel: BaseChannel, conversationId: ConversationId): TACTool<SendMessageParams, SendMessageResult>;
|
|
5104
|
+
/**
|
|
5105
|
+
* Create factory function for messaging tools
|
|
5106
|
+
*/
|
|
5107
|
+
declare function createMessagingTools(): {
|
|
5108
|
+
forConversation: (channel: BaseChannel, conversationId: ConversationId) => TACTool<SendMessageParams, SendMessageResult>;
|
|
5109
|
+
};
|
|
5110
|
+
|
|
5111
|
+
/**
|
|
5112
|
+
* Handoff tool for the Twilio Agent Connect.
|
|
5113
|
+
*
|
|
5114
|
+
* Generic Studio-backed handoff that routes a conversation to a human agent.
|
|
5115
|
+
* Produces a structured HandoffPayload and delivers it as a Twilio Studio
|
|
5116
|
+
* Execution (voice via `<Connect action>`, digital channels via direct POST).
|
|
5117
|
+
*/
|
|
5118
|
+
|
|
5119
|
+
/**
|
|
5120
|
+
* Build a HandoffPayload from session context and attributes.
|
|
5121
|
+
*
|
|
5122
|
+
* Useful for custom handoff tools that want TAC's payload shape without
|
|
5123
|
+
* the Studio-specific delivery in `postStudioHandoff`.
|
|
5124
|
+
*/
|
|
5125
|
+
declare function buildHandoffPayload(session: ConversationSession, memoryStoreId: string, attributes: Record<string, unknown>): HandoffPayload;
|
|
5126
|
+
/**
|
|
5127
|
+
* POST a handoff payload to a Twilio Studio Flow Executions endpoint.
|
|
5128
|
+
*
|
|
5129
|
+
* Emits the Twilio Studio Executions API wire format: form-encoded
|
|
5130
|
+
* `To` / `From` / `Parameters` fields with HTTP Basic auth.
|
|
5131
|
+
* `Parameters` is a JSON string keyed under `HandoffData` so Studio
|
|
5132
|
+
* can reference it via `{{flow.data.HandoffData.*}}`.
|
|
5133
|
+
*/
|
|
5134
|
+
declare function postStudioHandoff(payload: HandoffPayload, session: ConversationSession, options: {
|
|
5135
|
+
handoffUrl: string;
|
|
5136
|
+
fromAddress: string;
|
|
5137
|
+
apiKey: string;
|
|
5138
|
+
apiSecret: string;
|
|
5139
|
+
}): Promise<void>;
|
|
5140
|
+
/**
|
|
5141
|
+
* Result returned by the handoff tool.
|
|
5142
|
+
*/
|
|
5143
|
+
interface HandoffResult {
|
|
5144
|
+
status: 'handoff_initiated' | 'handoff_failed';
|
|
5145
|
+
channel: string;
|
|
5146
|
+
error?: string;
|
|
5147
|
+
}
|
|
5148
|
+
interface HandoffParams {
|
|
5149
|
+
reason: string;
|
|
5150
|
+
}
|
|
5151
|
+
/**
|
|
5152
|
+
* Create a handoff tool that delivers in the Twilio Studio Executions API shape.
|
|
5153
|
+
*
|
|
5154
|
+
* The returned tool exposes only `handoff({ reason })` to the LLM. All other
|
|
5155
|
+
* dependencies (TAC instance, session, static attributes) are captured in the
|
|
5156
|
+
* closure.
|
|
5157
|
+
*
|
|
5158
|
+
* On digital channels, the tool POSTs to the Studio Flow Executions endpoint
|
|
5159
|
+
* derived from `tac.getConfig().studioHandoffFlowSid`. For voice channels,
|
|
5160
|
+
* the payload is stored on the session and the voice channel automatically
|
|
5161
|
+
* sends the WS `end` message with `handoffData` after the LLM's final
|
|
5162
|
+
* response is delivered.
|
|
5163
|
+
*
|
|
5164
|
+
* The tool also sets the conversation to INACTIVE and clears status callbacks
|
|
5165
|
+
* to prevent further webhook events from being routed to TAC.
|
|
5166
|
+
*
|
|
5167
|
+
* **Not available in voice-only mode.** This tool requires Conversation
|
|
5168
|
+
* Orchestrator for conversation state management and Conversation Memory for
|
|
5169
|
+
* the handoff payload. In voice-only mode, implement your own handoff by
|
|
5170
|
+
* setting `session.pendingHandoffData` directly — the voice channel will
|
|
5171
|
+
* send the WS `end` message with your payload, and your `<Connect action>`
|
|
5172
|
+
* URL handler can route the call accordingly.
|
|
5173
|
+
*
|
|
5174
|
+
* @throws Error if `tac.getConfig().studioHandoffFlowSid` is unset, if
|
|
5175
|
+
* Conversation Orchestrator is not configured (voice-only mode), or if
|
|
5176
|
+
* the memory store ID was not resolved at startup.
|
|
5177
|
+
*/
|
|
5178
|
+
declare function createStudioHandoffTool(tac: TAC, session: ConversationSession, options?: {
|
|
5179
|
+
attributes?: Record<string, unknown>;
|
|
5180
|
+
name?: string;
|
|
5181
|
+
description?: string;
|
|
5182
|
+
}): TACTool<HandoffParams, HandoffResult>;
|
|
5183
|
+
|
|
5184
|
+
/**
|
|
5185
|
+
* Parameters for knowledge search tool (visible to LLM)
|
|
5186
|
+
*/
|
|
5187
|
+
interface KnowledgeSearchParams {
|
|
5188
|
+
query: string;
|
|
5189
|
+
}
|
|
5190
|
+
/**
|
|
5191
|
+
* Configuration for knowledge search tool
|
|
5192
|
+
*/
|
|
5193
|
+
interface KnowledgeToolConfig {
|
|
5194
|
+
name?: string;
|
|
5195
|
+
description?: string;
|
|
5196
|
+
topK?: number;
|
|
5197
|
+
}
|
|
5198
|
+
/**
|
|
5199
|
+
* Create knowledge search tool with explicit name and description
|
|
5200
|
+
*
|
|
5201
|
+
* @param knowledgeClient - The Knowledge client instance
|
|
5202
|
+
* @param knowledgeBaseId - The knowledge base ID to search
|
|
5203
|
+
* @param config - Configuration with required name and description
|
|
5204
|
+
* @returns TACTool configured for knowledge search
|
|
5205
|
+
*/
|
|
5206
|
+
declare function createKnowledgeSearchTool(knowledgeClient: KnowledgeClient, knowledgeBaseId: string, config: {
|
|
5207
|
+
name: string;
|
|
5208
|
+
description: string;
|
|
5209
|
+
topK?: number;
|
|
5210
|
+
}): TACTool<KnowledgeSearchParams, KnowledgeChunkResult[]>;
|
|
5211
|
+
/**
|
|
5212
|
+
* Create knowledge search tool with auto-fetched metadata from knowledge base
|
|
5213
|
+
*
|
|
5214
|
+
* This async version fetches the knowledge base metadata to auto-generate
|
|
5215
|
+
* the tool name and description if not provided.
|
|
5216
|
+
*
|
|
5217
|
+
* @param knowledgeClient - The Knowledge client instance
|
|
5218
|
+
* @param knowledgeBaseId - The knowledge base ID to search
|
|
5219
|
+
* @param config - Optional configuration (name/description auto-generated if not provided)
|
|
5220
|
+
* @returns Promise containing TACTool configured for knowledge search
|
|
5221
|
+
*/
|
|
5222
|
+
declare function createKnowledgeSearchToolAsync(knowledgeClient: KnowledgeClient, knowledgeBaseId: string, config?: KnowledgeToolConfig): Promise<TACTool<KnowledgeSearchParams, KnowledgeChunkResult[]>>;
|
|
5223
|
+
/**
|
|
5224
|
+
* Create factory for knowledge tools
|
|
5225
|
+
*
|
|
5226
|
+
* @param knowledgeClient - The Knowledge client instance
|
|
5227
|
+
* @returns Factory object with methods to create knowledge tools
|
|
5228
|
+
*/
|
|
5229
|
+
declare function createKnowledgeTools(knowledgeClient: KnowledgeClient): {
|
|
5230
|
+
forKnowledgeBase: (knowledgeBaseId: string, config: {
|
|
5231
|
+
name: string;
|
|
5232
|
+
description: string;
|
|
5233
|
+
topK?: number;
|
|
5234
|
+
}) => TACTool<KnowledgeSearchParams, KnowledgeChunkResult[]>;
|
|
5235
|
+
forKnowledgeBaseAsync: (knowledgeBaseId: string, config?: KnowledgeToolConfig) => Promise<TACTool<KnowledgeSearchParams, KnowledgeChunkResult[]>>;
|
|
5236
|
+
};
|
|
5237
|
+
|
|
5238
|
+
/**
|
|
5239
|
+
* Options accepted by {@link MediaStreamsOpenAIProviderConfig}.
|
|
5240
|
+
*/
|
|
5241
|
+
interface MediaStreamsOpenAIProviderConfigOptions extends MediaStreamsProviderConfigOptions {
|
|
5242
|
+
/**
|
|
5243
|
+
* OpenAI API key. Defaults to the `OPENAI_API_KEY` environment variable.
|
|
5244
|
+
*/
|
|
5245
|
+
openaiApiKey?: string;
|
|
5246
|
+
/**
|
|
5247
|
+
* Executable `TACTool` implementations, looked up by name to run mid-call
|
|
5248
|
+
* tool requests. This alone does not tell the model these tools exist — the
|
|
5249
|
+
* session config sent to OpenAI must separately declare each tool's schema.
|
|
5250
|
+
*/
|
|
5251
|
+
tools?: TACTool<never, unknown>[];
|
|
5252
|
+
/**
|
|
5253
|
+
* Session configuration sent to OpenAI once the model connects — used for any
|
|
5254
|
+
* call that doesn't supply its own via
|
|
5255
|
+
* {@link MediaStreamsOpenAIProviderConfigOptions.onInboundCallSessionConfig}
|
|
5256
|
+
* or per-call outbound options.
|
|
5257
|
+
*
|
|
5258
|
+
* If using {@link MediaStreamsOpenAIProviderConfigOptions.tools}, this config
|
|
5259
|
+
* must separately list each tool's schema — it is passed to OpenAI as-is,
|
|
5260
|
+
* with no tool schemas merged in.
|
|
5261
|
+
*/
|
|
5262
|
+
defaultSessionConfig?: Record<string, unknown>;
|
|
5263
|
+
/**
|
|
5264
|
+
* Per-inbound-call override for
|
|
5265
|
+
* {@link MediaStreamsOpenAIProviderConfigOptions.defaultSessionConfig},
|
|
5266
|
+
* called with the `TwiMLRequest`. Its return value is used verbatim (not
|
|
5267
|
+
* merged with `defaultSessionConfig`); return `null` to fall back to it.
|
|
5268
|
+
* Outbound calls don't use this — they pass their session config per call.
|
|
5269
|
+
*/
|
|
5270
|
+
onInboundCallSessionConfig?: (req: TwiMLRequest) => Promise<Record<string, unknown> | null>;
|
|
5271
|
+
}
|
|
5272
|
+
/**
|
|
5273
|
+
* Base configuration for an OpenAI-backed Media Streams provider.
|
|
5274
|
+
*
|
|
5275
|
+
* Holds what every OpenAI-backed Media Streams provider needs — credentials,
|
|
5276
|
+
* executable tools, and the session config sent when the model connects —
|
|
5277
|
+
* independent of which OpenAI API runs over the stream.
|
|
5278
|
+
*/
|
|
5279
|
+
declare class MediaStreamsOpenAIProviderConfig extends MediaStreamsProviderConfig {
|
|
5280
|
+
/** OpenAI API key. Defaults to the `OPENAI_API_KEY` environment variable. */
|
|
5281
|
+
readonly openaiApiKey: string;
|
|
5282
|
+
/**
|
|
5283
|
+
* Executable `TACTool` implementations, looked up by name to run mid-call
|
|
5284
|
+
* tool requests. This alone does not tell the model these tools exist — the
|
|
5285
|
+
* session config sent to OpenAI must separately declare each tool's schema.
|
|
5286
|
+
*/
|
|
5287
|
+
readonly tools: TACTool<never, unknown>[];
|
|
5288
|
+
/**
|
|
5289
|
+
* Session configuration sent to OpenAI once the model connects — used for any
|
|
5290
|
+
* call that doesn't supply its own via
|
|
5291
|
+
* {@link MediaStreamsOpenAIProviderConfig.onInboundCallSessionConfig} or
|
|
5292
|
+
* per-call outbound options.
|
|
5293
|
+
*
|
|
5294
|
+
* If using {@link MediaStreamsOpenAIProviderConfig.tools}, this config must
|
|
5295
|
+
* separately list each tool's schema — it is passed to OpenAI as-is, with no
|
|
5296
|
+
* tool schemas merged in.
|
|
5297
|
+
*/
|
|
5298
|
+
readonly defaultSessionConfig?: Record<string, unknown>;
|
|
5299
|
+
/**
|
|
5300
|
+
* Per-inbound-call override for
|
|
5301
|
+
* {@link MediaStreamsOpenAIProviderConfig.defaultSessionConfig}, called with
|
|
5302
|
+
* the `TwiMLRequest`. Its return value is used verbatim (not merged with
|
|
5303
|
+
* `defaultSessionConfig`); return `null` to fall back to it. Outbound calls
|
|
5304
|
+
* don't use this — they pass their session config per call.
|
|
5305
|
+
*/
|
|
5306
|
+
readonly onInboundCallSessionConfig?: (req: TwiMLRequest) => Promise<Record<string, unknown> | null>;
|
|
5307
|
+
constructor(options?: MediaStreamsOpenAIProviderConfigOptions);
|
|
5308
|
+
}
|
|
5309
|
+
|
|
5310
|
+
/**
|
|
5311
|
+
* Both legs of one call's audio bridge — the Twilio-facing socket and the
|
|
5312
|
+
* model-facing socket — live here together, rather than in two parallel maps
|
|
5313
|
+
* keyed by conversation id that could drift out of sync.
|
|
5314
|
+
*
|
|
5315
|
+
* `streamSid` and `transcript` live on `ConversationSession.metadata` instead,
|
|
5316
|
+
* not here: this map is deleted before `onConversationEnded` fires, so anything
|
|
5317
|
+
* a handler needs to read after the call ends must survive on the session.
|
|
5318
|
+
*
|
|
5319
|
+
* @internal
|
|
5320
|
+
*/
|
|
5321
|
+
declare class MediaStreamsOpenAICallState {
|
|
5322
|
+
twilioWs: WebSocket | null;
|
|
5323
|
+
modelWs: WebSocket | null;
|
|
5324
|
+
/**
|
|
5325
|
+
* Resolves `true` once this call's model socket is open and its session
|
|
5326
|
+
* config has been sent, or `false` if that handshake failed. `null` until the
|
|
5327
|
+
* handshake has been started.
|
|
5328
|
+
*
|
|
5329
|
+
* Twilio begins streaming caller audio as soon as the media stream opens,
|
|
5330
|
+
* which is well before the OpenAI handshake completes. Caller audio waits on
|
|
5331
|
+
* this promise rather than being written to a socket that does not exist
|
|
5332
|
+
* yet, so a caller who speaks the instant the call connects is not clipped.
|
|
5333
|
+
* Every frame awaits this same promise, so the frames resume in the order
|
|
5334
|
+
* they arrived.
|
|
5335
|
+
*
|
|
5336
|
+
* It resolves rather than rejects: a failed handshake is reported once, by
|
|
5337
|
+
* the code that opened the socket, not once per waiting frame.
|
|
5338
|
+
*/
|
|
5339
|
+
modelReady: Promise<boolean> | null;
|
|
5340
|
+
}
|
|
5341
|
+
|
|
5342
|
+
/**
|
|
5343
|
+
* Identifies this SDK to OpenAI on every WebSocket connection, per OpenAI's
|
|
5344
|
+
* requested User-Agent pattern: [Company/Library name]/[Language] [Version].
|
|
5345
|
+
*
|
|
5346
|
+
* Deliberately unlike the Twilio-facing User-Agent in `clients/base.ts`, which
|
|
5347
|
+
* follows Twilio's own convention instead.
|
|
5348
|
+
*/
|
|
5349
|
+
declare const OPENAI_USER_AGENT: string;
|
|
5350
|
+
/**
|
|
5351
|
+
* Shared scaffolding for a {@link VoiceProvider} bridging Twilio Media Streams
|
|
5352
|
+
* to an OpenAI real-time voice API.
|
|
5353
|
+
*
|
|
5354
|
+
* Holds only what's identical across every such provider; each subclass still
|
|
5355
|
+
* owns its own `initiateOutboundConversation`, `handleWebSocket`,
|
|
5356
|
+
* `registerCall`, `connectModel`, {@link dispatchModelEvent},
|
|
5357
|
+
* `handleFunctionCall`, and `cleanupCall`.
|
|
5358
|
+
*
|
|
5359
|
+
* Generic over `TCallState` (bound to `MediaStreamsOpenAICallState`) so
|
|
5360
|
+
* {@link calls} keeps each subclass's own call-state shape instead of widening
|
|
5361
|
+
* to the shared base everywhere it's read.
|
|
5362
|
+
*/
|
|
5363
|
+
declare abstract class MediaStreamsOpenAIProvider<TCallState extends MediaStreamsOpenAICallState> extends VoiceProvider {
|
|
5364
|
+
/**
|
|
5365
|
+
* The owning channel's logger, so this provider logs under the same name the
|
|
5366
|
+
* rest of the voice channel does.
|
|
5367
|
+
*/
|
|
5368
|
+
protected readonly logger: Logger;
|
|
5369
|
+
/** Executable tools from the config, looked up by the name the model sends. */
|
|
5370
|
+
protected readonly toolsByName: Map<string, TACTool>;
|
|
5371
|
+
/** Per-call transport state, keyed by conversation id. */
|
|
5372
|
+
protected readonly calls: Map<ConversationId, TCallState>;
|
|
5373
|
+
protected readonly config: MediaStreamsOpenAIProviderConfig;
|
|
5374
|
+
protected readonly tacConfig: TACConfig;
|
|
5375
|
+
protected readonly twimlBuilder: TwiMLBuilderMediaStreams;
|
|
5376
|
+
/**
|
|
5377
|
+
* Session config overrides awaiting the call they belong to.
|
|
5378
|
+
*
|
|
5379
|
+
* Inbound entries are keyed by call SID (known when the TwiML webhook is
|
|
5380
|
+
* answered); a subclass keys its outbound entries by whatever token it round
|
|
5381
|
+
* trips through the stream's custom parameters.
|
|
5382
|
+
*/
|
|
5383
|
+
protected readonly pendingSessionConfigs: Map<string, Record<string, unknown>>;
|
|
5384
|
+
/**
|
|
5385
|
+
* Expiry timers for the inbound {@link pendingSessionConfigs} entries, keyed
|
|
5386
|
+
* by the same call SID. Each fires once to purge a stash whose Media Stream
|
|
5387
|
+
* never connected; a normal connect cancels it in the subclass's
|
|
5388
|
+
* `registerCall`. Outbound entries are keyed by token instead and are not
|
|
5389
|
+
* tracked here.
|
|
5390
|
+
*/
|
|
5391
|
+
private readonly pendingInboundExpiries;
|
|
5392
|
+
constructor(channel: VoiceChannel, tacConfig: TACConfig, config: MediaStreamsOpenAIProviderConfig);
|
|
5393
|
+
/** The Twilio-facing WebSocket for a conversation, if one is tracked. */
|
|
5394
|
+
getWebSocket(conversationId: ConversationId): WebSocket | null;
|
|
5395
|
+
/**
|
|
5396
|
+
* Open a WebSocket and resolve once it is ready to carry traffic.
|
|
5397
|
+
*
|
|
5398
|
+
* Isolated from each subclass's `connectModel` so tests can substitute a
|
|
5399
|
+
* socket without reaching the network.
|
|
5400
|
+
*
|
|
5401
|
+
* A resolved socket always carries at least one `'error'` listener, whatever
|
|
5402
|
+
* the caller does with it next.
|
|
5403
|
+
*
|
|
5404
|
+
* @internal
|
|
5405
|
+
*/
|
|
5406
|
+
openModelSocket(url: string, headers: Record<string, string>): Promise<WebSocket>;
|
|
5407
|
+
/**
|
|
5408
|
+
* The transcript captured so far for an in-progress call.
|
|
5409
|
+
*
|
|
5410
|
+
* It lives on `ConversationSession.metadata.transcript`, so once the call
|
|
5411
|
+
* ends and the session is dropped it is no longer reachable here — read it
|
|
5412
|
+
* from the session an `onConversationEnded` handler receives instead.
|
|
5413
|
+
*/
|
|
5414
|
+
getTranscript(conversationId: ConversationId): Record<string, string>[];
|
|
5415
|
+
/**
|
|
5416
|
+
* The session config stashed for `key` — a call SID for inbound calls, a
|
|
5417
|
+
* token for outbound ones.
|
|
5418
|
+
*
|
|
5419
|
+
* @internal
|
|
5420
|
+
*/
|
|
5421
|
+
peekPendingSessionConfig(key: string): Record<string, unknown> | undefined;
|
|
5422
|
+
/**
|
|
5423
|
+
* How many session config overrides are waiting for their call.
|
|
5424
|
+
*
|
|
5425
|
+
* @internal
|
|
5426
|
+
*/
|
|
5427
|
+
pendingSessionConfigCount(): number;
|
|
5428
|
+
/**
|
|
5429
|
+
* Start the clock on an inbound stash, so a call whose Media Stream never
|
|
5430
|
+
* connects cannot strand its override in {@link pendingSessionConfigs} until
|
|
5431
|
+
* shutdown.
|
|
5432
|
+
*
|
|
5433
|
+
* Unref'd: a two-minute timer must not be what keeps the process alive after
|
|
5434
|
+
* the call it belongs to is long over. Re-arming replaces any prior timer for
|
|
5435
|
+
* the same call SID, so a duplicate inbound webhook can't orphan one.
|
|
5436
|
+
*/
|
|
5437
|
+
private armInboundConfigExpiry;
|
|
5438
|
+
/**
|
|
5439
|
+
* Stop the clock on an inbound stash, once the call it belongs to has
|
|
5440
|
+
* connected and is about to consume the entry. A no-op for outbound calls,
|
|
5441
|
+
* which key their stash by token and never arm one — the subclass calls this
|
|
5442
|
+
* with the call SID for every `start`, inbound or not.
|
|
5443
|
+
*
|
|
5444
|
+
* @internal
|
|
5445
|
+
*/
|
|
5446
|
+
protected cancelInboundConfigExpiry(callSid: string): void;
|
|
5447
|
+
/**
|
|
5448
|
+
* The executable tool the model would run for `name`, if the config supplied
|
|
5449
|
+
* one.
|
|
5450
|
+
*
|
|
5451
|
+
* @internal
|
|
5452
|
+
*/
|
|
5453
|
+
peekTool(name: string): TACTool | undefined;
|
|
5454
|
+
/**
|
|
5455
|
+
* Build the `<Connect><Stream>` TwiML for an inbound call.
|
|
5456
|
+
*
|
|
5457
|
+
* TwiML fields are merged per-field, highest precedence first:
|
|
5458
|
+
* 1. Output of the customizer registered via
|
|
5459
|
+
* `VoiceChannel.onInboundCallTwiml(...)`, if configured and
|
|
5460
|
+
* `twimlRequest` is given
|
|
5461
|
+
* 2. `MediaStreamsProviderConfig.defaultTwimlOptions` — channel-wide
|
|
5462
|
+
* defaults
|
|
5463
|
+
* 3. `options.hostTwimlOptions` — per-call transport facts supplied by the
|
|
5464
|
+
* host
|
|
5465
|
+
* 4. TAC defaults: the WebSocket URL derived from
|
|
5466
|
+
* `TACConfig.voicePublicDomain` + `voiceWebsocketPath`
|
|
5467
|
+
*
|
|
5468
|
+
* Also runs `MediaStreamsOpenAIProviderConfig.onInboundCallSessionConfig`, if
|
|
5469
|
+
* set, and stashes its result for the call to pick up once it connects. The
|
|
5470
|
+
* hook runs only after the TwiML builds, so a call that never connects
|
|
5471
|
+
* leaves nothing stashed behind it.
|
|
5472
|
+
*
|
|
5473
|
+
* @param twimlRequest - Parsed Twilio webhook fields for the inbound call.
|
|
5474
|
+
* @param options - Additional per-call inputs.
|
|
5475
|
+
* @param options.hostTwimlOptions - Per-call TwiML supplied by a custom
|
|
5476
|
+
* in-process host.
|
|
5477
|
+
* @throws {TypeError} if either the host options or the customizer's output
|
|
5478
|
+
* is not a `VoiceTwiMLOptionsMediaStreams`.
|
|
5479
|
+
* @throws {Error} if no WebSocket URL can be resolved — none of the TwiML
|
|
5480
|
+
* layers set one and `TACConfig.voicePublicDomain` is unset.
|
|
5481
|
+
*/
|
|
5482
|
+
handleIncomingCall(twimlRequest?: TwiMLRequest, options?: {
|
|
5483
|
+
hostTwimlOptions?: VoiceTwiMLOptions;
|
|
5484
|
+
}): Promise<string>;
|
|
5485
|
+
/**
|
|
5486
|
+
* Narrow provider-agnostic {@link VoiceTwiMLOptions} to this provider's
|
|
5487
|
+
* concrete shape. `VoiceProvider.handleIncomingCall` is typed against the
|
|
5488
|
+
* base so every provider can accept its own TwiML options, so the Media
|
|
5489
|
+
* Streams shape has to be established at runtime.
|
|
5490
|
+
*
|
|
5491
|
+
* @param value - Options from a caller or the application customizer.
|
|
5492
|
+
* @param caller - Name of the calling method, for the error message.
|
|
5493
|
+
* @param label - What produced `value`, for the error message.
|
|
5494
|
+
*/
|
|
5495
|
+
protected narrowTwimlOptions(value: VoiceTwiMLOptions | undefined, caller: string, label: string): VoiceTwiMLOptionsMediaStreams | undefined;
|
|
5496
|
+
/**
|
|
5497
|
+
* Parse one frame off the model socket and hand it to
|
|
5498
|
+
* {@link dispatchModelEvent}.
|
|
5499
|
+
*
|
|
5500
|
+
* A failure here is logged and skipped rather than ending the call: one
|
|
5501
|
+
* malformed delta must not hang up on the caller.
|
|
5502
|
+
*
|
|
5503
|
+
* @internal
|
|
5504
|
+
*/
|
|
5505
|
+
handleModelMessage(conversationId: ConversationId, raw: Buffer | string): Promise<void>;
|
|
5506
|
+
/**
|
|
5507
|
+
* Interpret one event received from the model. Protocol-specific —
|
|
5508
|
+
* implemented by each subclass.
|
|
5509
|
+
*/
|
|
5510
|
+
protected abstract dispatchModelEvent(conversationId: ConversationId, session: ConversationSession, event: Record<string, unknown>): Promise<void>;
|
|
5511
|
+
/**
|
|
5512
|
+
* Look up a model-requested tool by name, run it, and return its output.
|
|
5513
|
+
*
|
|
5514
|
+
* Errors are returned as part of the output rather than thrown, so a bad
|
|
5515
|
+
* tool call does not kill the call.
|
|
5516
|
+
*
|
|
5517
|
+
* @internal
|
|
5518
|
+
*/
|
|
5519
|
+
runToolCall(conversationId: ConversationId, name: string, argumentsJson: unknown): Promise<unknown>;
|
|
5520
|
+
/** Write one event to this call's model socket, if it still has one. */
|
|
5521
|
+
protected modelSend(conversationId: ConversationId, payload: Record<string, unknown>): void;
|
|
5522
|
+
/** Write one message to this call's Twilio socket, if it still has one. */
|
|
5523
|
+
protected twilioSend(conversationId: ConversationId, payload: Record<string, unknown>): void;
|
|
5524
|
+
/**
|
|
5525
|
+
* Always throws: the model streams its reply as audio straight to Twilio, so
|
|
5526
|
+
* this transport has no text response to send.
|
|
5527
|
+
*/
|
|
5528
|
+
sendResponse(_conversationId: ConversationId, _message: string, _metadata?: Record<string, unknown>): Promise<void>;
|
|
5529
|
+
/**
|
|
5530
|
+
* Drop this provider's Media Streams transport state on channel shutdown.
|
|
5531
|
+
*
|
|
5532
|
+
* Note: WebSocket connections are managed by the server and closed there.
|
|
5533
|
+
* This method only cleans up internal provider state — including session
|
|
5534
|
+
* config overrides stashed for calls that were placed but never connected.
|
|
5535
|
+
*/
|
|
5536
|
+
shutdown(): void;
|
|
5537
|
+
}
|
|
5538
|
+
|
|
5539
|
+
/**
|
|
5540
|
+
* Options accepted by {@link OpenAIRealtimeProviderConfig}.
|
|
5541
|
+
*/
|
|
5542
|
+
interface OpenAIRealtimeProviderConfigOptions extends MediaStreamsOpenAIProviderConfigOptions {
|
|
5543
|
+
/**
|
|
5544
|
+
* Executable `TACTool` implementations, looked up by name to run mid-call
|
|
5545
|
+
* tool requests. This alone does not tell the model these tools exist — also
|
|
5546
|
+
* add each tool's `toRealtimeFormat()` schema to
|
|
5547
|
+
* {@link OpenAIRealtimeProviderConfigOptions.defaultSessionConfig}'s `tools`
|
|
5548
|
+
* entry.
|
|
5549
|
+
*/
|
|
5550
|
+
tools?: TACTool<never, unknown>[];
|
|
5551
|
+
/**
|
|
5552
|
+
* If set, sent verbatim as `response.create`'s `response` payload when the
|
|
5553
|
+
* call connects — e.g. `{ instructions: 'Hi there!' }`. No SDK-added wrapping
|
|
5554
|
+
* text or language assumption.
|
|
5555
|
+
*/
|
|
5556
|
+
welcomeGreetingResponse?: Record<string, unknown>;
|
|
5557
|
+
/**
|
|
5558
|
+
* The `session.update` payload's `session` body, sent once the model connects
|
|
5559
|
+
* — used for any call that doesn't supply its own via
|
|
5560
|
+
* {@link OpenAIRealtimeProviderConfigOptions.onInboundCallSessionConfig} or
|
|
5561
|
+
* `InitiateVoiceConversationOptionsOpenAIRealtime`.
|
|
5562
|
+
*
|
|
5563
|
+
* See
|
|
5564
|
+
* https://developers.openai.com/api/reference/resources/realtime/client-events#session.update
|
|
5565
|
+
* for the schema. If using {@link OpenAIRealtimeProviderConfigOptions.tools},
|
|
5566
|
+
* its `tools` entry must separately list each tool's `toRealtimeFormat()`
|
|
5567
|
+
* schema — this config is passed to OpenAI as-is, with no tool schemas merged
|
|
5568
|
+
* in.
|
|
5569
|
+
*/
|
|
5570
|
+
defaultSessionConfig?: Record<string, unknown>;
|
|
5571
|
+
/**
|
|
5572
|
+
* Per-inbound-call override for
|
|
5573
|
+
* {@link OpenAIRealtimeProviderConfigOptions.defaultSessionConfig}, called
|
|
5574
|
+
* with the `TwiMLRequest`. Its return value is used verbatim (not merged with
|
|
5575
|
+
* `defaultSessionConfig`); return `null` to fall back to it. Outbound calls
|
|
5576
|
+
* don't use this — see `InitiateVoiceConversationOptionsOpenAIRealtime`.
|
|
5577
|
+
*/
|
|
5578
|
+
onInboundCallSessionConfig?: (req: TwiMLRequest) => Promise<Record<string, unknown> | null>;
|
|
5579
|
+
}
|
|
5580
|
+
/**
|
|
5581
|
+
* Configuration for `OpenAIRealtimeProvider`.
|
|
5582
|
+
*/
|
|
5583
|
+
declare class OpenAIRealtimeProviderConfig extends MediaStreamsOpenAIProviderConfig {
|
|
5584
|
+
/**
|
|
5585
|
+
* Executable `TACTool` implementations, looked up by name to run mid-call
|
|
5586
|
+
* tool requests. This alone does not tell the model these tools exist — also
|
|
5587
|
+
* add each tool's `toRealtimeFormat()` schema to
|
|
5588
|
+
* {@link OpenAIRealtimeProviderConfig.defaultSessionConfig}'s `tools` entry.
|
|
5589
|
+
*/
|
|
5590
|
+
readonly tools: TACTool<never, unknown>[];
|
|
5591
|
+
/**
|
|
5592
|
+
* If set, sent verbatim as `response.create`'s `response` payload when the
|
|
5593
|
+
* call connects — e.g. `{ instructions: 'Hi there!' }`. No SDK-added wrapping
|
|
5594
|
+
* text or language assumption.
|
|
5595
|
+
*/
|
|
5596
|
+
readonly welcomeGreetingResponse?: Record<string, unknown>;
|
|
5597
|
+
/**
|
|
5598
|
+
* The `session.update` payload's `session` body, sent once the model connects
|
|
5599
|
+
* — used for any call that doesn't supply its own via
|
|
5600
|
+
* {@link OpenAIRealtimeProviderConfig.onInboundCallSessionConfig} or
|
|
5601
|
+
* `InitiateVoiceConversationOptionsOpenAIRealtime`.
|
|
5602
|
+
*
|
|
5603
|
+
* See
|
|
5604
|
+
* https://developers.openai.com/api/reference/resources/realtime/client-events#session.update
|
|
5605
|
+
* for the schema. If using {@link OpenAIRealtimeProviderConfig.tools}, its
|
|
5606
|
+
* `tools` entry must separately list each tool's `toRealtimeFormat()` schema
|
|
5607
|
+
* — this config is passed to OpenAI as-is, with no tool schemas merged in.
|
|
5608
|
+
*/
|
|
5609
|
+
readonly defaultSessionConfig?: Record<string, unknown>;
|
|
5610
|
+
/**
|
|
5611
|
+
* Per-inbound-call override for
|
|
5612
|
+
* {@link OpenAIRealtimeProviderConfig.defaultSessionConfig}, called with the
|
|
5613
|
+
* `TwiMLRequest`. Its return value is used verbatim (not merged with
|
|
5614
|
+
* `defaultSessionConfig`); return `null` to fall back to it. Outbound calls
|
|
5615
|
+
* don't use this — see `InitiateVoiceConversationOptionsOpenAIRealtime`.
|
|
5616
|
+
*/
|
|
5617
|
+
readonly onInboundCallSessionConfig?: (req: TwiMLRequest) => Promise<Record<string, unknown> | null>;
|
|
5618
|
+
constructor(options?: OpenAIRealtimeProviderConfigOptions);
|
|
5619
|
+
createProvider(channel: VoiceChannel, tacConfig: TACConfig): VoiceProvider;
|
|
5620
|
+
}
|
|
5621
|
+
|
|
5622
|
+
/**
|
|
5623
|
+
* Per-call barge-in bookkeeping.
|
|
5624
|
+
*
|
|
5625
|
+
* For every delta that carries an `item_id`, `currentItemAudioMs` is never
|
|
5626
|
+
* more than the duration of audio actually sent to Twilio for
|
|
5627
|
+
* `lastAssistantItem`: it comes from delta byte counts rather than a
|
|
5628
|
+
* wall-clock estimate, floored per delta, so it can understate by up to a
|
|
5629
|
+
* millisecond per delta. `conversation.item.truncate` rejects an `audioEndMs`
|
|
5630
|
+
* beyond the item's real content, so understating is the safe direction.
|
|
5631
|
+
*
|
|
5632
|
+
* `responseActive` tracks whether a response is still being generated (set on
|
|
5633
|
+
* `response.created`, cleared on `response.done` or once barge-in cancels it) —
|
|
5634
|
+
* `response.cancel` with nothing in flight is itself an error event, so this
|
|
5635
|
+
* gates whether to send it.
|
|
5636
|
+
*
|
|
5637
|
+
* `mutedItemId` is the assistant item truncated by the last barge-in —
|
|
5638
|
+
* `response.output_audio.delta` events whose `item_id` matches it are dropped
|
|
5639
|
+
* as stale audio for a reply the caller already talked over. It is never
|
|
5640
|
+
* cleared; the next barge-in overwrites it.
|
|
5641
|
+
*
|
|
5642
|
+
* @internal
|
|
5643
|
+
*/
|
|
5644
|
+
declare class BargeInState {
|
|
5645
|
+
lastAssistantItem: string | null;
|
|
5646
|
+
currentItemAudioMs: number;
|
|
5647
|
+
mutedItemId: string | null;
|
|
5648
|
+
responseActive: boolean;
|
|
5649
|
+
}
|
|
5650
|
+
/**
|
|
5651
|
+
* Per-call bookkeeping the OpenAI Realtime provider needs beyond
|
|
5652
|
+
* `ConversationSession` and the sockets its base class holds.
|
|
5653
|
+
*
|
|
5654
|
+
* @internal
|
|
5655
|
+
*/
|
|
5656
|
+
declare class CallState$1 extends MediaStreamsOpenAICallState {
|
|
5657
|
+
/**
|
|
5658
|
+
* Tail of this call's model-event chain: each incoming OpenAI Realtime event
|
|
5659
|
+
* is appended to it rather than dispatched on arrival.
|
|
5660
|
+
*
|
|
5661
|
+
* The Python SDK reads model events in a sequential loop, so event N is fully
|
|
5662
|
+
* handled before N+1 is even read. `ws` delivers each event on its own
|
|
5663
|
+
* `'message'` emission with nothing serializing them, so without this chain a
|
|
5664
|
+
* `response.output_audio.delta` could advance the barge-in bookkeeping while
|
|
5665
|
+
* dispatch is suspended on the `handleFunctionCall` await, producing a
|
|
5666
|
+
* truncate that overruns the item it names.
|
|
5667
|
+
*/
|
|
5668
|
+
modelEvents: Promise<void>;
|
|
5669
|
+
readonly bargeIn: BargeInState;
|
|
5670
|
+
}
|
|
5671
|
+
|
|
5672
|
+
/**
|
|
5673
|
+
* The audio format both directions of a call must use.
|
|
5674
|
+
*
|
|
5675
|
+
* Twilio Media Streams always sends and expects 8kHz G.711 u-law — see
|
|
5676
|
+
* https://www.twilio.com/docs/voice/media-streams/websocket-messages. Not
|
|
5677
|
+
* configurable. No `rate` key: Realtime's `session.audio.*.format` schema
|
|
5678
|
+
* rejects it as unknown, since g711 is inherently fixed-rate.
|
|
5679
|
+
*/
|
|
5680
|
+
declare const TWILIO_AUDIO_FORMAT_FOR_REALTIME: {
|
|
5681
|
+
readonly type: "audio/pcmu";
|
|
5682
|
+
};
|
|
5683
|
+
/**
|
|
5684
|
+
* A {@link VoiceProvider} bridging Twilio Media Streams to OpenAI's Realtime
|
|
5685
|
+
* API.
|
|
5686
|
+
*
|
|
5687
|
+
* Twilio streams call audio to TAC's own WebSocket via `<Connect><Stream>`, and
|
|
5688
|
+
* this provider relays it to and from a second WebSocket it opens to OpenAI's
|
|
5689
|
+
* Realtime API.
|
|
5690
|
+
*
|
|
5691
|
+
* ```ts
|
|
5692
|
+
* const channel = new VoiceChannel(
|
|
5693
|
+
* tac,
|
|
5694
|
+
* new OpenAIRealtimeProviderConfig({ defaultSessionConfig: { instructions: '...' } })
|
|
5695
|
+
* );
|
|
5696
|
+
* ```
|
|
5697
|
+
*/
|
|
5698
|
+
declare class OpenAIRealtimeProvider extends MediaStreamsOpenAIProvider<CallState$1> {
|
|
5699
|
+
/** @internal */
|
|
5700
|
+
get providerId(): string;
|
|
5701
|
+
/**
|
|
5702
|
+
* The Realtime-specific config this provider was built with.
|
|
5703
|
+
*
|
|
5704
|
+
* `declare`: `target: ES2022` implies `useDefineForClassFields`, so a plain
|
|
5705
|
+
* redeclaration would emit a field definition that runs after `super()` and
|
|
5706
|
+
* overwrite the value the base constructor assigned with `undefined`. This
|
|
5707
|
+
* exists only to narrow the base's `MediaStreamsOpenAIProviderConfig` to the
|
|
5708
|
+
* Realtime shape `connectModel` reads `welcomeGreetingResponse` from.
|
|
5709
|
+
*
|
|
5710
|
+
* No `override`: TypeScript rejects it alongside `declare` (TS1243), and
|
|
5711
|
+
* `noImplicitOverride` does not require it for a `declare`d field.
|
|
5712
|
+
*/
|
|
5713
|
+
protected readonly config: OpenAIRealtimeProviderConfig;
|
|
5714
|
+
constructor(channel: VoiceChannel, tacConfig: TACConfig, config: OpenAIRealtimeProviderConfig);
|
|
5715
|
+
get channelName(): string;
|
|
5716
|
+
/**
|
|
5717
|
+
* Initiate an outbound voice conversation.
|
|
5718
|
+
*
|
|
5719
|
+
* Places an outbound call with inline TwiML that connects to a Media Stream.
|
|
5720
|
+
* Unlike inbound, there is no local session yet at this point — one is
|
|
5721
|
+
* created when Twilio's WebSocket `start` event arrives.
|
|
5722
|
+
*
|
|
5723
|
+
* TwiML fields are merged per-field — see
|
|
5724
|
+
* {@link TwiMLBuilderMediaStreams.build}. The WebSocket URL is derived from
|
|
5725
|
+
* `TACConfig.voicePublicDomain` + `TACConfig.voiceWebsocketPath` unless
|
|
5726
|
+
* overridden per-call via `options.websocketUrl`.
|
|
5727
|
+
*
|
|
5728
|
+
* Pass `InitiateVoiceConversationOptionsOpenAIRealtime` with `sessionConfig`
|
|
5729
|
+
* set to override `OpenAIRealtimeProviderConfig.defaultSessionConfig` for
|
|
5730
|
+
* this call.
|
|
5731
|
+
*
|
|
5732
|
+
* @param options - Outbound call options, validated in full against
|
|
5733
|
+
* `InitiateVoiceConversationOptionsOpenAIRealtimeSchema`.
|
|
5734
|
+
* @throws {TypeError} if `options` is not a valid
|
|
5735
|
+
* `InitiateVoiceConversationOptionsOpenAIRealtime` — including an unknown
|
|
5736
|
+
* key, a missing `to`, or a `twimlOptions` that is not a
|
|
5737
|
+
* `VoiceTwiMLOptionsMediaStreams`.
|
|
5738
|
+
* @throws {Error} if no WebSocket URL can be resolved — neither
|
|
5739
|
+
* `options.websocketUrl` nor any TwiML layer sets one and
|
|
5740
|
+
* `TACConfig.voicePublicDomain` is unset.
|
|
5741
|
+
*/
|
|
5742
|
+
initiateOutboundConversation(options: InitiateVoiceConversationOptions | InitiateVoiceConversationOptionsOpenAIRealtime): Promise<InitiateVoiceConversationResult>;
|
|
5743
|
+
/**
|
|
5744
|
+
* Drive one Twilio Media Stream connection from `start` to disconnect.
|
|
5745
|
+
*
|
|
5746
|
+
* Twilio's `start` event names the call, which opens the matching OpenAI
|
|
5747
|
+
* Realtime socket; from then on caller audio is relayed to the model and the
|
|
5748
|
+
* model's audio back to Twilio, until either side goes away. Whichever leg
|
|
5749
|
+
* closes first takes the other down with it, so a caller is never left
|
|
5750
|
+
* connected to silence.
|
|
5751
|
+
*
|
|
5752
|
+
* Twilio streams audio without waiting for the OpenAI socket to finish
|
|
5753
|
+
* connecting, so audio that arrives during that handshake is held and
|
|
5754
|
+
* forwarded, in order, once the model is ready — a caller who speaks the
|
|
5755
|
+
* instant the call connects is heard in full.
|
|
5756
|
+
*
|
|
5757
|
+
* Called by `VoiceChannel.handleWebSocketConnection`; hosts serve the socket
|
|
5758
|
+
* rather than calling this directly.
|
|
5759
|
+
*
|
|
5760
|
+
* @param ws - The accepted Twilio-facing WebSocket.
|
|
5761
|
+
*/
|
|
5762
|
+
handleWebSocket(ws: WebSocket): void;
|
|
5763
|
+
/**
|
|
5764
|
+
* Handle Twilio's `start` event: track the call and open its session.
|
|
5765
|
+
*
|
|
5766
|
+
* @param start - The event's `start` body, parsed against
|
|
5767
|
+
* `StreamStartMessageSchema`.
|
|
5768
|
+
* @param ws - The Twilio-facing socket this call arrived on.
|
|
5769
|
+
* @returns The conversation id — which is the call SID — and the call's
|
|
5770
|
+
* freshly tracked transport state.
|
|
5771
|
+
*/
|
|
5772
|
+
private registerCall;
|
|
5773
|
+
/**
|
|
5774
|
+
* Open this call's OpenAI Realtime socket and send its session config.
|
|
5775
|
+
*
|
|
5776
|
+
* @internal
|
|
5777
|
+
*/
|
|
5778
|
+
connectModel(conversationId: ConversationId): Promise<void>;
|
|
5779
|
+
/**
|
|
5780
|
+
* The validated session config for this call: its own stashed override if it
|
|
5781
|
+
* has one, else the channel-wide default.
|
|
5782
|
+
*
|
|
5783
|
+
* @throws {Error} if neither exists, if it has no `model`, or if either audio
|
|
5784
|
+
* direction is set to a format Twilio can't carry.
|
|
5785
|
+
*/
|
|
5786
|
+
private resolveSessionConfig;
|
|
5787
|
+
/**
|
|
5788
|
+
* Wire up the model socket: dispatch its events, and tear the call down when
|
|
5789
|
+
* it goes away.
|
|
5790
|
+
*
|
|
5791
|
+
* The Python SDK races its two read loops so the Twilio leg dies with the
|
|
5792
|
+
* model leg; `ws` is event-driven, so the same guarantee is a close/error
|
|
5793
|
+
* handler instead. Python's sequential read loop also handles each model
|
|
5794
|
+
* event to completion before reading the next, which `ws` does not — see
|
|
5795
|
+
* {@link CallState.modelEvents} for the chain that restores it.
|
|
5796
|
+
*/
|
|
5797
|
+
private attachModelHandlers;
|
|
5798
|
+
/**
|
|
5799
|
+
* Hang up the Twilio leg because the model leg is gone, then clean up. A
|
|
5800
|
+
* no-op once the call has already been cleaned up, so both the model socket's
|
|
5801
|
+
* `close` and its `error` can call it.
|
|
5802
|
+
*/
|
|
5803
|
+
private endCallFromModel;
|
|
5804
|
+
/** Apply one parsed OpenAI Realtime event to the call. */
|
|
5805
|
+
protected dispatchModelEvent(conversationId: ConversationId, session: ConversationSession, event: Record<string, unknown>): Promise<void>;
|
|
5806
|
+
/** Record one turn on the session's running transcript. */
|
|
5807
|
+
private appendTranscript;
|
|
5808
|
+
/**
|
|
5809
|
+
* The caller started talking. Cancel any response still generating, truncate
|
|
5810
|
+
* the model's memory of the last reply at the point actually heard, then
|
|
5811
|
+
* clear Twilio's buffered audio so playback stops immediately.
|
|
5812
|
+
*
|
|
5813
|
+
* If no assistant audio has been sent since the last barge-in this is a
|
|
5814
|
+
* no-op: there is nothing queued at Twilio to clear, no item id to name in a
|
|
5815
|
+
* truncate, and any response still generating is left to run.
|
|
5816
|
+
*/
|
|
5817
|
+
private handleBargeIn;
|
|
5818
|
+
/**
|
|
5819
|
+
* Run a model-requested tool call and hand the result back.
|
|
5820
|
+
*
|
|
5821
|
+
* Always sends a `function_call_output` once a `call_id` is present — even a
|
|
5822
|
+
* tool that ran successfully can return something `JSON.stringify` throws on
|
|
5823
|
+
* (a circular object, a `BigInt`) or has no JSON form at all, which
|
|
5824
|
+
* `JSON.stringify` reports by returning `undefined` rather than throwing (a
|
|
5825
|
+
* void tool, a bare function, a `Symbol`). Either way the model would
|
|
5826
|
+
* otherwise be left waiting on a `call_id` it never gets a result for.
|
|
5827
|
+
* Without a `call_id` there is nothing to reply to, so the item is dropped
|
|
5828
|
+
* instead.
|
|
5829
|
+
*/
|
|
5830
|
+
private handleFunctionCall;
|
|
5831
|
+
/**
|
|
5832
|
+
* Drop this call's transport state, close the model socket, and end the
|
|
5833
|
+
* session.
|
|
5834
|
+
*
|
|
5835
|
+
* Both legs can report the call ending, and the first one to arrive tears
|
|
5836
|
+
* down the other, so this runs at most once per call: a second invocation
|
|
5837
|
+
* finds nothing tracked and returns.
|
|
5838
|
+
*/
|
|
5839
|
+
private cleanupCall;
|
|
5840
|
+
}
|
|
5841
|
+
|
|
5842
|
+
interface GPTLiveProviderConfigOptions extends MediaStreamsOpenAIProviderConfigOptions {
|
|
5843
|
+
/**
|
|
5844
|
+
* If set, sent verbatim as a `session.commentary.append` once `session.started`
|
|
5845
|
+
* arrives. Word it as an instruction, not just a greeting — e.g. "Greet the
|
|
5846
|
+
* caller immediately using: Hi, how can I help you today?". A bare greeting
|
|
5847
|
+
* will not make the model speak first.
|
|
5848
|
+
*/
|
|
5849
|
+
welcomeInstruction?: string;
|
|
5850
|
+
}
|
|
5851
|
+
/**
|
|
5852
|
+
* Configuration for `GPTLiveProvider`.
|
|
5853
|
+
*
|
|
5854
|
+
* Two GPT-Live-specific notes on inherited members:
|
|
5855
|
+
*
|
|
5856
|
+
* - `tools` holds executable implementations looked up by name. It does **not**
|
|
5857
|
+
* tell the model the tools exist — also add each tool's `toRealtimeFormat()`
|
|
5858
|
+
* schema to `defaultSessionConfig.delegation.responses.tools`.
|
|
5859
|
+
* - `defaultSessionConfig` is the `session.start` payload's `session` body. It
|
|
5860
|
+
* must include `model` (e.g. `'gpt-live-1'`), and `audio.format`
|
|
5861
|
+
* must be `TWILIO_AUDIO_FORMAT_FOR_GPT_LIVE`.
|
|
5862
|
+
*/
|
|
5863
|
+
declare class GPTLiveProviderConfig extends MediaStreamsOpenAIProviderConfig {
|
|
5864
|
+
readonly welcomeInstruction: string | null;
|
|
5865
|
+
constructor(opts?: GPTLiveProviderConfigOptions);
|
|
5866
|
+
createProvider(channel: VoiceChannel, tacConfig: TACConfig): VoiceProvider;
|
|
5867
|
+
}
|
|
5868
|
+
|
|
5869
|
+
/**
|
|
5870
|
+
* Per-call bookkeeping `GPTLiveProvider` needs beyond `ConversationSession`.
|
|
5871
|
+
*
|
|
5872
|
+
* @internal
|
|
5873
|
+
*/
|
|
5874
|
+
declare class CallState extends MediaStreamsOpenAICallState {
|
|
5875
|
+
/**
|
|
5876
|
+
* Settles once `session.closed` arrives, so teardown can wait for graceful
|
|
5877
|
+
* finalization before tearing the socket down.
|
|
5878
|
+
*/
|
|
5879
|
+
readonly closed: Promise<void>;
|
|
5880
|
+
private readonly resolveClosed;
|
|
5881
|
+
constructor();
|
|
5882
|
+
markClosed(): void;
|
|
5883
|
+
}
|
|
5884
|
+
|
|
5885
|
+
/**
|
|
5886
|
+
* The audio format both directions of a call must use.
|
|
5887
|
+
*
|
|
5888
|
+
* Twilio Media Streams always sends and expects 8kHz G.711 u-law — see
|
|
5889
|
+
* https://www.twilio.com/docs/voice/media-streams/websocket-messages. Not
|
|
5890
|
+
* configurable. GPT-Live speaks it natively on both legs, so a single
|
|
5891
|
+
* `session.audio.format` covers input and output and nothing transcodes.
|
|
5892
|
+
*
|
|
5893
|
+
* Spelled with an explicit `rate`, which GPT-Live's schema wants and Realtime's
|
|
5894
|
+
* rejects — that is why this is a separate constant from
|
|
5895
|
+
* `TWILIO_AUDIO_FORMAT_FOR_REALTIME` rather than a shared one.
|
|
5896
|
+
*/
|
|
5897
|
+
declare const TWILIO_AUDIO_FORMAT_FOR_GPT_LIVE: {
|
|
5898
|
+
readonly type: "audio/pcmu";
|
|
5899
|
+
readonly rate: 8000;
|
|
5900
|
+
};
|
|
5901
|
+
/**
|
|
5902
|
+
* `ConversationSession.metadata` key holding OpenAI's id for the GPT-Live
|
|
5903
|
+
* session behind this call, set once `session.started` arrives. Quote it to
|
|
5904
|
+
* OpenAI support when reporting a session.
|
|
5905
|
+
*
|
|
5906
|
+
* Opaque: the prefix differs across GPT-Live's alpha (`rtc_`) and GA (`live_`),
|
|
5907
|
+
* so never parse it, validate it, or branch on it.
|
|
5908
|
+
*/
|
|
5909
|
+
declare const GPT_LIVE_SESSION_ID_METADATA_KEY = "gpt_live_session_id";
|
|
5910
|
+
/**
|
|
5911
|
+
* A {@link VoiceProvider} bridging Twilio Media Streams to OpenAI's GPT-Live
|
|
5912
|
+
* API.
|
|
5913
|
+
*/
|
|
5914
|
+
declare class GPTLiveProvider extends MediaStreamsOpenAIProvider<CallState> {
|
|
5915
|
+
/** @internal */
|
|
5916
|
+
get providerId(): string;
|
|
5917
|
+
/**
|
|
5918
|
+
* No `override`: TypeScript rejects it alongside `declare` (TS1243), and
|
|
5919
|
+
* `declare` is what keeps this a pure type narrowing of the base's field
|
|
5920
|
+
* rather than a second field that shadows it.
|
|
5921
|
+
*/
|
|
5922
|
+
protected readonly config: GPTLiveProviderConfig;
|
|
5923
|
+
private readonly pendingTokenExpiries;
|
|
5924
|
+
/** Calls whose teardown has begun but is still awaiting `session.closed`. */
|
|
5925
|
+
private readonly closingCalls;
|
|
5926
|
+
get channelName(): string;
|
|
5927
|
+
/**
|
|
5928
|
+
* Initiate an outbound voice conversation.
|
|
5929
|
+
*
|
|
5930
|
+
* Places an outbound call with inline TwiML that connects to a Media Stream.
|
|
5931
|
+
* Unlike inbound, there is no local session yet at this point — one is
|
|
5932
|
+
* created when Twilio's WebSocket `start` event arrives.
|
|
5933
|
+
*
|
|
5934
|
+
* TwiML fields are merged per-field — see
|
|
5935
|
+
* {@link TwiMLBuilderMediaStreams.build}. The WebSocket URL is derived from
|
|
5936
|
+
* `TACConfig.voicePublicDomain` + `TACConfig.voiceWebsocketPath` unless
|
|
5937
|
+
* overridden per-call via `options.websocketUrl`.
|
|
5938
|
+
*
|
|
5939
|
+
* Pass `InitiateVoiceConversationOptionsGPTLive` with `sessionConfig` set to
|
|
5940
|
+
* override `GPTLiveProviderConfig.defaultSessionConfig` for this call.
|
|
5941
|
+
*
|
|
5942
|
+
* @param options - Outbound call options.
|
|
5943
|
+
* @throws {TypeError} if `options` does not satisfy
|
|
5944
|
+
* `InitiateVoiceConversationOptionsGPTLiveSchema`.
|
|
5945
|
+
* @throws {Error} if no WebSocket URL can be resolved — neither
|
|
5946
|
+
* `options.websocketUrl` nor any TwiML layer sets one and
|
|
5947
|
+
* `TACConfig.voicePublicDomain` is unset.
|
|
5948
|
+
*/
|
|
5949
|
+
initiateOutboundConversation(options: InitiateVoiceConversationOptions | InitiateVoiceConversationOptionsGPTLive): Promise<InitiateVoiceConversationResult>;
|
|
5950
|
+
/**
|
|
5951
|
+
* Start the clock on a stashed token, so a call that never connects cannot
|
|
5952
|
+
* strand its override in {@link pendingSessionConfigs} forever.
|
|
5953
|
+
*
|
|
5954
|
+
* Unref'd: a two-minute timer must not be what keeps the process alive after
|
|
5955
|
+
* the call it belongs to is long over.
|
|
5956
|
+
*/
|
|
5957
|
+
private armTokenExpiry;
|
|
5958
|
+
/**
|
|
5959
|
+
* Stop the clock on a token, once the call it belongs to has claimed it.
|
|
5960
|
+
*
|
|
5961
|
+
* Without this a two-minute timer outlives every call that connected
|
|
5962
|
+
* normally, waiting to purge an entry that is already gone.
|
|
5963
|
+
*/
|
|
5964
|
+
private cancelTokenExpiry;
|
|
5965
|
+
/**
|
|
5966
|
+
* Drive one Twilio Media Stream connection from `start` to disconnect.
|
|
5967
|
+
*
|
|
5968
|
+
* Twilio's `start` event names the call, which opens the matching GPT-Live
|
|
5969
|
+
* socket; from then on caller audio is relayed to the model and the model's
|
|
5970
|
+
* audio back to Twilio, until either side goes away. Whichever leg closes
|
|
5971
|
+
* first takes the other down with it, so a caller is never left connected to
|
|
5972
|
+
* silence.
|
|
5973
|
+
*
|
|
5974
|
+
* Twilio streams audio without waiting for the GPT-Live socket to finish
|
|
5975
|
+
* connecting, so audio that arrives during that handshake is held and
|
|
5976
|
+
* forwarded, in order, once the model is ready — a caller who speaks the
|
|
5977
|
+
* instant the call connects is heard in full.
|
|
5978
|
+
*
|
|
5979
|
+
* Called by `VoiceChannel.handleWebSocketConnection`; hosts serve the socket
|
|
5980
|
+
* rather than calling this directly.
|
|
5981
|
+
*
|
|
5982
|
+
* @param ws - The accepted Twilio-facing WebSocket.
|
|
5983
|
+
*/
|
|
5984
|
+
handleWebSocket(ws: WebSocket): void;
|
|
5985
|
+
/**
|
|
5986
|
+
* Handle Twilio's `start` event: track the call and open its session.
|
|
5987
|
+
*
|
|
5988
|
+
* @param start - The event's `start` body, parsed against
|
|
5989
|
+
* `StreamStartMessageSchema`.
|
|
5990
|
+
* @param ws - The Twilio-facing socket this call arrived on.
|
|
5991
|
+
* @returns The conversation id — which is the call SID — and the call's
|
|
5992
|
+
* freshly tracked transport state.
|
|
5993
|
+
*/
|
|
5994
|
+
private registerCall;
|
|
5995
|
+
/**
|
|
5996
|
+
* Open this call's GPT-Live socket and send its session config.
|
|
5997
|
+
*
|
|
5998
|
+
* @internal
|
|
5999
|
+
*/
|
|
6000
|
+
connectModel(conversationId: ConversationId): Promise<void>;
|
|
6001
|
+
/**
|
|
6002
|
+
* The validated session config for this call: its own stashed override if it
|
|
6003
|
+
* has one, else the channel-wide default.
|
|
6004
|
+
*
|
|
6005
|
+
* @throws {Error} if neither exists, if the audio format is one Twilio can't
|
|
6006
|
+
* carry, or if it names no model.
|
|
6007
|
+
*/
|
|
6008
|
+
private resolveSessionConfig;
|
|
6009
|
+
/**
|
|
6010
|
+
* Wire up the model socket: dispatch its events, and tear the call down when
|
|
6011
|
+
* it goes away.
|
|
4048
6012
|
*
|
|
4049
|
-
*
|
|
4050
|
-
*
|
|
6013
|
+
* The Python SDK races its Twilio read against its model-event reader so the
|
|
6014
|
+
* Twilio leg dies with the model leg; `ws` is event-driven, so the same
|
|
6015
|
+
* guarantee is a close/error handler instead.
|
|
4051
6016
|
*/
|
|
4052
|
-
|
|
6017
|
+
private attachModelHandlers;
|
|
4053
6018
|
/**
|
|
4054
|
-
*
|
|
4055
|
-
*
|
|
4056
|
-
*
|
|
4057
|
-
* emitted as the `url` attribute), actionUrl, languages, customParameters, extra.
|
|
6019
|
+
* Hang up the Twilio leg because the model leg is gone, then clean up. A
|
|
6020
|
+
* no-op once the call has already been cleaned up, so both the model socket's
|
|
6021
|
+
* `close` and its `error` can call it.
|
|
4058
6022
|
*/
|
|
4059
|
-
private
|
|
6023
|
+
private endCallFromModel;
|
|
4060
6024
|
/**
|
|
4061
|
-
*
|
|
6025
|
+
* Close this call's GPT-Live session gracefully, drop its transport state,
|
|
6026
|
+
* and end the session.
|
|
4062
6027
|
*
|
|
4063
|
-
*
|
|
4064
|
-
*
|
|
4065
|
-
*
|
|
4066
|
-
*
|
|
4067
|
-
* channel-less caller can pass everything in one object.
|
|
6028
|
+
* `session.close` asks the server to finalize the session, and teardown waits
|
|
6029
|
+
* up to {@link CLOSE_TIMEOUT_MS} for the `session.closed` answering it before
|
|
6030
|
+
* the socket goes away — otherwise the socket would be gone before the server
|
|
6031
|
+
* could finish.
|
|
4068
6032
|
*
|
|
4069
|
-
*
|
|
4070
|
-
*
|
|
4071
|
-
*
|
|
4072
|
-
* @returns TwiML XML string ready to return to Twilio.
|
|
4073
|
-
* @throws {Error} if no WebSocket URL is provided via either source.
|
|
6033
|
+
* Both legs can report the call ending, and the first one to arrive tears
|
|
6034
|
+
* down the other, so this runs at most once per call: a second invocation
|
|
6035
|
+
* finds the call either untracked or already closing, and returns.
|
|
4074
6036
|
*/
|
|
4075
|
-
private
|
|
6037
|
+
private cleanupCall;
|
|
4076
6038
|
/**
|
|
4077
|
-
*
|
|
4078
|
-
*
|
|
6039
|
+
* Drop this provider's transport state on channel shutdown, including the
|
|
6040
|
+
* bookkeeping it keeps beyond the base class's.
|
|
4079
6041
|
*
|
|
4080
|
-
*
|
|
4081
|
-
*
|
|
4082
|
-
*
|
|
4083
|
-
* @throws {Error} if config validation fails
|
|
6042
|
+
* The token expiry timers are unref'd and delete themselves, so nothing hangs
|
|
6043
|
+
* without this — but a shut-down provider must not still be holding entries
|
|
6044
|
+
* for calls that can no longer arrive.
|
|
4084
6045
|
*/
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
}): string;
|
|
6046
|
+
shutdown(): void;
|
|
6047
|
+
/** Apply one parsed GPT-Live event to the call. */
|
|
6048
|
+
protected dispatchModelEvent(conversationId: ConversationId, session: ConversationSession, event: Record<string, unknown>): Promise<void>;
|
|
4089
6049
|
/**
|
|
4090
|
-
*
|
|
4091
|
-
*
|
|
6050
|
+
* Run a Responses-delegated tool call and hand the result back.
|
|
6051
|
+
*
|
|
6052
|
+
* Always sends a `function_call_output` once a `call_id` is present — even a
|
|
6053
|
+
* tool that ran successfully can return something `JSON.stringify` throws on
|
|
6054
|
+
* (a circular object, a `BigInt`) or has no JSON form at all, which
|
|
6055
|
+
* `JSON.stringify` reports by returning `undefined` rather than throwing (a
|
|
6056
|
+
* void tool, a bare function, a `Symbol`). Either way the model would
|
|
6057
|
+
* otherwise be left waiting on a `call_id` it never gets a result for.
|
|
6058
|
+
* Without a `call_id` there is nothing to reply to, so the item is dropped
|
|
6059
|
+
* instead.
|
|
4092
6060
|
*/
|
|
4093
|
-
private
|
|
6061
|
+
private handleFunctionCall;
|
|
4094
6062
|
/**
|
|
4095
|
-
*
|
|
6063
|
+
* Surface the GPT-Live session id from a session-snapshot event.
|
|
4096
6064
|
*
|
|
4097
|
-
*
|
|
4098
|
-
*
|
|
6065
|
+
* OpenAI support asks for this id when investigating a session, so it goes
|
|
6066
|
+
* where a caller can reach it — `session.metadata`, which outlives the call
|
|
6067
|
+
* into `onConversationEnded` — and is logged once per call.
|
|
4099
6068
|
*/
|
|
4100
|
-
|
|
6069
|
+
private recordGptLiveSessionId;
|
|
6070
|
+
/** Accumulate one transcript delta into the in-progress turn. */
|
|
6071
|
+
private static appendTranscriptDelta;
|
|
4101
6072
|
}
|
|
4102
6073
|
|
|
4103
6074
|
declare function scrubPii(value: string): string;
|
|
@@ -4292,243 +6263,6 @@ declare class MemoryPromptBuilder {
|
|
|
4292
6263
|
private static assemblePrompt;
|
|
4293
6264
|
}
|
|
4294
6265
|
|
|
4295
|
-
/**
|
|
4296
|
-
* TAC Tool class with helper methods for LLM integration
|
|
4297
|
-
*
|
|
4298
|
-
* Matches Python's TACTool dataclass with conversion methods.
|
|
4299
|
-
*/
|
|
4300
|
-
declare class TACTool<TParams = unknown, TResult = unknown> {
|
|
4301
|
-
readonly name: string;
|
|
4302
|
-
readonly description: string;
|
|
4303
|
-
readonly parameters: JSONSchema;
|
|
4304
|
-
readonly implementation: ToolFunction<TParams, TResult>;
|
|
4305
|
-
constructor(name: string, description: string, parameters: JSONSchema, implementation: ToolFunction<TParams, TResult>);
|
|
4306
|
-
/**
|
|
4307
|
-
* Convert to OpenAI function calling format
|
|
4308
|
-
*/
|
|
4309
|
-
toOpenAIFormat(): OpenAITool;
|
|
4310
|
-
/**
|
|
4311
|
-
* Convert to Anthropic tool calling format
|
|
4312
|
-
*/
|
|
4313
|
-
toAnthropicFormat(): AnthropicTool;
|
|
4314
|
-
/**
|
|
4315
|
-
* Convert to JSON string (OpenAI format by default)
|
|
4316
|
-
*/
|
|
4317
|
-
toJSON(): string;
|
|
4318
|
-
/**
|
|
4319
|
-
* Convert this tool to an OpenAI Agents SDK `FunctionTool` instance.
|
|
4320
|
-
*
|
|
4321
|
-
* Unlike `toOpenAIFormat` and `toAnthropicFormat` (which return plain
|
|
4322
|
-
* objects consumed by HTTP APIs), the OpenAI Agents SDK dispatches on tool
|
|
4323
|
-
* *type*, so this returns a live `tool(...)` object with an invoke callback
|
|
4324
|
-
* that calls this tool and JSON-encodes the result.
|
|
4325
|
-
*
|
|
4326
|
-
* Requires the `@openai/agents` package:
|
|
4327
|
-
*
|
|
4328
|
-
* npm install @openai/agents
|
|
4329
|
-
*
|
|
4330
|
-
* @returns A FunctionTool ready to pass to `new Agent({ tools: [...] })`.
|
|
4331
|
-
*/
|
|
4332
|
-
toOpenAIAgentsSDKTool(): Promise<any>;
|
|
4333
|
-
}
|
|
4334
|
-
/**
|
|
4335
|
-
* Create a tool directly with all parameters
|
|
4336
|
-
*
|
|
4337
|
-
* Simplified approach matching Python's create_tool function.
|
|
4338
|
-
* No builder pattern - just a simple function call.
|
|
4339
|
-
*/
|
|
4340
|
-
declare function defineTool<TParams = unknown, TResult = unknown>(name: string, description: string, parameters: JSONSchema, implementation: ToolFunction<TParams, TResult>): TACTool<TParams, TResult>;
|
|
4341
|
-
|
|
4342
|
-
/**
|
|
4343
|
-
* Parameters for memory retrieval tool
|
|
4344
|
-
*/
|
|
4345
|
-
interface MemoryRetrievalParams {
|
|
4346
|
-
query?: string;
|
|
4347
|
-
beginDate?: string;
|
|
4348
|
-
endDate?: string;
|
|
4349
|
-
observationsLimit?: number;
|
|
4350
|
-
summariesLimit?: number;
|
|
4351
|
-
communicationsLimit?: number;
|
|
4352
|
-
relevanceThreshold?: number;
|
|
4353
|
-
}
|
|
4354
|
-
/**
|
|
4355
|
-
* Create memory retrieval tool.
|
|
4356
|
-
*
|
|
4357
|
-
* @param memoryClient - Memory client instance (must be initialized with storeId)
|
|
4358
|
-
* @param profileId - Optional profile ID for memory retrieval
|
|
4359
|
-
* @param conversationId - Optional conversation ID for memory retrieval
|
|
4360
|
-
* @param options - Optional overrides for tool metadata.
|
|
4361
|
-
* @param options.name - Tool name exposed to the LLM. Defaults to `retrieve_profile_memory`.
|
|
4362
|
-
* @param options.description - Tool description exposed to the LLM. Defaults to a
|
|
4363
|
-
* generic "retrieve memories" prompt.
|
|
4364
|
-
*/
|
|
4365
|
-
declare function createMemoryRetrievalTool(memoryClient: MemoryClient, profileId?: string, conversationId?: string, options?: {
|
|
4366
|
-
name?: string;
|
|
4367
|
-
description?: string;
|
|
4368
|
-
}): TACTool<MemoryRetrievalParams, MemoryRetrievalResponse>;
|
|
4369
|
-
/**
|
|
4370
|
-
* Create factory function for memory tools
|
|
4371
|
-
*
|
|
4372
|
-
* @param memoryClient - Memory client instance (must be initialized with storeId)
|
|
4373
|
-
*/
|
|
4374
|
-
declare function createMemoryTools(memoryClient: MemoryClient): {
|
|
4375
|
-
forProfile: (profileId: string, conversationId?: string) => TACTool<MemoryRetrievalParams, MemoryRetrievalResponse>;
|
|
4376
|
-
forSession: (profileId?: string, conversationId?: string) => TACTool<MemoryRetrievalParams, MemoryRetrievalResponse>;
|
|
4377
|
-
};
|
|
4378
|
-
|
|
4379
|
-
/**
|
|
4380
|
-
* Parameters for send message tool
|
|
4381
|
-
*/
|
|
4382
|
-
interface SendMessageParams {
|
|
4383
|
-
message: string;
|
|
4384
|
-
metadata?: Record<string, unknown>;
|
|
4385
|
-
}
|
|
4386
|
-
/**
|
|
4387
|
-
* Result from send message tool
|
|
4388
|
-
*/
|
|
4389
|
-
interface SendMessageResult {
|
|
4390
|
-
success: boolean;
|
|
4391
|
-
message_id?: string;
|
|
4392
|
-
error?: string;
|
|
4393
|
-
}
|
|
4394
|
-
/**
|
|
4395
|
-
* Create send message tool
|
|
4396
|
-
*/
|
|
4397
|
-
declare function createSendMessageTool(channel: BaseChannel, conversationId: ConversationId): TACTool<SendMessageParams, SendMessageResult>;
|
|
4398
|
-
/**
|
|
4399
|
-
* Create factory function for messaging tools
|
|
4400
|
-
*/
|
|
4401
|
-
declare function createMessagingTools(): {
|
|
4402
|
-
forConversation: (channel: BaseChannel, conversationId: ConversationId) => TACTool<SendMessageParams, SendMessageResult>;
|
|
4403
|
-
};
|
|
4404
|
-
|
|
4405
|
-
/**
|
|
4406
|
-
* Handoff tool for the Twilio Agent Connect.
|
|
4407
|
-
*
|
|
4408
|
-
* Generic Studio-backed handoff that routes a conversation to a human agent.
|
|
4409
|
-
* Produces a structured HandoffPayload and delivers it as a Twilio Studio
|
|
4410
|
-
* Execution (voice via `<Connect action>`, digital channels via direct POST).
|
|
4411
|
-
*/
|
|
4412
|
-
|
|
4413
|
-
/**
|
|
4414
|
-
* Build a HandoffPayload from session context and attributes.
|
|
4415
|
-
*
|
|
4416
|
-
* Useful for custom handoff tools that want TAC's payload shape without
|
|
4417
|
-
* the Studio-specific delivery in `postStudioHandoff`.
|
|
4418
|
-
*/
|
|
4419
|
-
declare function buildHandoffPayload(session: ConversationSession, memoryStoreId: string, attributes: Record<string, unknown>): HandoffPayload;
|
|
4420
|
-
/**
|
|
4421
|
-
* POST a handoff payload to a Twilio Studio Flow Executions endpoint.
|
|
4422
|
-
*
|
|
4423
|
-
* Emits the Twilio Studio Executions API wire format: form-encoded
|
|
4424
|
-
* `To` / `From` / `Parameters` fields with HTTP Basic auth.
|
|
4425
|
-
* `Parameters` is a JSON string keyed under `HandoffData` so Studio
|
|
4426
|
-
* can reference it via `{{flow.data.HandoffData.*}}`.
|
|
4427
|
-
*/
|
|
4428
|
-
declare function postStudioHandoff(payload: HandoffPayload, session: ConversationSession, options: {
|
|
4429
|
-
handoffUrl: string;
|
|
4430
|
-
fromAddress: string;
|
|
4431
|
-
apiKey: string;
|
|
4432
|
-
apiSecret: string;
|
|
4433
|
-
}): Promise<void>;
|
|
4434
|
-
/**
|
|
4435
|
-
* Result returned by the handoff tool.
|
|
4436
|
-
*/
|
|
4437
|
-
interface HandoffResult {
|
|
4438
|
-
status: 'handoff_initiated' | 'handoff_failed';
|
|
4439
|
-
channel: string;
|
|
4440
|
-
error?: string;
|
|
4441
|
-
}
|
|
4442
|
-
interface HandoffParams {
|
|
4443
|
-
reason: string;
|
|
4444
|
-
}
|
|
4445
|
-
/**
|
|
4446
|
-
* Create a handoff tool that delivers in the Twilio Studio Executions API shape.
|
|
4447
|
-
*
|
|
4448
|
-
* The returned tool exposes only `handoff({ reason })` to the LLM. All other
|
|
4449
|
-
* dependencies (TAC instance, session, static attributes) are captured in the
|
|
4450
|
-
* closure.
|
|
4451
|
-
*
|
|
4452
|
-
* On digital channels, the tool POSTs to the Studio Flow Executions endpoint
|
|
4453
|
-
* derived from `tac.getConfig().studioHandoffFlowSid`. For voice channels,
|
|
4454
|
-
* the payload is stored on the session and the voice channel automatically
|
|
4455
|
-
* sends the WS `end` message with `handoffData` after the LLM's final
|
|
4456
|
-
* response is delivered.
|
|
4457
|
-
*
|
|
4458
|
-
* The tool also sets the conversation to INACTIVE and clears status callbacks
|
|
4459
|
-
* to prevent further webhook events from being routed to TAC.
|
|
4460
|
-
*
|
|
4461
|
-
* **Not available in voice-only mode.** This tool requires Conversation
|
|
4462
|
-
* Orchestrator for conversation state management and Conversation Memory for
|
|
4463
|
-
* the handoff payload. In voice-only mode, implement your own handoff by
|
|
4464
|
-
* setting `session.pendingHandoffData` directly — the voice channel will
|
|
4465
|
-
* send the WS `end` message with your payload, and your `<Connect action>`
|
|
4466
|
-
* URL handler can route the call accordingly.
|
|
4467
|
-
*
|
|
4468
|
-
* @throws Error if `tac.getConfig().studioHandoffFlowSid` is unset, if
|
|
4469
|
-
* Conversation Orchestrator is not configured (voice-only mode), or if
|
|
4470
|
-
* the memory store ID was not resolved at startup.
|
|
4471
|
-
*/
|
|
4472
|
-
declare function createStudioHandoffTool(tac: TAC, session: ConversationSession, options?: {
|
|
4473
|
-
attributes?: Record<string, unknown>;
|
|
4474
|
-
name?: string;
|
|
4475
|
-
description?: string;
|
|
4476
|
-
}): TACTool<HandoffParams, HandoffResult>;
|
|
4477
|
-
|
|
4478
|
-
/**
|
|
4479
|
-
* Parameters for knowledge search tool (visible to LLM)
|
|
4480
|
-
*/
|
|
4481
|
-
interface KnowledgeSearchParams {
|
|
4482
|
-
query: string;
|
|
4483
|
-
}
|
|
4484
|
-
/**
|
|
4485
|
-
* Configuration for knowledge search tool
|
|
4486
|
-
*/
|
|
4487
|
-
interface KnowledgeToolConfig {
|
|
4488
|
-
name?: string;
|
|
4489
|
-
description?: string;
|
|
4490
|
-
topK?: number;
|
|
4491
|
-
}
|
|
4492
|
-
/**
|
|
4493
|
-
* Create knowledge search tool with explicit name and description
|
|
4494
|
-
*
|
|
4495
|
-
* @param knowledgeClient - The Knowledge client instance
|
|
4496
|
-
* @param knowledgeBaseId - The knowledge base ID to search
|
|
4497
|
-
* @param config - Configuration with required name and description
|
|
4498
|
-
* @returns TACTool configured for knowledge search
|
|
4499
|
-
*/
|
|
4500
|
-
declare function createKnowledgeSearchTool(knowledgeClient: KnowledgeClient, knowledgeBaseId: string, config: {
|
|
4501
|
-
name: string;
|
|
4502
|
-
description: string;
|
|
4503
|
-
topK?: number;
|
|
4504
|
-
}): TACTool<KnowledgeSearchParams, KnowledgeChunkResult[]>;
|
|
4505
|
-
/**
|
|
4506
|
-
* Create knowledge search tool with auto-fetched metadata from knowledge base
|
|
4507
|
-
*
|
|
4508
|
-
* This async version fetches the knowledge base metadata to auto-generate
|
|
4509
|
-
* the tool name and description if not provided.
|
|
4510
|
-
*
|
|
4511
|
-
* @param knowledgeClient - The Knowledge client instance
|
|
4512
|
-
* @param knowledgeBaseId - The knowledge base ID to search
|
|
4513
|
-
* @param config - Optional configuration (name/description auto-generated if not provided)
|
|
4514
|
-
* @returns Promise containing TACTool configured for knowledge search
|
|
4515
|
-
*/
|
|
4516
|
-
declare function createKnowledgeSearchToolAsync(knowledgeClient: KnowledgeClient, knowledgeBaseId: string, config?: KnowledgeToolConfig): Promise<TACTool<KnowledgeSearchParams, KnowledgeChunkResult[]>>;
|
|
4517
|
-
/**
|
|
4518
|
-
* Create factory for knowledge tools
|
|
4519
|
-
*
|
|
4520
|
-
* @param knowledgeClient - The Knowledge client instance
|
|
4521
|
-
* @returns Factory object with methods to create knowledge tools
|
|
4522
|
-
*/
|
|
4523
|
-
declare function createKnowledgeTools(knowledgeClient: KnowledgeClient): {
|
|
4524
|
-
forKnowledgeBase: (knowledgeBaseId: string, config: {
|
|
4525
|
-
name: string;
|
|
4526
|
-
description: string;
|
|
4527
|
-
topK?: number;
|
|
4528
|
-
}) => TACTool<KnowledgeSearchParams, KnowledgeChunkResult[]>;
|
|
4529
|
-
forKnowledgeBaseAsync: (knowledgeBaseId: string, config?: KnowledgeToolConfig) => Promise<TACTool<KnowledgeSearchParams, KnowledgeChunkResult[]>>;
|
|
4530
|
-
};
|
|
4531
|
-
|
|
4532
6266
|
/**
|
|
4533
6267
|
* Server configuration options
|
|
4534
6268
|
*/
|
|
@@ -4650,4 +6384,4 @@ declare class TACServer {
|
|
|
4650
6384
|
stop(): Promise<void>;
|
|
4651
6385
|
}
|
|
4652
6386
|
|
|
4653
|
-
export { type ActionChannelSettings, ActionChannelSettingsSchema, type ActionParticipantRef, ActionParticipantRefSchema, type ActionResponse, ActionResponseSchema, type ActionTextContent, ActionTextContentSchema, type AdapterOptions, type AmdEvent, AmdEventSchema, type AmdHandler, type AnthropicTool, AnthropicToolSchema, type AuthorInfo, AuthorInfoSchema, BaseChannel, type BaseChannelEvents, type BaseChannelOptions, BaseClient, type BuiltInToolName, BuiltInTools, CALL_EVENT_KINDS, type CallEventKind, CallEventKindSchema, type CallOptions, CallOptionsSchema, type CallStatusEvent, CallStatusEventSchema, type CallStatusHandler, type CaptureRule, CaptureRuleSchema, type ChannelSettings, ChannelSettingsSchema, type ChannelType, ChannelTypeSchema, ChatChannel, type ChatChannelConfig, type CintelParticipant, CintelParticipantSchema, type Communication, type CommunicationContent, CommunicationContentSchema, type CommunicationParticipant, CommunicationParticipantSchema, CommunicationSchema, type ConversationAddress, ConversationAddressSchema, ConversationClient, type ConversationConfiguration, ConversationConfigurationSchema, type ConversationEndedCallback, type ConversationGroupingType, ConversationGroupingTypeSchema, type ConversationId, type ConversationIntelligenceConfig, ConversationIntelligenceConfigSchema, type ConversationParticipant, ConversationParticipantSchema, type ConversationRelayAttributes, ConversationRelayAttributesSchema, type ConversationRelayCallbackPayload, ConversationRelayCallbackPayloadSchema, type ConversationRelayConfig, ConversationRelayConfigSchema, type ConversationResponse, ConversationResponseSchema, type ConversationSession, ConversationSessionSchema, type ConversationSummaryItem, ConversationSummaryItemSchema, type ConversationWebhookPayload, type CreateConversationSummariesResponse, CreateConversationSummariesResponseSchema, type CreateObservationResponse, CreateObservationResponseSchema, type CreateObservationsRequest, CreateObservationsRequestSchema, type CustomParameters, CustomParametersSchema, EMPTY_MEMORY_RESPONSE, EnvironmentVariables, type ExecutionDetails, ExecutionDetailsSchema, type HandoffPayload, HandoffPayloadSchema, type HandoffResult, type InboundCallTwimlHandler, type InitiateChatConversationOptions, type InitiateConversationResult, type InitiateMessagingConversationOptions, InitiateMessagingConversationOptionsSchema, type InitiateVoiceConversationOptions, InitiateVoiceConversationOptionsSchema, type InitiateVoiceConversationResult, type IntelligenceConfiguration, IntelligenceConfigurationSchema, type InterruptCallback, type InterruptMessage, InterruptMessageSchema, type InterruptMode, InterruptModeSchema, type JSONSchema, JSONSchemaSchema, type KnowledgeBase, KnowledgeBaseSchema, type KnowledgeBaseStatus, KnowledgeBaseStatusSchema, type KnowledgeChunkResult, KnowledgeChunkResultSchema, KnowledgeClient, type KnowledgeSearchResponse, KnowledgeSearchResponseSchema, type LanguageAttributes, LanguageAttributesSchema, type LanguageConfig, LanguageConfigSchema, type ListCommunicationsResponse, ListCommunicationsResponseSchema, type ListConversationsResponse, ListConversationsResponseSchema, type ListParticipantsResponse, ListParticipantsResponseSchema, type Logger, type MemoryChannelType, MemoryChannelTypeSchema, MemoryClient, type MemoryCommunication, type MemoryCommunicationContent, MemoryCommunicationContentSchema, MemoryCommunicationSchema, type MemoryDeliveryStatus, MemoryDeliveryStatusSchema, type MemoryMode, MemoryModeSchema, type MemoryParticipant, MemoryParticipantSchema, type MemoryParticipantType, MemoryParticipantTypeSchema, MemoryPromptBuilder, type MemoryRetrievalRequest, MemoryRetrievalRequestSchema, type MemoryRetrievalResponse, MemoryRetrievalResponseSchema, type MessageDirection, MessageDirectionSchema, type MessageReadyCallback, MessagingChannel, type MessagingChannelConfig, type MessagingChannelEvents, type ObservationCreateRequest, ObservationCreateRequestSchema, type ObservationInfo, ObservationInfoSchema, type OpenAITool, OpenAIToolSchema, type Operator, type OperatorProcessingResult, OperatorProcessingResultSchema, type OperatorResult, type OperatorResultEvent, OperatorResultEventSchema, OperatorResultProcessor, OperatorResultSchema, OperatorSchema, type ParticipantAddress, ParticipantAddressSchema, type ParticipantAddressType, ParticipantAddressTypeSchema, type ParticipantId, type PendingHandoffData, PendingHandoffDataSchema, type Profile, type ProfileId, type ProfileLookupResponse, ProfileLookupResponseSchema, type ProfileResponse, ProfileResponseSchema, type PromptMessage, PromptMessageSchema, RCSChannel, type RecordingEvent, RecordingEventSchema, type RecordingHandler, SMSChannel, type SendMessageActionPayload, SendMessageActionPayloadSchema, type SendMessageActionRequest, SendMessageActionRequestSchema, type SessionInfo, SessionInfoSchema, type SessionMessage, SessionMessageSchema, type SetupMessage, SetupMessageSchema, type StatusCallback, StatusCallbackSchema, type StatusTimeouts, StatusTimeoutsSchema, type StreamTask, type SummaryInfo, SummaryInfoSchema, TAC, type TACChannelType, TACChannelTypeSchema, type TACCommunication, type TACCommunicationAuthor, TACCommunicationAuthorSchema, type TACCommunicationContent, TACCommunicationContentSchema, TACCommunicationSchema, TACConfig, type TACConfigData, TACConfigSchema, type TACDeliveryStatus, TACDeliveryStatusSchema, TACMemoryResponse, type TACOptions, type TACParticipantType, TACParticipantTypeSchema, TACServer, type TACServerConfig, TACTool, type TextTokenMessage, TextTokenMessageSchema, type ToolContext, type ToolExecutionResult, ToolExecutionResultSchema, type ToolFunction, type Transcription, TranscriptionSchema, type TranscriptionWord, TranscriptionWordSchema, type TwiMLOptions, TwiMLOptionsSchema, type TwiMLRequest, TwiMLRequestSchema, type TwilioMemoryConfig, TwilioMemoryConfigSchema, type TypedCallOptions, VoiceChannel, type VoiceChannelConfig, type VoiceChannelEvents, type WebSocketMessage, WebSocketMessageSchema, WhatsAppChannel, type _CallsCreateDriftGuards, type _SDKDriftGuards, amdEventFromForm, buildHandoffPayload, callOptionsToCreateParams, callStatusEventFromForm, createKnowledgeSearchTool, createKnowledgeSearchToolAsync, createKnowledgeTools, createLogger, createMemoryRetrievalTool, createMemoryTools, createMessagingTools, createSendMessageTool, createStudioHandoffTool, defineTool, isConversationId, isParticipantId, isProfileId, maskAddress, maskEmail, maskPhone, postStudioHandoff, recordingEventFromForm, redactTwimlParameters, scrubObject, scrubPii, studioExecutionsUrl, studioVoiceHandoffUrl, twiMLRequestFromForm };
|
|
6387
|
+
export { type ActionChannelSettings, ActionChannelSettingsSchema, type ActionParticipantRef, ActionParticipantRefSchema, type ActionResponse, ActionResponseSchema, type ActionTextContent, ActionTextContentSchema, type AdapterOptions, type AmdEvent, AmdEventSchema, type AmdHandler, type AnthropicTool, AnthropicToolSchema, type AuthorInfo, AuthorInfoSchema, BaseChannel, type BaseChannelEvents, type BaseChannelOptions, BaseClient, type BuildStreamTwiMLInputs, type BuiltInToolName, BuiltInTools, CALL_EVENT_KINDS, type CallEventKind, CallEventKindSchema, type CallOptions, CallOptionsSchema, type CallStatusEvent, CallStatusEventSchema, type CallStatusHandler, type CaptureRule, CaptureRuleSchema, type ChannelSettings, ChannelSettingsSchema, type ChannelType, ChannelTypeSchema, ChatChannel, type ChatChannelConfig, type CintelParticipant, CintelParticipantSchema, type Communication, type CommunicationContent, CommunicationContentSchema, type CommunicationParticipant, CommunicationParticipantSchema, CommunicationSchema, type ConversationAddress, ConversationAddressSchema, ConversationClient, type ConversationConfiguration, ConversationConfigurationSchema, type ConversationEndedCallback, type ConversationGroupingType, ConversationGroupingTypeSchema, type ConversationId, type ConversationIntelligenceConfig, ConversationIntelligenceConfigSchema, type ConversationParticipant, ConversationParticipantSchema, type ConversationRelayAttributes, ConversationRelayAttributesSchema, type ConversationRelayCallbackPayload, ConversationRelayCallbackPayloadSchema, type ConversationRelayConfig, ConversationRelayConfigSchema, ConversationRelayProvider, ConversationRelayProviderConfig, type ConversationRelayProviderConfigOptions, type ConversationResponse, ConversationResponseSchema, type ConversationSession, ConversationSessionSchema, type ConversationSummaryItem, ConversationSummaryItemSchema, type ConversationWebhookPayload, type CreateConversationSummariesResponse, CreateConversationSummariesResponseSchema, type CreateObservationResponse, CreateObservationResponseSchema, type CreateObservationsRequest, CreateObservationsRequestSchema, type CustomParameters, CustomParametersSchema, type DtmfEvent, type DtmfHandler, type DtmfMessage, DtmfMessageSchema, EMPTY_MEMORY_RESPONSE, EnvironmentVariables, type ExecutionDetails, ExecutionDetailsSchema, GPTLiveProvider, GPTLiveProviderConfig, type GPTLiveProviderConfigOptions, GPT_LIVE_SESSION_ID_METADATA_KEY, type HandoffPayload, HandoffPayloadSchema, type HandoffResult, type InboundCallTwimlHandler, type InitiateChatConversationOptions, type InitiateConversationResult, type InitiateMessagingConversationOptions, InitiateMessagingConversationOptionsSchema, type InitiateVoiceConversationOptions, type InitiateVoiceConversationOptionsGPTLive, InitiateVoiceConversationOptionsGPTLiveSchema, type InitiateVoiceConversationOptionsOpenAIRealtime, InitiateVoiceConversationOptionsOpenAIRealtimeSchema, InitiateVoiceConversationOptionsSchema, type InitiateVoiceConversationResult, type IntelligenceConfiguration, IntelligenceConfigurationSchema, type InterruptCallback, type InterruptMessage, InterruptMessageSchema, type InterruptMode, InterruptModeSchema, type JSONSchema, JSONSchemaSchema, type KnowledgeBase, KnowledgeBaseSchema, type KnowledgeBaseStatus, KnowledgeBaseStatusSchema, type KnowledgeChunkResult, KnowledgeChunkResultSchema, KnowledgeClient, type KnowledgeSearchResponse, KnowledgeSearchResponseSchema, type LanguageAttributes, LanguageAttributesSchema, type LanguageConfig, LanguageConfigSchema, type ListCommunicationsResponse, ListCommunicationsResponseSchema, type ListConversationsResponse, ListConversationsResponseSchema, type ListParticipantsResponse, ListParticipantsResponseSchema, type Logger, MediaStreamsOpenAICallState, MediaStreamsOpenAIProvider, MediaStreamsOpenAIProviderConfig, type MediaStreamsOpenAIProviderConfigOptions, MediaStreamsProviderConfig, type MediaStreamsProviderConfigOptions, type MediaStreamsTwiMLBuilderConfig, type MemoryChannelType, MemoryChannelTypeSchema, MemoryClient, type MemoryCommunication, type MemoryCommunicationContent, MemoryCommunicationContentSchema, MemoryCommunicationSchema, type MemoryDeliveryStatus, MemoryDeliveryStatusSchema, type MemoryMode, MemoryModeSchema, type MemoryParticipant, MemoryParticipantSchema, type MemoryParticipantType, MemoryParticipantTypeSchema, MemoryPromptBuilder, type MemoryRetrievalRequest, MemoryRetrievalRequestSchema, type MemoryRetrievalResponse, MemoryRetrievalResponseSchema, type MessageDirection, MessageDirectionSchema, type MessageReadyCallback, MessagingChannel, type MessagingChannelConfig, type MessagingChannelEvents, OPENAI_USER_AGENT, type ObservationCreateRequest, ObservationCreateRequestSchema, type ObservationInfo, ObservationInfoSchema, OpenAIRealtimeProvider, OpenAIRealtimeProviderConfig, type OpenAIRealtimeProviderConfigOptions, type OpenAIRealtimeTool, OpenAIRealtimeToolSchema, type OpenAITool, OpenAIToolSchema, type Operator, type OperatorProcessingResult, OperatorProcessingResultSchema, type OperatorResult, type OperatorResultEvent, OperatorResultEventSchema, OperatorResultProcessor, OperatorResultSchema, OperatorSchema, type ParticipantAddress, ParticipantAddressSchema, type ParticipantAddressType, ParticipantAddressTypeSchema, type ParticipantId, type PendingHandoffData, PendingHandoffDataSchema, type Profile, type ProfileId, type ProfileLookupResponse, ProfileLookupResponseSchema, type ProfileResponse, ProfileResponseSchema, type PromptMessage, PromptMessageSchema, RCSChannel, type RecordingEvent, RecordingEventSchema, type RecordingHandler, SMSChannel, type SendMessageActionPayload, SendMessageActionPayloadSchema, type SendMessageActionRequest, SendMessageActionRequestSchema, type SessionInfo, SessionInfoSchema, type SessionMessage, SessionMessageSchema, type SetupMessage, SetupMessageSchema, type StatusCallback, StatusCallbackSchema, type StatusTimeouts, StatusTimeoutsSchema, type StreamStartMessage, StreamStartMessageSchema, type StreamTask, type SummaryInfo, SummaryInfoSchema, TAC, type TACChannelType, TACChannelTypeSchema, type TACCommunication, type TACCommunicationAuthor, TACCommunicationAuthorSchema, type TACCommunicationContent, TACCommunicationContentSchema, TACCommunicationSchema, TACConfig, type TACConfigData, TACConfigSchema, type TACDeliveryStatus, TACDeliveryStatusSchema, TACMemoryResponse, type TACOptions, type TACParticipantType, TACParticipantTypeSchema, TACServer, type TACServerConfig, TACTool, TWILIO_AUDIO_FORMAT_FOR_GPT_LIVE, TWILIO_AUDIO_FORMAT_FOR_REALTIME, type TextTokenMessage, TextTokenMessageSchema, type ToolContext, type ToolExecutionResult, ToolExecutionResultSchema, type ToolFunction, type Transcription, TranscriptionSchema, type TranscriptionWord, TranscriptionWordSchema, TwiMLBuilderMediaStreams, type TwiMLOptions, TwiMLOptionsSchema, type TwiMLRequest, TwiMLRequestSchema, type TwilioMemoryConfig, TwilioMemoryConfigSchema, type TwilioProviderCallbackResponse, type TypedCallOptions, VoiceChannel, type VoiceChannelConfig, type VoiceChannelEvents, VoiceProvider, VoiceProviderConfig, type VoiceTwiMLOptions, type VoiceTwiMLOptionsConversationRelay, VoiceTwiMLOptionsConversationRelaySchema, type VoiceTwiMLOptionsMediaStreams, VoiceTwiMLOptionsMediaStreamsSchema, VoiceTwiMLOptionsSchema, type WebSocketMessage, WebSocketMessageSchema, WhatsAppChannel, type _CallsCreateDriftGuards, type _SDKDriftGuards, amdEventFromForm, buildHandoffPayload, callOptionsToCreateParams, callStatusEventFromForm, createKnowledgeSearchTool, createKnowledgeSearchToolAsync, createKnowledgeTools, createLogger, createMemoryRetrievalTool, createMemoryTools, createMessagingTools, createSendMessageTool, createStudioHandoffTool, defineTool, generateStreamTwiml, isConversationId, isParticipantId, isProfileId, maskAddress, maskEmail, maskPhone, postStudioHandoff, recordingEventFromForm, redactTwimlParameters, scrubObject, scrubPii, shutdownAnalytics, studioExecutionsUrl, studioVoiceHandoffUrl, trackEvent, twiMLRequestFromForm };
|