@voicelayer/sdk 0.1.8 → 0.1.10
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/dist/index.d.ts +34 -1184
- package/dist/index.js +209 -131
- package/dist/runtime/text-session.d.ts +1 -1
- package/dist/runtime/text-session.js +730 -16
- package/dist/text-session-D1j8nQac.d.ts +1996 -0
- package/package.json +4 -4
- package/dist/text-session-BoUmDEX9.d.ts +0 -837
package/dist/index.js
CHANGED
|
@@ -3133,7 +3133,7 @@ var init_executors = __esm({
|
|
|
3133
3133
|
const authoredSlot = slot === node.id ? "" : slot.trim();
|
|
3134
3134
|
const label = authoredSlot.replace(/[_-]+/g, " ");
|
|
3135
3135
|
if (hasSlot(deps.processRt.getData(), slot)) {
|
|
3136
|
-
|
|
3136
|
+
deps.events.note("ask.skipped", { slot: slot.trim(), reason: "already known" });
|
|
3137
3137
|
return { kind: "advance" };
|
|
3138
3138
|
}
|
|
3139
3139
|
const askText = interpolate(
|
|
@@ -3147,10 +3147,10 @@ var init_executors = __esm({
|
|
|
3147
3147
|
state.lastUtterance = t.text;
|
|
3148
3148
|
state.lastDtmf = t.dtmf;
|
|
3149
3149
|
if (hasSlot(deps.processRt.getData(), slot)) {
|
|
3150
|
-
|
|
3150
|
+
deps.events.note("ask.captured", { slot: slot.trim() });
|
|
3151
3151
|
return { kind: "advance" };
|
|
3152
3152
|
}
|
|
3153
|
-
|
|
3153
|
+
deps.events.note("ask.clarify", { slot: slot.trim(), turn });
|
|
3154
3154
|
await withHistory(
|
|
3155
3155
|
deps,
|
|
3156
3156
|
historyPolicyOf(node),
|
|
@@ -3251,11 +3251,18 @@ ${collected}`);
|
|
|
3251
3251
|
if (ok && cfg.outputAs && typeof cfg.outputAs === "object") {
|
|
3252
3252
|
for (const [slot, path] of Object.entries(cfg.outputAs)) {
|
|
3253
3253
|
if (typeof path !== "string" || !path.trim()) continue;
|
|
3254
|
-
const
|
|
3255
|
-
if (
|
|
3256
|
-
deps.
|
|
3257
|
-
|
|
3254
|
+
const raw = resolvePath(result, path.trim());
|
|
3255
|
+
if (raw === void 0 || raw === null) {
|
|
3256
|
+
deps.events.note("tool.output_missing", { node: node.id, slot, path });
|
|
3257
|
+
continue;
|
|
3258
3258
|
}
|
|
3259
|
+
const value = typeof raw === "string" ? raw : typeof raw === "number" || typeof raw === "boolean" || typeof raw === "bigint" ? String(raw) : JSON.stringify(raw);
|
|
3260
|
+
const captured = deps.processRt.captureField(slot, value);
|
|
3261
|
+
deps.events.note(captured ? "tool.output_captured" : "tool.output_rejected", {
|
|
3262
|
+
node: node.id,
|
|
3263
|
+
slot,
|
|
3264
|
+
...captured ? {} : { reason: "slot not declared or value not coercible" }
|
|
3265
|
+
});
|
|
3259
3266
|
}
|
|
3260
3267
|
}
|
|
3261
3268
|
return routeByPort(node, deps, ok ? "ok" : "fail");
|
|
@@ -3764,13 +3771,19 @@ ${collected}`);
|
|
|
3764
3771
|
setExecutor = async (node, state, deps) => {
|
|
3765
3772
|
const assignments = Array.isArray(node.config.assignments) ? node.config.assignments : [];
|
|
3766
3773
|
let applied = 0;
|
|
3774
|
+
const rejected = [];
|
|
3767
3775
|
for (const a of assignments) {
|
|
3768
3776
|
if (!a || typeof a.name !== "string" || !a.name.trim()) continue;
|
|
3777
|
+
const name = a.name.trim();
|
|
3769
3778
|
const value = interpolate(typeof a.value === "string" ? a.value : "", scopeFor(state, deps));
|
|
3770
|
-
deps.processRt.captureField(
|
|
3771
|
-
|
|
3779
|
+
if (deps.processRt.captureField(name, value)) applied += 1;
|
|
3780
|
+
else rejected.push(name);
|
|
3772
3781
|
}
|
|
3773
|
-
deps.events.note("set.applied", {
|
|
3782
|
+
deps.events.note("set.applied", {
|
|
3783
|
+
node: node.id,
|
|
3784
|
+
count: applied,
|
|
3785
|
+
...rejected.length ? { rejected } : {}
|
|
3786
|
+
});
|
|
3774
3787
|
return { kind: "advance" };
|
|
3775
3788
|
};
|
|
3776
3789
|
MAX_SUBFLOW_DEPTH = 3;
|
|
@@ -7365,6 +7378,125 @@ function createTextSessionAdapter(transport) {
|
|
|
7365
7378
|
return { adapter, push, setState, close };
|
|
7366
7379
|
}
|
|
7367
7380
|
|
|
7381
|
+
// src/flow-runtime.ts
|
|
7382
|
+
init_define_tool();
|
|
7383
|
+
function processSchemaToDefinition(schema) {
|
|
7384
|
+
const required = new Set(schema.completionGate.requiredFields);
|
|
7385
|
+
const collect = {};
|
|
7386
|
+
for (const f of schema.fields) {
|
|
7387
|
+
collect[f.name] = {
|
|
7388
|
+
type: f.type,
|
|
7389
|
+
required: required.has(f.name) || f.required,
|
|
7390
|
+
...f.ask !== void 0 ? { ask: f.ask } : {},
|
|
7391
|
+
...f.pattern !== void 0 ? { pattern: new RegExp(f.pattern) } : {},
|
|
7392
|
+
...f.min !== void 0 ? { min: f.min } : {},
|
|
7393
|
+
...f.max !== void 0 ? { max: f.max } : {},
|
|
7394
|
+
...f.enum !== void 0 ? { enum: f.enum } : {}
|
|
7395
|
+
};
|
|
7396
|
+
}
|
|
7397
|
+
return {
|
|
7398
|
+
collect,
|
|
7399
|
+
completeWhen: "all-required-captured",
|
|
7400
|
+
...schema.completionGate.backendAck !== void 0 ? { backendAck: schema.completionGate.backendAck } : {}
|
|
7401
|
+
};
|
|
7402
|
+
}
|
|
7403
|
+
var DEFAULT_FLOW_PROMPT = "You are a helpful voice assistant. Keep replies short and natural.";
|
|
7404
|
+
function toTriggerCondition(on) {
|
|
7405
|
+
return on.startsWith("signal:") ? on : new RegExp(on, "i");
|
|
7406
|
+
}
|
|
7407
|
+
function toTriggerAction(then, graphNodeIds) {
|
|
7408
|
+
if (then === "endCall" || then === "end") return "endCall";
|
|
7409
|
+
if (then === "handoff") return "handoff";
|
|
7410
|
+
if (then.startsWith("say:")) return { say: then.slice(4).trim() };
|
|
7411
|
+
if (graphNodeIds?.has(then)) return { goto: then };
|
|
7412
|
+
return "handoff";
|
|
7413
|
+
}
|
|
7414
|
+
function processSchemaToAgentParts(schema, opts = {}) {
|
|
7415
|
+
const process2 = processSchemaToDefinition(schema);
|
|
7416
|
+
const promptParts = [];
|
|
7417
|
+
if (opts.basePrompt && opts.basePrompt.trim()) promptParts.push(opts.basePrompt.trim());
|
|
7418
|
+
for (const p of schema.prompts ?? []) {
|
|
7419
|
+
if (p.text.trim()) promptParts.push(p.text.trim());
|
|
7420
|
+
}
|
|
7421
|
+
const prompt = promptParts.length > 0 ? promptParts.join("\n\n") : DEFAULT_FLOW_PROMPT;
|
|
7422
|
+
let triggers;
|
|
7423
|
+
if (schema.triggers && schema.triggers.length > 0) {
|
|
7424
|
+
triggers = {};
|
|
7425
|
+
for (const t of schema.triggers) {
|
|
7426
|
+
triggers[t.name] = {
|
|
7427
|
+
on: toTriggerCondition(t.on),
|
|
7428
|
+
then: toTriggerAction(t.then, opts.graphNodeIds),
|
|
7429
|
+
...t.onlyWhile ? { onlyWhile: t.onlyWhile } : {}
|
|
7430
|
+
};
|
|
7431
|
+
}
|
|
7432
|
+
}
|
|
7433
|
+
const handoff = schema.handoff?.fallback ? {
|
|
7434
|
+
fallback: schema.handoff.fallback,
|
|
7435
|
+
...schema.handoff.routes ? { routes: schema.handoff.routes } : {}
|
|
7436
|
+
} : void 0;
|
|
7437
|
+
const memory = schema.memory ? {
|
|
7438
|
+
...schema.memory.scope ? { scope: schema.memory.scope } : {},
|
|
7439
|
+
...schema.memory.retentionDays !== void 0 ? { retentionDays: schema.memory.retentionDays } : {},
|
|
7440
|
+
...schema.memory.piiFields ? { piiFields: schema.memory.piiFields } : {}
|
|
7441
|
+
} : void 0;
|
|
7442
|
+
let tools;
|
|
7443
|
+
if (schema.tools && schema.tools.length > 0) {
|
|
7444
|
+
tools = {};
|
|
7445
|
+
for (const t of schema.tools) {
|
|
7446
|
+
if (t.auth === "connection") {
|
|
7447
|
+
tools[t.name] = {
|
|
7448
|
+
description: t.description,
|
|
7449
|
+
input: t.input,
|
|
7450
|
+
run: () => ({
|
|
7451
|
+
kind: "unavailable",
|
|
7452
|
+
reason: "connection-auth tools need the vault resolver (not wired yet)"
|
|
7453
|
+
})
|
|
7454
|
+
};
|
|
7455
|
+
continue;
|
|
7456
|
+
}
|
|
7457
|
+
Object.assign(
|
|
7458
|
+
tools,
|
|
7459
|
+
httpTool({
|
|
7460
|
+
name: t.name,
|
|
7461
|
+
description: t.description,
|
|
7462
|
+
input: t.input,
|
|
7463
|
+
url: t.url,
|
|
7464
|
+
method: t.method,
|
|
7465
|
+
...t.headers ? { headers: t.headers } : {}
|
|
7466
|
+
})
|
|
7467
|
+
);
|
|
7468
|
+
}
|
|
7469
|
+
}
|
|
7470
|
+
let speech;
|
|
7471
|
+
if (schema.speech) {
|
|
7472
|
+
const i = schema.speech.interruption;
|
|
7473
|
+
const e = schema.speech.endpointing;
|
|
7474
|
+
const interruption = i ? {
|
|
7475
|
+
...i.enabled !== void 0 ? { enabled: i.enabled } : {},
|
|
7476
|
+
...i.minWords !== void 0 ? { minWords: i.minWords } : {},
|
|
7477
|
+
...i.minDuration !== void 0 ? { minDuration: i.minDuration } : {}
|
|
7478
|
+
} : void 0;
|
|
7479
|
+
const endpointing = e ? {
|
|
7480
|
+
...e.minDelay !== void 0 ? { minDelay: e.minDelay } : {},
|
|
7481
|
+
...e.maxDelay !== void 0 ? { maxDelay: e.maxDelay } : {}
|
|
7482
|
+
} : void 0;
|
|
7483
|
+
speech = {
|
|
7484
|
+
...interruption && Object.keys(interruption).length ? { interruption } : {},
|
|
7485
|
+
...endpointing && Object.keys(endpointing).length ? { endpointing } : {}
|
|
7486
|
+
};
|
|
7487
|
+
if (Object.keys(speech).length === 0) speech = void 0;
|
|
7488
|
+
}
|
|
7489
|
+
return {
|
|
7490
|
+
prompt,
|
|
7491
|
+
process: process2,
|
|
7492
|
+
...triggers ? { triggers } : {},
|
|
7493
|
+
...handoff ? { handoff } : {},
|
|
7494
|
+
...memory ? { memory } : {},
|
|
7495
|
+
...tools ? { tools } : {},
|
|
7496
|
+
...speech ? { speech } : {}
|
|
7497
|
+
};
|
|
7498
|
+
}
|
|
7499
|
+
|
|
7368
7500
|
// src/runtime/text-session.ts
|
|
7369
7501
|
function buildTextContext(adapter, call, processRt) {
|
|
7370
7502
|
return {
|
|
@@ -7382,6 +7514,18 @@ function buildTextContext(adapter, call, processRt) {
|
|
|
7382
7514
|
get process() {
|
|
7383
7515
|
return { data: processRt.getData(), complete: processRt.isComplete() };
|
|
7384
7516
|
},
|
|
7517
|
+
// Voice-only actions, stubbed so a flow containing them can still be dry-run
|
|
7518
|
+
// over text. Without these the handoff node threw "deps.ctx.handoff is not
|
|
7519
|
+
// a function" mid-trace (seen in the builder's dry run); the graph now
|
|
7520
|
+
// reaches its handoff outcome cleanly and the trace says why nothing dialed.
|
|
7521
|
+
handoff: async (to) => {
|
|
7522
|
+
processRt.recordEvent({
|
|
7523
|
+
kind: "handoff.simulated",
|
|
7524
|
+
data: { to, reason: "text dry run \u2014 no telephony leg to transfer" }
|
|
7525
|
+
});
|
|
7526
|
+
},
|
|
7527
|
+
endCall: async () => {
|
|
7528
|
+
},
|
|
7385
7529
|
// Voice-only escape hatch is absent on text; left undefined.
|
|
7386
7530
|
livekit: { session: {}, job: {} }
|
|
7387
7531
|
};
|
|
@@ -7423,14 +7567,51 @@ function runTextSession(opts) {
|
|
|
7423
7567
|
end: () => handle.close()
|
|
7424
7568
|
};
|
|
7425
7569
|
}
|
|
7570
|
+
function deriveCollectFromProgram(program) {
|
|
7571
|
+
const collect = {};
|
|
7572
|
+
for (const [nodeId, node] of Object.entries(program.nodes)) {
|
|
7573
|
+
const cfg = node.config;
|
|
7574
|
+
if (node.type === "ask") {
|
|
7575
|
+
const name = typeof cfg.slot === "string" && cfg.slot ? cfg.slot : nodeId;
|
|
7576
|
+
const type = cfg.type;
|
|
7577
|
+
collect[name] = {
|
|
7578
|
+
type: type === "number" || type === "boolean" || type === "datetime" || type === "string[]" ? type : "string",
|
|
7579
|
+
...cfg.required !== false ? { required: true } : {},
|
|
7580
|
+
...typeof cfg.ask === "string" ? { ask: cfg.ask } : {},
|
|
7581
|
+
...typeof cfg.pattern === "string" ? { pattern: new RegExp(cfg.pattern) } : {}
|
|
7582
|
+
};
|
|
7583
|
+
}
|
|
7584
|
+
if (cfg.outputAs && typeof cfg.outputAs === "object") {
|
|
7585
|
+
for (const slot of Object.keys(cfg.outputAs)) {
|
|
7586
|
+
collect[slot] ??= { type: "string" };
|
|
7587
|
+
}
|
|
7588
|
+
}
|
|
7589
|
+
if (Array.isArray(cfg.assignments)) {
|
|
7590
|
+
for (const a of cfg.assignments) {
|
|
7591
|
+
if (a && typeof a.name === "string" && a.name.trim()) collect[a.name.trim()] ??= { type: "string" };
|
|
7592
|
+
}
|
|
7593
|
+
}
|
|
7594
|
+
}
|
|
7595
|
+
return { collect, completeWhen: "all-required-captured" };
|
|
7596
|
+
}
|
|
7597
|
+
function definitionFor(opts) {
|
|
7598
|
+
if (opts.schema) {
|
|
7599
|
+
try {
|
|
7600
|
+
return processSchemaToDefinition(opts.schema);
|
|
7601
|
+
} catch {
|
|
7602
|
+
}
|
|
7603
|
+
}
|
|
7604
|
+
return deriveCollectFromProgram(opts.program);
|
|
7605
|
+
}
|
|
7426
7606
|
async function runTextTranscript(opts) {
|
|
7427
7607
|
const replies = [];
|
|
7428
7608
|
const trace7 = [];
|
|
7609
|
+
const processRt = opts.processRt ?? createProcessRuntime(definitionFor(opts));
|
|
7429
7610
|
const session = runTextSession({
|
|
7430
7611
|
program: opts.program,
|
|
7431
7612
|
onAgentText: (t) => void replies.push(t),
|
|
7432
7613
|
onTrace: (e) => void trace7.push(e),
|
|
7433
|
-
...
|
|
7614
|
+
...processRt ? { processRt } : {},
|
|
7434
7615
|
...opts.generate ? { generate: opts.generate } : {},
|
|
7435
7616
|
...opts.call ? { call: opts.call } : {},
|
|
7436
7617
|
...opts.maxSteps !== void 0 ? { maxSteps: opts.maxSteps } : {}
|
|
@@ -8190,125 +8371,6 @@ function computeEmptyRequired(view) {
|
|
|
8190
8371
|
}
|
|
8191
8372
|
return empty;
|
|
8192
8373
|
}
|
|
8193
|
-
|
|
8194
|
-
// src/flow-runtime.ts
|
|
8195
|
-
init_define_tool();
|
|
8196
|
-
function processSchemaToDefinition(schema) {
|
|
8197
|
-
const required = new Set(schema.completionGate.requiredFields);
|
|
8198
|
-
const collect = {};
|
|
8199
|
-
for (const f of schema.fields) {
|
|
8200
|
-
collect[f.name] = {
|
|
8201
|
-
type: f.type,
|
|
8202
|
-
required: required.has(f.name) || f.required,
|
|
8203
|
-
...f.ask !== void 0 ? { ask: f.ask } : {},
|
|
8204
|
-
...f.pattern !== void 0 ? { pattern: new RegExp(f.pattern) } : {},
|
|
8205
|
-
...f.min !== void 0 ? { min: f.min } : {},
|
|
8206
|
-
...f.max !== void 0 ? { max: f.max } : {},
|
|
8207
|
-
...f.enum !== void 0 ? { enum: f.enum } : {}
|
|
8208
|
-
};
|
|
8209
|
-
}
|
|
8210
|
-
return {
|
|
8211
|
-
collect,
|
|
8212
|
-
completeWhen: "all-required-captured",
|
|
8213
|
-
...schema.completionGate.backendAck !== void 0 ? { backendAck: schema.completionGate.backendAck } : {}
|
|
8214
|
-
};
|
|
8215
|
-
}
|
|
8216
|
-
var DEFAULT_FLOW_PROMPT = "You are a helpful voice assistant. Keep replies short and natural.";
|
|
8217
|
-
function toTriggerCondition(on) {
|
|
8218
|
-
return on.startsWith("signal:") ? on : new RegExp(on, "i");
|
|
8219
|
-
}
|
|
8220
|
-
function toTriggerAction(then, graphNodeIds) {
|
|
8221
|
-
if (then === "endCall" || then === "end") return "endCall";
|
|
8222
|
-
if (then === "handoff") return "handoff";
|
|
8223
|
-
if (then.startsWith("say:")) return { say: then.slice(4).trim() };
|
|
8224
|
-
if (graphNodeIds?.has(then)) return { goto: then };
|
|
8225
|
-
return "handoff";
|
|
8226
|
-
}
|
|
8227
|
-
function processSchemaToAgentParts(schema, opts = {}) {
|
|
8228
|
-
const process2 = processSchemaToDefinition(schema);
|
|
8229
|
-
const promptParts = [];
|
|
8230
|
-
if (opts.basePrompt && opts.basePrompt.trim()) promptParts.push(opts.basePrompt.trim());
|
|
8231
|
-
for (const p of schema.prompts ?? []) {
|
|
8232
|
-
if (p.text.trim()) promptParts.push(p.text.trim());
|
|
8233
|
-
}
|
|
8234
|
-
const prompt = promptParts.length > 0 ? promptParts.join("\n\n") : DEFAULT_FLOW_PROMPT;
|
|
8235
|
-
let triggers;
|
|
8236
|
-
if (schema.triggers && schema.triggers.length > 0) {
|
|
8237
|
-
triggers = {};
|
|
8238
|
-
for (const t of schema.triggers) {
|
|
8239
|
-
triggers[t.name] = {
|
|
8240
|
-
on: toTriggerCondition(t.on),
|
|
8241
|
-
then: toTriggerAction(t.then, opts.graphNodeIds),
|
|
8242
|
-
...t.onlyWhile ? { onlyWhile: t.onlyWhile } : {}
|
|
8243
|
-
};
|
|
8244
|
-
}
|
|
8245
|
-
}
|
|
8246
|
-
const handoff = schema.handoff?.fallback ? {
|
|
8247
|
-
fallback: schema.handoff.fallback,
|
|
8248
|
-
...schema.handoff.routes ? { routes: schema.handoff.routes } : {}
|
|
8249
|
-
} : void 0;
|
|
8250
|
-
const memory = schema.memory ? {
|
|
8251
|
-
...schema.memory.scope ? { scope: schema.memory.scope } : {},
|
|
8252
|
-
...schema.memory.retentionDays !== void 0 ? { retentionDays: schema.memory.retentionDays } : {},
|
|
8253
|
-
...schema.memory.piiFields ? { piiFields: schema.memory.piiFields } : {}
|
|
8254
|
-
} : void 0;
|
|
8255
|
-
let tools;
|
|
8256
|
-
if (schema.tools && schema.tools.length > 0) {
|
|
8257
|
-
tools = {};
|
|
8258
|
-
for (const t of schema.tools) {
|
|
8259
|
-
if (t.auth === "connection") {
|
|
8260
|
-
tools[t.name] = {
|
|
8261
|
-
description: t.description,
|
|
8262
|
-
input: t.input,
|
|
8263
|
-
run: () => ({
|
|
8264
|
-
kind: "unavailable",
|
|
8265
|
-
reason: "connection-auth tools need the vault resolver (not wired yet)"
|
|
8266
|
-
})
|
|
8267
|
-
};
|
|
8268
|
-
continue;
|
|
8269
|
-
}
|
|
8270
|
-
Object.assign(
|
|
8271
|
-
tools,
|
|
8272
|
-
httpTool({
|
|
8273
|
-
name: t.name,
|
|
8274
|
-
description: t.description,
|
|
8275
|
-
input: t.input,
|
|
8276
|
-
url: t.url,
|
|
8277
|
-
method: t.method,
|
|
8278
|
-
...t.headers ? { headers: t.headers } : {}
|
|
8279
|
-
})
|
|
8280
|
-
);
|
|
8281
|
-
}
|
|
8282
|
-
}
|
|
8283
|
-
let speech;
|
|
8284
|
-
if (schema.speech) {
|
|
8285
|
-
const i = schema.speech.interruption;
|
|
8286
|
-
const e = schema.speech.endpointing;
|
|
8287
|
-
const interruption = i ? {
|
|
8288
|
-
...i.enabled !== void 0 ? { enabled: i.enabled } : {},
|
|
8289
|
-
...i.minWords !== void 0 ? { minWords: i.minWords } : {},
|
|
8290
|
-
...i.minDuration !== void 0 ? { minDuration: i.minDuration } : {}
|
|
8291
|
-
} : void 0;
|
|
8292
|
-
const endpointing = e ? {
|
|
8293
|
-
...e.minDelay !== void 0 ? { minDelay: e.minDelay } : {},
|
|
8294
|
-
...e.maxDelay !== void 0 ? { maxDelay: e.maxDelay } : {}
|
|
8295
|
-
} : void 0;
|
|
8296
|
-
speech = {
|
|
8297
|
-
...interruption && Object.keys(interruption).length ? { interruption } : {},
|
|
8298
|
-
...endpointing && Object.keys(endpointing).length ? { endpointing } : {}
|
|
8299
|
-
};
|
|
8300
|
-
if (Object.keys(speech).length === 0) speech = void 0;
|
|
8301
|
-
}
|
|
8302
|
-
return {
|
|
8303
|
-
prompt,
|
|
8304
|
-
process: process2,
|
|
8305
|
-
...triggers ? { triggers } : {},
|
|
8306
|
-
...handoff ? { handoff } : {},
|
|
8307
|
-
...memory ? { memory } : {},
|
|
8308
|
-
...tools ? { tools } : {},
|
|
8309
|
-
...speech ? { speech } : {}
|
|
8310
|
-
};
|
|
8311
|
-
}
|
|
8312
8374
|
var BrainConfigError = class extends Error {
|
|
8313
8375
|
constructor(message) {
|
|
8314
8376
|
super(message);
|
|
@@ -10987,7 +11049,7 @@ async function executeHandoff(args, config, deps) {
|
|
|
10987
11049
|
});
|
|
10988
11050
|
}
|
|
10989
11051
|
}
|
|
10990
|
-
if (sipOps) {
|
|
11052
|
+
if (sipOps && isSipParticipant(deps.callerIdentity)) {
|
|
10991
11053
|
if (mode === "warm") {
|
|
10992
11054
|
await sayFixed(deps, "I'm transferring you now \u2014 one moment.");
|
|
10993
11055
|
}
|
|
@@ -11003,6 +11065,19 @@ async function executeHandoff(args, config, deps) {
|
|
|
11003
11065
|
error: err instanceof Error ? err.message : String(err)
|
|
11004
11066
|
});
|
|
11005
11067
|
}
|
|
11068
|
+
} else if (sipOps) {
|
|
11069
|
+
console.warn("[handoff] caller has no SIP leg; cannot transfer this channel", {
|
|
11070
|
+
callerIdentity: deps.callerIdentity,
|
|
11071
|
+
conferenceAvailable: sipOps.canConference
|
|
11072
|
+
});
|
|
11073
|
+
notify("handoff.unavailable", {
|
|
11074
|
+
to: args.to,
|
|
11075
|
+
reason: sipOps.canConference ? "caller has no SIP leg (web/playground call)" : "caller has no SIP leg and no outbound trunk is configured for conferencing"
|
|
11076
|
+
});
|
|
11077
|
+
await sayFixed(
|
|
11078
|
+
deps,
|
|
11079
|
+
"I'm not able to connect you to a person on this channel \u2014 please call our phone line and we'll pick up right where we left off."
|
|
11080
|
+
);
|
|
11006
11081
|
}
|
|
11007
11082
|
try {
|
|
11008
11083
|
await deps.disconnect();
|
|
@@ -11052,6 +11127,9 @@ function buildDefaultSipOps() {
|
|
|
11052
11127
|
}
|
|
11053
11128
|
};
|
|
11054
11129
|
}
|
|
11130
|
+
function isSipParticipant(identity) {
|
|
11131
|
+
return !/^(user[-_]|web[-_]|playground[-_]|vl-client)/i.test(identity.trim());
|
|
11132
|
+
}
|
|
11055
11133
|
function normalizeSipTarget(target) {
|
|
11056
11134
|
if (target.startsWith("sip:") || target.startsWith("tel:")) return target;
|
|
11057
11135
|
return `tel:${target}`;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { aa as GraphTraceEvent, u as RunTextSessionOptions, v as RunTextTranscriptOptions, V as TextSession, W as TextTranscriptResult, a7 as runTextSession, a8 as runTextTranscript } from '../text-session-D1j8nQac.js';
|
|
2
2
|
import '@livekit/agents';
|
|
3
3
|
import 'zod';
|