@kognitivedev/cloud-voice 0.2.29
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/.turbo/turbo-build.log +2 -0
- package/.turbo/turbo-test.log +13 -0
- package/CHANGELOG.md +10 -0
- package/README.md +226 -0
- package/dist/browser.d.ts +7 -0
- package/dist/browser.js +301 -0
- package/dist/client.d.ts +219 -0
- package/dist/client.js +535 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +15 -0
- package/dist/server.d.ts +58 -0
- package/dist/server.js +92 -0
- package/dist/server.test.d.ts +1 -0
- package/dist/server.test.js +78 -0
- package/dist/sse.d.ts +7 -0
- package/dist/sse.js +75 -0
- package/dist/types.d.ts +865 -0
- package/dist/types.js +2 -0
- package/package.json +52 -0
- package/src/__tests__/browser.test.ts +196 -0
- package/src/__tests__/client.test.ts +482 -0
- package/src/__tests__/server.test.ts +84 -0
- package/src/browser.ts +342 -0
- package/src/client.ts +610 -0
- package/src/index.ts +100 -0
- package/src/server.ts +140 -0
- package/src/sse.ts +57 -0
- package/src/types.ts +927 -0
- package/tsconfig.json +14 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
$ vitest run
|
|
2
|
+
|
|
3
|
+
RUN v3.2.4 /Users/vserifsaglam/work/memory-experiment/packages/cloud-voice
|
|
4
|
+
|
|
5
|
+
✓ src/__tests__/browser.test.ts (3 tests) 7ms
|
|
6
|
+
✓ src/__tests__/server.test.ts (2 tests) 7ms
|
|
7
|
+
✓ src/__tests__/client.test.ts (13 tests) 55ms
|
|
8
|
+
|
|
9
|
+
Test Files 3 passed (3)
|
|
10
|
+
Tests 18 passed (18)
|
|
11
|
+
Start at 17:30:01
|
|
12
|
+
Duration 1.22s (transform 248ms, setup 0ms, collect 475ms, tests 69ms, environment 0ms, prepare 823ms)
|
|
13
|
+
|
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# @kognitivedev/cloud-voice
|
|
2
|
+
|
|
3
|
+
Cloud Voice Agents SDK for Kognitive hosted `/api/cloud/voice/*` APIs.
|
|
4
|
+
|
|
5
|
+
Create and publish agents in the Kognitive dashboard under **Voice > Agents**, then use the deploy page to generate origin-constrained `kvp_*` public embed keys. Browser code uses `kvp_*` keys only. Private `kog_*` project API keys stay server-side.
|
|
6
|
+
|
|
7
|
+
## Server SDK
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { KognitiveCloudVoiceClient } from "@kognitivedev/cloud-voice";
|
|
11
|
+
|
|
12
|
+
const voice = new KognitiveCloudVoiceClient({
|
|
13
|
+
baseUrl: process.env.KOGNITIVE_API_URL!,
|
|
14
|
+
apiKey: process.env.KOGNITIVE_API_KEY,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
await voice.agents.management.create({
|
|
18
|
+
name: "Support",
|
|
19
|
+
slug: "support",
|
|
20
|
+
config: {
|
|
21
|
+
instructions: "Help customers over voice.",
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
await voice.agents.management.publish("support");
|
|
26
|
+
|
|
27
|
+
// Idempotent create-or-update by slug. This is the preferred setup helper for
|
|
28
|
+
// scripts, deploy hooks, and customer provisioning flows.
|
|
29
|
+
const { agent, action } = await voice.agents.management.createOrUse("support", {
|
|
30
|
+
name: "Support",
|
|
31
|
+
publish: true,
|
|
32
|
+
config: {
|
|
33
|
+
instructions: "Help customers over voice.",
|
|
34
|
+
provider: "openai-realtime",
|
|
35
|
+
model: "gpt-realtime",
|
|
36
|
+
voice: "marin",
|
|
37
|
+
transport: "webrtc",
|
|
38
|
+
channels: {
|
|
39
|
+
web: true,
|
|
40
|
+
iframe: true,
|
|
41
|
+
script: true,
|
|
42
|
+
phone: true,
|
|
43
|
+
sip: false,
|
|
44
|
+
outbound: true,
|
|
45
|
+
},
|
|
46
|
+
humanization: {
|
|
47
|
+
openingMode: "auto",
|
|
48
|
+
openingStyle: "warm",
|
|
49
|
+
fillerStyle: "light",
|
|
50
|
+
backchannelFrequency: "low",
|
|
51
|
+
disfluency: "rare",
|
|
52
|
+
toolLatencyFillerMs: 700,
|
|
53
|
+
},
|
|
54
|
+
widget: {
|
|
55
|
+
title: "Talk to support",
|
|
56
|
+
subtitle: "Voice agent",
|
|
57
|
+
launcher: "button",
|
|
58
|
+
position: "bottom-right",
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
console.log(action, agent.slug);
|
|
64
|
+
|
|
65
|
+
const session = await voice.sessions.create("support", {
|
|
66
|
+
userId: "user_123",
|
|
67
|
+
channel: "web",
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Phone Calls
|
|
72
|
+
|
|
73
|
+
Cloud Phone uses the same Cloud Voice agent/session/event model for PSTN/SIP channels. Configure provider credentials and assign numbers in the dashboard under **Voice > Phone Numbers**.
|
|
74
|
+
|
|
75
|
+
Outbound calls are server-side and use private `kog_*` API keys:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
const call = await voice.calls.create({
|
|
79
|
+
agent: "support",
|
|
80
|
+
fromNumberId: "number_123",
|
|
81
|
+
to: "+15551234567",
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Inbound calls are bound through phone numbers:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
await voice.phone.numbers.create({
|
|
89
|
+
phoneNumber: "+15551234567",
|
|
90
|
+
inboundAgentSlug: "support",
|
|
91
|
+
inboundEnabled: true,
|
|
92
|
+
outboundEnabled: true,
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Live phone audio requires the Cloud Voice phone bridge:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
cd apps/backend
|
|
100
|
+
bun run phone:bridge
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The bridge handles Twilio `wss://` Media Streams and reports readiness through the SDK:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
const bridge = await voice.phone.bridge.health();
|
|
107
|
+
console.log(bridge.online);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Phone-call tools execute through managed Cloud Voice tools and optional per-call server tool bridges. Browser SDK tools do not run for phone calls because there is no browser parent page during PSTN execution.
|
|
111
|
+
|
|
112
|
+
## Browser widget
|
|
113
|
+
|
|
114
|
+
Browser embeds use public `kvp_*` keys:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
import { createVoiceWidget } from "@kognitivedev/cloud-voice/browser";
|
|
118
|
+
|
|
119
|
+
createVoiceWidget({
|
|
120
|
+
baseUrl: "https://dashboard.example.com",
|
|
121
|
+
publicKey: "kvp_...",
|
|
122
|
+
agent: "support",
|
|
123
|
+
target: "#voice-agent",
|
|
124
|
+
style: {
|
|
125
|
+
theme: "minimal",
|
|
126
|
+
accentColor: "#111111",
|
|
127
|
+
surfaceColor: "#fffdf8",
|
|
128
|
+
radius: "12px",
|
|
129
|
+
shadow: "none",
|
|
130
|
+
align: "center",
|
|
131
|
+
},
|
|
132
|
+
iframe: {
|
|
133
|
+
width: "380",
|
|
134
|
+
height: "620",
|
|
135
|
+
style: { borderRadius: "16px" },
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Client-side tools
|
|
141
|
+
|
|
142
|
+
Customer SDK tools execute in the app that embeds the widget. The SDK sends only the tool manifest/schema to Cloud Voice; function code stays in the browser.
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
createVoiceWidget({
|
|
146
|
+
baseUrl: "https://dashboard.example.com",
|
|
147
|
+
publicKey: "kvp_...",
|
|
148
|
+
agent: "support",
|
|
149
|
+
target: "#voice-agent",
|
|
150
|
+
tools: {
|
|
151
|
+
lookup_order: {
|
|
152
|
+
description: "Look up an order in this app.",
|
|
153
|
+
inputSchema: {
|
|
154
|
+
type: "object",
|
|
155
|
+
properties: { orderNumber: { type: "string" } },
|
|
156
|
+
required: ["orderNumber"],
|
|
157
|
+
},
|
|
158
|
+
execute: async ({ orderNumber }) => fetchOrder(orderNumber),
|
|
159
|
+
render: ({ input, output, state }) => {
|
|
160
|
+
if (state === "input-available") return "Looking up order...";
|
|
161
|
+
return `Order ${input.orderNumber}: ${output.status}`;
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
managed_tool_ui: ({ output, state }) => {
|
|
165
|
+
if (state !== "output-available") return "Running...";
|
|
166
|
+
return `Managed tool returned ${JSON.stringify(output)}`;
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Tools with `execute` are registered as client tools and run in the customer page through the iframe bridge. Renderer-only shorthand is local UI for tools executed elsewhere, such as managed cloud tools configured on the agent.
|
|
173
|
+
|
|
174
|
+
## Iframe embed
|
|
175
|
+
|
|
176
|
+
```html
|
|
177
|
+
<iframe
|
|
178
|
+
src="https://dashboard.example.com/voice/embed?publicKey=kvp_...&agent=support&theme=minimal&accent=%23111111&surface=%23fffdf8&radius=12px&shadow=none"
|
|
179
|
+
allow="microphone; autoplay"
|
|
180
|
+
width="380"
|
|
181
|
+
height="620"
|
|
182
|
+
style="border:0;border-radius:16px;max-width:100%;"
|
|
183
|
+
></iframe>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Style options
|
|
187
|
+
|
|
188
|
+
`createVoiceWidget({ style })` and iframe query params support:
|
|
189
|
+
|
|
190
|
+
- `theme`: `default`, `minimal`, `solid`, `glass`
|
|
191
|
+
- `accentColor`, `backgroundColor`, `surfaceColor`, `textColor`, `mutedColor`
|
|
192
|
+
- `width`, `padding`, `gap`, `radius`, `panelRadius`, `buttonRadius`, `orbSize`
|
|
193
|
+
- `shadow`: `none`, `soft`, `strong`
|
|
194
|
+
- `align`: `center`, `top`, `bottom`
|
|
195
|
+
- `density`: `compact`, `comfortable`
|
|
196
|
+
|
|
197
|
+
For iframe query params, use the shorter aliases where available: `accent`, `bg`, `surface`, `text`, and `muted`.
|
|
198
|
+
|
|
199
|
+
## Phone server tools
|
|
200
|
+
|
|
201
|
+
Custom phone tools are normal Kognitive server tools exposed to the phone bridge for the lifetime of a call. Define them once in the customer app, register them on the `Kognitive` instance, and provide a per-call tool bridge URL when creating or binding a phone call.
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
import { Kognitive } from "@kognitivedev/core";
|
|
205
|
+
import { createTool } from "@kognitivedev/tools";
|
|
206
|
+
import { z } from "zod";
|
|
207
|
+
|
|
208
|
+
const lookupOrder = createTool({
|
|
209
|
+
id: "lookup_order",
|
|
210
|
+
description: "Look up an order by number",
|
|
211
|
+
inputSchema: z.object({
|
|
212
|
+
orderNumber: z.string(),
|
|
213
|
+
}),
|
|
214
|
+
execute: async ({ orderNumber }, ctx) => {
|
|
215
|
+
return db.orders.findByNumber(orderNumber);
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
export const kognitive = new Kognitive({
|
|
220
|
+
apiKey: process.env.KOGNITIVE_API_KEY,
|
|
221
|
+
baseUrl: process.env.KOGNITIVE_API_URL,
|
|
222
|
+
tools: [lookupOrder],
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Server tools work for inbound and outbound phone sessions when the call metadata includes the tool bridge URL. Browser SDK tools are separate: they run in the customer page and can render custom UI, but they cannot answer phone tool calls.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CloudVoiceEmbedOptions } from "./types";
|
|
2
|
+
export declare function mountIframe(options: CloudVoiceEmbedOptions): HTMLIFrameElement;
|
|
3
|
+
export declare function createVoiceSession(options: CloudVoiceEmbedOptions): Promise<import("./types").CloudVoiceSessionBootstrap>;
|
|
4
|
+
export declare function createVoiceWidget(options: CloudVoiceEmbedOptions): {
|
|
5
|
+
iframe: HTMLIFrameElement;
|
|
6
|
+
destroy(): void;
|
|
7
|
+
};
|
package/dist/browser.js
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mountIframe = mountIframe;
|
|
4
|
+
exports.createVoiceSession = createVoiceSession;
|
|
5
|
+
exports.createVoiceWidget = createVoiceWidget;
|
|
6
|
+
const client_1 = require("./client");
|
|
7
|
+
const MESSAGE_READY = "kognitive.cloudVoice.iframe.ready";
|
|
8
|
+
const MESSAGE_REGISTER_TOOLS = "kognitive.cloudVoice.tools.register";
|
|
9
|
+
const MESSAGE_TOOLS_REGISTERED = "kognitive.cloudVoice.tools.registered";
|
|
10
|
+
const MESSAGE_TOOL_CALL = "kognitive.cloudVoice.tool.call";
|
|
11
|
+
const MESSAGE_TOOL_RESULT = "kognitive.cloudVoice.tool.result";
|
|
12
|
+
const MESSAGE_TOOL_STATE = "kognitive.cloudVoice.tool.state";
|
|
13
|
+
const iframeCleanups = new WeakMap();
|
|
14
|
+
function resolveTarget(target) {
|
|
15
|
+
if (target instanceof HTMLElement)
|
|
16
|
+
return target;
|
|
17
|
+
if (typeof target === "string") {
|
|
18
|
+
const element = document.querySelector(target);
|
|
19
|
+
if (element instanceof HTMLElement)
|
|
20
|
+
return element;
|
|
21
|
+
}
|
|
22
|
+
return document.body;
|
|
23
|
+
}
|
|
24
|
+
function appendStyleParams(params, style) {
|
|
25
|
+
if (!style)
|
|
26
|
+
return;
|
|
27
|
+
const entries = [
|
|
28
|
+
["theme", style.theme],
|
|
29
|
+
["accent", style.accentColor],
|
|
30
|
+
["bg", style.backgroundColor],
|
|
31
|
+
["surface", style.surfaceColor],
|
|
32
|
+
["text", style.textColor],
|
|
33
|
+
["muted", style.mutedColor],
|
|
34
|
+
["width", style.width],
|
|
35
|
+
["padding", style.padding],
|
|
36
|
+
["gap", style.gap],
|
|
37
|
+
["radius", style.radius],
|
|
38
|
+
["panelRadius", style.panelRadius],
|
|
39
|
+
["buttonRadius", style.buttonRadius],
|
|
40
|
+
["orbSize", style.orbSize],
|
|
41
|
+
["shadow", style.shadow],
|
|
42
|
+
["align", style.align],
|
|
43
|
+
["density", style.density],
|
|
44
|
+
];
|
|
45
|
+
for (const [key, value] of entries) {
|
|
46
|
+
if (value)
|
|
47
|
+
params.set(key, value);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function isToolDefinition(value) {
|
|
51
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
52
|
+
}
|
|
53
|
+
function getToolRenderer(tool) {
|
|
54
|
+
if (!tool)
|
|
55
|
+
return undefined;
|
|
56
|
+
if (typeof tool === "function")
|
|
57
|
+
return tool;
|
|
58
|
+
return typeof tool.render === "function" ? tool.render : undefined;
|
|
59
|
+
}
|
|
60
|
+
function getToolExecutor(tool) {
|
|
61
|
+
if (!tool || !isToolDefinition(tool))
|
|
62
|
+
return undefined;
|
|
63
|
+
return typeof tool.execute === "function" ? tool.execute : undefined;
|
|
64
|
+
}
|
|
65
|
+
function getExecutableToolManifests(tools) {
|
|
66
|
+
if (!tools)
|
|
67
|
+
return [];
|
|
68
|
+
return Object.entries(tools)
|
|
69
|
+
.filter(([, tool]) => Boolean(getToolExecutor(tool)))
|
|
70
|
+
.map(([id, tool]) => {
|
|
71
|
+
var _a, _b, _c, _d;
|
|
72
|
+
const definition = isToolDefinition(tool) ? tool : {};
|
|
73
|
+
return {
|
|
74
|
+
id,
|
|
75
|
+
name: (_a = definition.name) !== null && _a !== void 0 ? _a : id,
|
|
76
|
+
description: (_c = (_b = definition.description) !== null && _b !== void 0 ? _b : definition.name) !== null && _c !== void 0 ? _c : id,
|
|
77
|
+
inputSchema: (_d = definition.inputSchema) !== null && _d !== void 0 ? _d : { type: "object", additionalProperties: true },
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function getIframeTargetOrigin(src) {
|
|
82
|
+
try {
|
|
83
|
+
return new URL(src).origin;
|
|
84
|
+
}
|
|
85
|
+
catch (_a) {
|
|
86
|
+
return "*";
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function isMessage(value) {
|
|
90
|
+
return Boolean(value && typeof value === "object" && "type" in value);
|
|
91
|
+
}
|
|
92
|
+
function escapeSelector(value) {
|
|
93
|
+
return typeof CSS !== "undefined" && typeof CSS.escape === "function"
|
|
94
|
+
? CSS.escape(value)
|
|
95
|
+
: value.replace(/["\\]/g, "\\$&");
|
|
96
|
+
}
|
|
97
|
+
function createToolRoot(options, target) {
|
|
98
|
+
if (!options.tools)
|
|
99
|
+
return { root: null, owned: false };
|
|
100
|
+
const explicitTarget = options.toolTarget ? resolveTarget(options.toolTarget) : null;
|
|
101
|
+
const root = explicitTarget !== null && explicitTarget !== void 0 ? explicitTarget : document.createElement("div");
|
|
102
|
+
root.className = [root.className, "kognitive-cloud-voice-tools"].filter(Boolean).join(" ");
|
|
103
|
+
if (!explicitTarget) {
|
|
104
|
+
target.appendChild(root);
|
|
105
|
+
}
|
|
106
|
+
return { root, owned: !explicitTarget };
|
|
107
|
+
}
|
|
108
|
+
function renderToolState(input) {
|
|
109
|
+
var _a, _b;
|
|
110
|
+
(_a = input.onToolState) === null || _a === void 0 ? void 0 : _a.call(input, input.state);
|
|
111
|
+
const renderer = getToolRenderer((_b = input.tools) === null || _b === void 0 ? void 0 : _b[input.state.toolName]);
|
|
112
|
+
if (!renderer || !input.root)
|
|
113
|
+
return;
|
|
114
|
+
const rendered = renderer(input.state);
|
|
115
|
+
const id = input.state.toolCallId || input.state.toolName;
|
|
116
|
+
let mount = input.root.querySelector(`[data-kognitive-tool-call-id="${escapeSelector(id)}"]`);
|
|
117
|
+
if (!mount) {
|
|
118
|
+
mount = document.createElement("div");
|
|
119
|
+
mount.dataset.kognitiveToolCallId = id;
|
|
120
|
+
mount.dataset.kognitiveToolName = input.state.toolName;
|
|
121
|
+
input.root.appendChild(mount);
|
|
122
|
+
}
|
|
123
|
+
mount.dataset.kognitiveToolState = input.state.state;
|
|
124
|
+
if (typeof Node !== "undefined" && rendered instanceof Node) {
|
|
125
|
+
mount.replaceChildren(rendered);
|
|
126
|
+
}
|
|
127
|
+
else if (typeof rendered === "string") {
|
|
128
|
+
mount.textContent = rendered;
|
|
129
|
+
}
|
|
130
|
+
else if (rendered == null) {
|
|
131
|
+
mount.replaceChildren();
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
mount.dispatchEvent(new CustomEvent("kognitive-cloud-voice-render", {
|
|
135
|
+
detail: { rendered, state: input.state },
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function mountIframe(options) {
|
|
140
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
141
|
+
const target = resolveTarget(options.target);
|
|
142
|
+
const iframe = document.createElement("iframe");
|
|
143
|
+
const clientTools = getExecutableToolManifests(options.tools);
|
|
144
|
+
const params = new URLSearchParams(Object.assign(Object.assign(Object.assign({ publicKey: options.publicKey, agent: options.agent }, (options.userId ? { userId: options.userId } : {})), (options.parameters ? { parameters: JSON.stringify(options.parameters) } : {})), (options.tools ? { sdk: "1" } : {})));
|
|
145
|
+
appendStyleParams(params, options.style);
|
|
146
|
+
iframe.src = `${options.baseUrl.replace(/\/$/, "")}/voice/embed?${params.toString()}`;
|
|
147
|
+
iframe.title = (_b = (_a = options.iframe) === null || _a === void 0 ? void 0 : _a.title) !== null && _b !== void 0 ? _b : "Kognitive voice agent";
|
|
148
|
+
iframe.width = (_d = (_c = options.iframe) === null || _c === void 0 ? void 0 : _c.width) !== null && _d !== void 0 ? _d : "380";
|
|
149
|
+
iframe.height = (_f = (_e = options.iframe) === null || _e === void 0 ? void 0 : _e.height) !== null && _f !== void 0 ? _f : "620";
|
|
150
|
+
iframe.setAttribute("allow", "microphone; autoplay");
|
|
151
|
+
iframe.style.border = "0";
|
|
152
|
+
iframe.style.maxWidth = "100%";
|
|
153
|
+
if ((_g = options.style) === null || _g === void 0 ? void 0 : _g.width)
|
|
154
|
+
iframe.style.width = options.style.width;
|
|
155
|
+
if ((_h = options.iframe) === null || _h === void 0 ? void 0 : _h.style)
|
|
156
|
+
Object.assign(iframe.style, options.iframe.style);
|
|
157
|
+
const toolRoot = createToolRoot(options, target);
|
|
158
|
+
const targetOrigin = getIframeTargetOrigin(iframe.src);
|
|
159
|
+
function postToolRegistration() {
|
|
160
|
+
var _a;
|
|
161
|
+
(_a = iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage({
|
|
162
|
+
type: MESSAGE_REGISTER_TOOLS,
|
|
163
|
+
tools: clientTools,
|
|
164
|
+
}, targetOrigin);
|
|
165
|
+
}
|
|
166
|
+
function handleMessage(event) {
|
|
167
|
+
var _a, _b, _c;
|
|
168
|
+
if (event.source !== iframe.contentWindow || !isMessage(event.data))
|
|
169
|
+
return;
|
|
170
|
+
if (event.data.type === MESSAGE_READY) {
|
|
171
|
+
postToolRegistration();
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (event.data.type === MESSAGE_TOOL_STATE) {
|
|
175
|
+
const message = event.data;
|
|
176
|
+
renderToolState({
|
|
177
|
+
root: toolRoot.root,
|
|
178
|
+
tools: options.tools,
|
|
179
|
+
onToolState: options.onToolState,
|
|
180
|
+
state: {
|
|
181
|
+
toolName: message.toolName,
|
|
182
|
+
toolCallId: (_a = message.toolCallId) !== null && _a !== void 0 ? _a : message.toolName,
|
|
183
|
+
input: message.input,
|
|
184
|
+
output: message.output,
|
|
185
|
+
error: message.error,
|
|
186
|
+
state: message.state,
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (event.data.type !== MESSAGE_TOOL_CALL)
|
|
192
|
+
return;
|
|
193
|
+
const message = event.data;
|
|
194
|
+
const tool = (_b = options.tools) === null || _b === void 0 ? void 0 : _b[message.toolName];
|
|
195
|
+
const execute = getToolExecutor(tool);
|
|
196
|
+
const toolCallId = (_c = message.toolCallId) !== null && _c !== void 0 ? _c : message.requestId;
|
|
197
|
+
void (async () => {
|
|
198
|
+
var _a, _b, _c, _d, _e;
|
|
199
|
+
renderToolState({
|
|
200
|
+
root: toolRoot.root,
|
|
201
|
+
tools: options.tools,
|
|
202
|
+
onToolState: options.onToolState,
|
|
203
|
+
state: {
|
|
204
|
+
toolName: message.toolName,
|
|
205
|
+
toolCallId,
|
|
206
|
+
input: message.args,
|
|
207
|
+
state: "input-available",
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
if (!execute) {
|
|
211
|
+
(_a = iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage({
|
|
212
|
+
type: MESSAGE_TOOL_RESULT,
|
|
213
|
+
requestId: message.requestId,
|
|
214
|
+
error: `No client executor registered for ${message.toolName}`,
|
|
215
|
+
}, targetOrigin);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
try {
|
|
219
|
+
const result = await execute(message.args, {
|
|
220
|
+
toolName: message.toolName,
|
|
221
|
+
toolCallId,
|
|
222
|
+
callId: (_b = message.context) === null || _b === void 0 ? void 0 : _b.callId,
|
|
223
|
+
sessionId: (_c = message.context) === null || _c === void 0 ? void 0 : _c.sessionId,
|
|
224
|
+
});
|
|
225
|
+
renderToolState({
|
|
226
|
+
root: toolRoot.root,
|
|
227
|
+
tools: options.tools,
|
|
228
|
+
onToolState: options.onToolState,
|
|
229
|
+
state: {
|
|
230
|
+
toolName: message.toolName,
|
|
231
|
+
toolCallId,
|
|
232
|
+
input: message.args,
|
|
233
|
+
output: result,
|
|
234
|
+
state: "output-available",
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
(_d = iframe.contentWindow) === null || _d === void 0 ? void 0 : _d.postMessage({
|
|
238
|
+
type: MESSAGE_TOOL_RESULT,
|
|
239
|
+
requestId: message.requestId,
|
|
240
|
+
result,
|
|
241
|
+
}, targetOrigin);
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
const messageText = error instanceof Error ? error.message : "Client tool failed";
|
|
245
|
+
renderToolState({
|
|
246
|
+
root: toolRoot.root,
|
|
247
|
+
tools: options.tools,
|
|
248
|
+
onToolState: options.onToolState,
|
|
249
|
+
state: {
|
|
250
|
+
toolName: message.toolName,
|
|
251
|
+
toolCallId,
|
|
252
|
+
input: message.args,
|
|
253
|
+
error: messageText,
|
|
254
|
+
state: "error",
|
|
255
|
+
},
|
|
256
|
+
});
|
|
257
|
+
(_e = iframe.contentWindow) === null || _e === void 0 ? void 0 : _e.postMessage({
|
|
258
|
+
type: MESSAGE_TOOL_RESULT,
|
|
259
|
+
requestId: message.requestId,
|
|
260
|
+
error: messageText,
|
|
261
|
+
}, targetOrigin);
|
|
262
|
+
}
|
|
263
|
+
})();
|
|
264
|
+
}
|
|
265
|
+
window.addEventListener("message", handleMessage);
|
|
266
|
+
iframe.addEventListener("load", postToolRegistration);
|
|
267
|
+
iframeCleanups.set(iframe, () => {
|
|
268
|
+
var _a;
|
|
269
|
+
window.removeEventListener("message", handleMessage);
|
|
270
|
+
iframe.removeEventListener("load", postToolRegistration);
|
|
271
|
+
if (toolRoot.owned)
|
|
272
|
+
(_a = toolRoot.root) === null || _a === void 0 ? void 0 : _a.remove();
|
|
273
|
+
});
|
|
274
|
+
target.appendChild(iframe);
|
|
275
|
+
return iframe;
|
|
276
|
+
}
|
|
277
|
+
function createVoiceSession(options) {
|
|
278
|
+
const client = new client_1.KognitiveCloudVoiceEmbedClient({
|
|
279
|
+
baseUrl: options.baseUrl,
|
|
280
|
+
publicKey: options.publicKey,
|
|
281
|
+
});
|
|
282
|
+
return client.createSession({
|
|
283
|
+
agentSlug: options.agent,
|
|
284
|
+
channel: "script",
|
|
285
|
+
userId: options.userId,
|
|
286
|
+
parameters: options.parameters,
|
|
287
|
+
clientTools: getExecutableToolManifests(options.tools),
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
function createVoiceWidget(options) {
|
|
291
|
+
const iframe = mountIframe(options);
|
|
292
|
+
return {
|
|
293
|
+
iframe,
|
|
294
|
+
destroy() {
|
|
295
|
+
var _a;
|
|
296
|
+
(_a = iframeCleanups.get(iframe)) === null || _a === void 0 ? void 0 : _a();
|
|
297
|
+
iframeCleanups.delete(iframe);
|
|
298
|
+
iframe.remove();
|
|
299
|
+
},
|
|
300
|
+
};
|
|
301
|
+
}
|