@exotel-npm-dev/exotel-ai-assist 1.0.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.
@@ -0,0 +1,35 @@
1
+ import { WorkerInboundMessage } from "../types";
2
+ type TransportMessageHandler = (msg: WorkerInboundMessage) => void;
3
+ export interface ITransport {
4
+ connect(url: string, authToken: string): void;
5
+ disconnect(): void;
6
+ send(payload: string): void;
7
+ onMessage(handler: TransportMessageHandler): void;
8
+ destroy(): void;
9
+ }
10
+ export declare class BroadcastChannelTransport implements ITransport {
11
+ private channel;
12
+ private socket;
13
+ private isLeader;
14
+ private socketConnected;
15
+ private handler;
16
+ private pendingUrl;
17
+ private pendingAuthToken;
18
+ private lockReleaser;
19
+ /**
20
+ * @param sessionHash - A hash of all connection-relevant params (see
21
+ * Utils.hashParams). Tabs with identical params share one WebSocket;
22
+ * any differing param produces a different hash and therefore a fully
23
+ * independent connection.
24
+ */
25
+ constructor(sessionHash: string);
26
+ private _electLeader;
27
+ private _openSocket;
28
+ connect(url: string, authToken: string): void;
29
+ disconnect(): void;
30
+ send(payload: string): void;
31
+ onMessage(handler: TransportMessageHandler): void;
32
+ destroy(): void;
33
+ }
34
+ export declare function createTransport(sessionHash: string): ITransport;
35
+ export {};
@@ -0,0 +1,89 @@
1
+ export interface ExotelAIAssistParams {
2
+ authToken: string;
3
+ call_sid: string;
4
+ /** Exotel account identifier. */
5
+ accountId: string;
6
+ /** WebSocket base URL. Defaults to the Exotel AI Assist backend if omitted. */
7
+ wssBaseUrl?: string;
8
+ reconnectInterval?: number;
9
+ maxReconnectAttempts?: number;
10
+ [key: string]: unknown;
11
+ }
12
+ /** A single AI-generated suggestion for the agent. */
13
+ export interface Suggestion {
14
+ id: string;
15
+ text: string;
16
+ timestamp: number;
17
+ }
18
+ /** A single spoken line as received in the live transcript. */
19
+ export interface TranscriptLine {
20
+ /** Unique stable ID (derived from the backend sequence number). */
21
+ id: string;
22
+ text: string;
23
+ /** Unix timestamp (ms) of the start of this utterance. */
24
+ startTime: number;
25
+ /** Unix timestamp (ms) of the end of this utterance. */
26
+ endTime: number;
27
+ isFinal: boolean;
28
+ }
29
+ /** The latest sentiment label for the call. */
30
+ export interface Sentiment {
31
+ label: "positive" | "neutral" | "negative";
32
+ timestamp: number;
33
+ }
34
+ export type ConnectionStatus = "idle" | "connecting" | "connected" | "disconnected" | "error";
35
+ /** Feature-flag config received from the AI Assist backend. */
36
+ export interface BotConfig {
37
+ sentiment: boolean;
38
+ transcript: boolean;
39
+ suggestions: boolean;
40
+ status: "LIVE" | "DRAFT" | "DEACTIVATED";
41
+ }
42
+ interface TranscriptSegment {
43
+ is_final: boolean;
44
+ end_timestamp: string;
45
+ start_timestamp: string;
46
+ text: string;
47
+ }
48
+ interface TranscriptMessage {
49
+ sequence: number;
50
+ transcript_segments: TranscriptSegment[];
51
+ }
52
+ export interface WssEvent {
53
+ event_type: "suggestion" | "sentiment";
54
+ transcript: TranscriptMessage[];
55
+ text: string;
56
+ }
57
+ export interface InitialHandshakeResponse {
58
+ type: string;
59
+ config: BotConfig;
60
+ events: WssEvent[] | WssEvent;
61
+ }
62
+ export interface WssResponse {
63
+ config: BotConfig;
64
+ events: WssEvent;
65
+ }
66
+ export interface ControllerEvents {
67
+ suggestion: (data: Suggestion) => void;
68
+ transcript: (lines: TranscriptLine[]) => void;
69
+ sentiment: (data: Sentiment) => void;
70
+ /** Internal: bot feature-flag config. Consumed by the UI component only. */
71
+ botConfig: (config: BotConfig) => void;
72
+ onCallStart: () => void;
73
+ onCallEnd: () => void;
74
+ statusChange: (status: ConnectionStatus) => void;
75
+ error: (err: Error) => void;
76
+ raw: (data: unknown) => void;
77
+ }
78
+ export type WorkerInboundMessage = {
79
+ type: "MESSAGE";
80
+ payload: string;
81
+ } | {
82
+ type: "CONNECTED";
83
+ } | {
84
+ type: "DISCONNECTED";
85
+ } | {
86
+ type: "ERROR";
87
+ message: string;
88
+ };
89
+ export {};
@@ -0,0 +1,39 @@
1
+ import { ExotelAIAssistParams } from "../types";
2
+ export declare class Utils {
3
+ static MAX_EXTRA_QUERY_PARAMS: number;
4
+ /**
5
+ * Returns a deterministic SHA-1 hex digest for any plain object.
6
+ *
7
+ * Key ordering is irrelevant — `{a:1, b:2}` and `{b:2, a:1}` produce the
8
+ * same hash. Powered by `object-hash`, which handles nested objects,
9
+ * arrays, and all primitive types correctly.
10
+ */
11
+ static hash(obj: Record<string, unknown>): string;
12
+ /**
13
+ * Formats a timestamp in milliseconds to a human-readable time string.
14
+ * @param ms - The timestamp in milliseconds.
15
+ * @returns The formatted time string.
16
+ */
17
+ static formatTimestamp(ms: number): string;
18
+ /**
19
+ * Returns the base WebSocket URL for the given account ID.
20
+ * @param accountId - The account ID to get the base WebSocket URL for.
21
+ * @returns The base WebSocket URL.
22
+ */
23
+ static getWssBaseUrl(accountId: string): string;
24
+ /**
25
+ * Builds a WebSocket URL from the given parameters.
26
+ * @param params - The parameters to build the WebSocket URL from.
27
+ * @returns The WebSocket URL.
28
+ */
29
+ static buildWsUrl(params: ExotelAIAssistParams): string;
30
+ static constructQueryParams(params: ExotelAIAssistParams): string;
31
+ /**
32
+ * Returns a unique ID string.
33
+ *
34
+ * If the browser supports `crypto.randomUUID`, it uses that. Otherwise, it
35
+ * falls back to a simple timestamp-based ID.
36
+ * @returns A unique ID string.
37
+ */
38
+ static getUniqueId(): string;
39
+ }
package/package.json ADDED
@@ -0,0 +1,97 @@
1
+ {
2
+ "name": "@exotel-npm-dev/exotel-ai-assist",
3
+ "version": "1.0.0",
4
+ "description": "AI-powered real-time suggestions, transcript, and sentiment for agent calls",
5
+ "license": "Apache-2.0",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "require": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "./react": {
15
+ "types": "./dist/react/index.d.ts",
16
+ "require": "./dist/react/index.js",
17
+ "default": "./dist/react/index.js"
18
+ },
19
+ "./controller": {
20
+ "types": "./dist/controller/index.d.ts",
21
+ "require": "./dist/controller/index.js",
22
+ "default": "./dist/controller/index.js"
23
+ }
24
+ },
25
+ "typesVersions": {
26
+ "*": {
27
+ "react": [
28
+ "dist/react/index.d.ts"
29
+ ],
30
+ "controller": [
31
+ "dist/controller/index.d.ts"
32
+ ]
33
+ }
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "react.js",
38
+ "controller.js"
39
+ ],
40
+ "scripts": {
41
+ "build": "tsc --emitDeclarationOnly && NODE_ENV=production rollup --config rollup.config.mjs",
42
+ "dev": "rollup --config rollup.config.mjs --watch",
43
+ "clean": "rm -rf dist",
44
+ "lint": "eslint src --ext .ts,.tsx"
45
+ },
46
+ "devDependencies": {
47
+ "@babel/core": "^7.29.0",
48
+ "@babel/preset-env": "^7.29.0",
49
+ "@rollup/plugin-babel": "^7.0.0",
50
+ "@rollup/plugin-commonjs": "^29.0.2",
51
+ "@rollup/plugin-node-resolve": "^16.0.3",
52
+ "@rollup/plugin-typescript": "^12.3.0",
53
+ "@types/node": "^20.0.0",
54
+ "@types/object-hash": "^3.0.6",
55
+ "@types/react": "^16.14.0",
56
+ "@types/react-dom": "^16.9.0",
57
+ "postcss": "^8.5.8",
58
+ "react": "^16.14.0",
59
+ "react-dom": "^16.14.0",
60
+ "rollup": "^4.59.0",
61
+ "rollup-plugin-postcss": "^4.0.2",
62
+ "tslib": "^2.8.1",
63
+ "typescript": "^5.4.0"
64
+ },
65
+ "dependencies": {
66
+ "@radix-ui/react-tabs": "^1.1.0",
67
+ "@radix-ui/react-tooltip": "^1.1.0",
68
+ "eventemitter3": "^5.0.1",
69
+ "lucide-react": "^0.263.0",
70
+ "object-hash": "^3.0.0"
71
+ },
72
+ "peerDependencies": {
73
+ "react": ">=16.8.0",
74
+ "react-dom": ">=16.8.0"
75
+ },
76
+ "peerDependenciesMeta": {
77
+ "react": {
78
+ "optional": true
79
+ },
80
+ "react-dom": {
81
+ "optional": true
82
+ }
83
+ },
84
+ "engines": {
85
+ "node": ">=16"
86
+ },
87
+ "keywords": [
88
+ "exotel",
89
+ "ai",
90
+ "assist",
91
+ "call",
92
+ "websocket",
93
+ "transcript",
94
+ "sentiment",
95
+ "suggestion"
96
+ ]
97
+ }
package/react.js ADDED
@@ -0,0 +1,5 @@
1
+ // Webpack 4 / CRA 4 compatibility shim.
2
+ // Modern bundlers (webpack 5+) use the "exports" field in package.json and
3
+ // never load this file. Webpack 4 does not understand "exports", so it
4
+ // resolves @exotel-npm-dev/exotel-ai-assist/react to this CJS file directly.
5
+ module.exports = require("./dist/react/index.js");