@absolutejs/voice 0.0.22-beta.1 → 0.0.22-beta.11
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 +82 -0
- package/dist/assistant.d.ts +143 -0
- package/dist/assistantMemory.d.ts +63 -0
- package/dist/fileStore.d.ts +5 -2
- package/dist/index.d.ts +7 -1
- package/dist/index.js +1455 -228
- package/dist/modelAdapters.d.ts +60 -0
- package/dist/trace.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5150,6 +5150,17 @@ var createVoiceAgent = (options) => {
|
|
|
5150
5150
|
if (output.assistantText?.trim()) {
|
|
5151
5151
|
messages.push({
|
|
5152
5152
|
content: output.assistantText,
|
|
5153
|
+
metadata: output.toolCalls?.length ? {
|
|
5154
|
+
toolCalls: output.toolCalls
|
|
5155
|
+
} : undefined,
|
|
5156
|
+
role: "assistant"
|
|
5157
|
+
});
|
|
5158
|
+
} else if (output.toolCalls?.length) {
|
|
5159
|
+
messages.push({
|
|
5160
|
+
content: "",
|
|
5161
|
+
metadata: {
|
|
5162
|
+
toolCalls: output.toolCalls
|
|
5163
|
+
},
|
|
5153
5164
|
role: "assistant"
|
|
5154
5165
|
});
|
|
5155
5166
|
}
|
|
@@ -5364,8 +5375,730 @@ var createVoiceAgentSquad = (options) => {
|
|
|
5364
5375
|
};
|
|
5365
5376
|
return {
|
|
5366
5377
|
id: options.id,
|
|
5367
|
-
onTurn: async (input) => run(input),
|
|
5368
|
-
run
|
|
5378
|
+
onTurn: async (input) => run(input),
|
|
5379
|
+
run
|
|
5380
|
+
};
|
|
5381
|
+
};
|
|
5382
|
+
|
|
5383
|
+
// src/outcomeRecipes.ts
|
|
5384
|
+
var RECIPE_DEFAULTS = {
|
|
5385
|
+
"appointment-booking": {
|
|
5386
|
+
completedAction: "Verify appointment details, confirm calendar state, and send any required confirmation.",
|
|
5387
|
+
completedDescription: "The call completed an appointment-booking flow and should be checked against the scheduling system.",
|
|
5388
|
+
completedKind: "appointment-booking",
|
|
5389
|
+
completedTitle: "Confirm booked appointment",
|
|
5390
|
+
defaultCompletedCreatesTask: true,
|
|
5391
|
+
defaultDueInMs: 30 * 60000,
|
|
5392
|
+
defaultPriority: "normal",
|
|
5393
|
+
defaultQueue: "appointments",
|
|
5394
|
+
description: "Creates appointment confirmation work for completed calls and callback/retry work for missed booking attempts.",
|
|
5395
|
+
escalationQueue: "appointments-escalations"
|
|
5396
|
+
},
|
|
5397
|
+
"lead-qualification": {
|
|
5398
|
+
completedAction: "Review qualification signals, update CRM fields, and route the lead to the right owner.",
|
|
5399
|
+
completedDescription: "The call completed a lead-qualification flow and should be reviewed for sales follow-up.",
|
|
5400
|
+
completedKind: "lead-qualification",
|
|
5401
|
+
completedTitle: "Review qualified lead",
|
|
5402
|
+
defaultCompletedCreatesTask: true,
|
|
5403
|
+
defaultDueInMs: 15 * 60000,
|
|
5404
|
+
defaultPriority: "high",
|
|
5405
|
+
defaultQueue: "sales-leads",
|
|
5406
|
+
description: "Creates sales follow-up work for completed qualification calls and fast callbacks for missed leads.",
|
|
5407
|
+
escalationQueue: "sales-escalations"
|
|
5408
|
+
},
|
|
5409
|
+
"support-triage": {
|
|
5410
|
+
completedAction: "Review the triage result, confirm the support category, and route any unresolved issue.",
|
|
5411
|
+
completedDescription: "The call completed support triage and may need queue routing or human follow-up.",
|
|
5412
|
+
completedKind: "support-triage",
|
|
5413
|
+
completedTitle: "Review support triage",
|
|
5414
|
+
defaultCompletedCreatesTask: true,
|
|
5415
|
+
defaultDueInMs: 20 * 60000,
|
|
5416
|
+
defaultPriority: "normal",
|
|
5417
|
+
defaultQueue: "support-triage",
|
|
5418
|
+
description: "Creates support triage work for completed calls and urgent escalation/callback work for unresolved callers.",
|
|
5419
|
+
escalationQueue: "support-escalations"
|
|
5420
|
+
},
|
|
5421
|
+
"voicemail-callback": {
|
|
5422
|
+
completedAction: "No callback is required for completed calls.",
|
|
5423
|
+
completedDescription: "The call completed without requiring voicemail follow-up.",
|
|
5424
|
+
completedKind: "callback",
|
|
5425
|
+
completedTitle: "Completed call",
|
|
5426
|
+
defaultCompletedCreatesTask: false,
|
|
5427
|
+
defaultDueInMs: 15 * 60000,
|
|
5428
|
+
defaultPriority: "high",
|
|
5429
|
+
defaultQueue: "callbacks",
|
|
5430
|
+
description: "Creates callback work for voicemail, no-answer, failed, or escalated calls while ignoring completed calls.",
|
|
5431
|
+
escalationQueue: "callback-escalations"
|
|
5432
|
+
},
|
|
5433
|
+
"warm-transfer": {
|
|
5434
|
+
completedAction: "Confirm the handoff target received the caller context and close the transfer loop.",
|
|
5435
|
+
completedDescription: "The call is part of a warm-transfer flow and should be verified downstream.",
|
|
5436
|
+
completedKind: "transfer-check",
|
|
5437
|
+
completedTitle: "Verify warm transfer",
|
|
5438
|
+
defaultCompletedCreatesTask: false,
|
|
5439
|
+
defaultDueInMs: 10 * 60000,
|
|
5440
|
+
defaultPriority: "normal",
|
|
5441
|
+
defaultQueue: "transfer-verification",
|
|
5442
|
+
description: "Creates transfer verification work for transferred calls and escalation work when the handoff fails.",
|
|
5443
|
+
escalationQueue: "transfer-escalations"
|
|
5444
|
+
}
|
|
5445
|
+
};
|
|
5446
|
+
var buildRecipeTask = (input) => {
|
|
5447
|
+
const createdAt = input.review.generatedAt ?? Date.now();
|
|
5448
|
+
const queue = input.options.queue ?? input.defaults.defaultQueue;
|
|
5449
|
+
const target = input.options.target ?? input.review.postCall?.target;
|
|
5450
|
+
const common = {
|
|
5451
|
+
assignee: input.options.assignee,
|
|
5452
|
+
createdAt,
|
|
5453
|
+
history: [
|
|
5454
|
+
{
|
|
5455
|
+
actor: "system",
|
|
5456
|
+
at: createdAt,
|
|
5457
|
+
detail: input.review.postCall?.summary,
|
|
5458
|
+
type: "created"
|
|
5459
|
+
}
|
|
5460
|
+
],
|
|
5461
|
+
id: `${input.review.id}:${input.defaults.completedKind}`,
|
|
5462
|
+
intakeId: input.review.id,
|
|
5463
|
+
outcome: input.review.summary.outcome,
|
|
5464
|
+
priority: input.options.priority ?? input.defaults.defaultPriority,
|
|
5465
|
+
queue,
|
|
5466
|
+
reviewId: input.review.id,
|
|
5467
|
+
status: "open",
|
|
5468
|
+
target,
|
|
5469
|
+
updatedAt: createdAt
|
|
5470
|
+
};
|
|
5471
|
+
switch (input.disposition) {
|
|
5472
|
+
case "completed":
|
|
5473
|
+
if (!(input.options.completedCreatesTask ?? input.defaults.defaultCompletedCreatesTask)) {
|
|
5474
|
+
return null;
|
|
5475
|
+
}
|
|
5476
|
+
return {
|
|
5477
|
+
...common,
|
|
5478
|
+
description: input.defaults.completedDescription,
|
|
5479
|
+
kind: input.defaults.completedKind,
|
|
5480
|
+
recommendedAction: input.defaults.completedAction,
|
|
5481
|
+
title: target ? `${input.defaults.completedTitle}: ${target}` : input.defaults.completedTitle
|
|
5482
|
+
};
|
|
5483
|
+
case "voicemail":
|
|
5484
|
+
return {
|
|
5485
|
+
...common,
|
|
5486
|
+
description: input.review.postCall?.summary ?? "The caller reached voicemail and needs a callback.",
|
|
5487
|
+
id: `${input.review.id}:callback`,
|
|
5488
|
+
kind: "callback",
|
|
5489
|
+
recommendedAction: input.review.postCall?.recommendedAction ?? "Call the customer back and continue the original flow.",
|
|
5490
|
+
title: target ? `Call back ${target}` : "Call back voicemail lead"
|
|
5491
|
+
};
|
|
5492
|
+
case "no-answer":
|
|
5493
|
+
return {
|
|
5494
|
+
...common,
|
|
5495
|
+
description: input.review.postCall?.summary ?? "The call did not reach a live respondent and should be retried.",
|
|
5496
|
+
id: `${input.review.id}:retry`,
|
|
5497
|
+
kind: "callback",
|
|
5498
|
+
recommendedAction: input.review.postCall?.recommendedAction ?? "Retry the call or schedule a callback.",
|
|
5499
|
+
title: "Retry no-answer call"
|
|
5500
|
+
};
|
|
5501
|
+
case "transferred":
|
|
5502
|
+
return {
|
|
5503
|
+
...common,
|
|
5504
|
+
description: input.review.postCall?.summary ?? "The call was transferred and should be verified downstream.",
|
|
5505
|
+
id: `${input.review.id}:transfer-check`,
|
|
5506
|
+
kind: "transfer-check",
|
|
5507
|
+
recommendedAction: input.review.postCall?.recommendedAction ?? "Confirm the receiving team got the caller context.",
|
|
5508
|
+
title: target ? `Verify transfer to ${target}` : "Verify call transfer"
|
|
5509
|
+
};
|
|
5510
|
+
case "escalated":
|
|
5511
|
+
return {
|
|
5512
|
+
...common,
|
|
5513
|
+
description: input.review.postCall?.summary ?? "The call escalated and needs human review.",
|
|
5514
|
+
id: `${input.review.id}:escalation`,
|
|
5515
|
+
kind: "escalation",
|
|
5516
|
+
priority: "urgent",
|
|
5517
|
+
queue: input.options.escalationQueue ?? input.defaults.escalationQueue,
|
|
5518
|
+
assignee: input.options.escalationAssignee ?? input.options.assignee,
|
|
5519
|
+
recommendedAction: input.review.postCall?.recommendedAction ?? "Review the escalated call and respond immediately.",
|
|
5520
|
+
title: "Review escalated call"
|
|
5521
|
+
};
|
|
5522
|
+
case "failed":
|
|
5523
|
+
case "closed":
|
|
5524
|
+
return {
|
|
5525
|
+
...common,
|
|
5526
|
+
description: input.review.postCall?.summary ?? "The call ended before successful completion and needs review.",
|
|
5527
|
+
id: `${input.review.id}:retry-review`,
|
|
5528
|
+
kind: "retry-review",
|
|
5529
|
+
priority: "high",
|
|
5530
|
+
recommendedAction: input.review.postCall?.recommendedAction ?? "Inspect the call and decide whether to retry, escalate, or close.",
|
|
5531
|
+
title: "Inspect incomplete call"
|
|
5532
|
+
};
|
|
5533
|
+
default:
|
|
5534
|
+
return null;
|
|
5535
|
+
}
|
|
5536
|
+
};
|
|
5537
|
+
var resolveVoiceOutcomeRecipe = (name, options = {}) => {
|
|
5538
|
+
const defaults = RECIPE_DEFAULTS[name];
|
|
5539
|
+
const taskPolicies = {
|
|
5540
|
+
completed: {
|
|
5541
|
+
assignee: options.assignee,
|
|
5542
|
+
dueInMs: options.dueInMs ?? defaults.defaultDueInMs,
|
|
5543
|
+
name: `${name}-completed`,
|
|
5544
|
+
priority: options.priority ?? defaults.defaultPriority,
|
|
5545
|
+
queue: options.queue ?? defaults.defaultQueue
|
|
5546
|
+
},
|
|
5547
|
+
escalated: {
|
|
5548
|
+
assignee: options.escalationAssignee ?? options.assignee,
|
|
5549
|
+
dueInMs: Math.min(options.dueInMs ?? defaults.defaultDueInMs, 10 * 60000),
|
|
5550
|
+
name: `${name}-escalation`,
|
|
5551
|
+
priority: "urgent",
|
|
5552
|
+
queue: options.escalationQueue ?? defaults.escalationQueue
|
|
5553
|
+
},
|
|
5554
|
+
failed: {
|
|
5555
|
+
assignee: options.assignee,
|
|
5556
|
+
dueInMs: options.dueInMs ?? defaults.defaultDueInMs,
|
|
5557
|
+
name: `${name}-failed-review`,
|
|
5558
|
+
priority: "high",
|
|
5559
|
+
queue: options.queue ?? defaults.defaultQueue
|
|
5560
|
+
},
|
|
5561
|
+
"no-answer": {
|
|
5562
|
+
assignee: options.assignee,
|
|
5563
|
+
dueInMs: options.dueInMs ?? defaults.defaultDueInMs,
|
|
5564
|
+
name: `${name}-no-answer`,
|
|
5565
|
+
priority: options.priority ?? defaults.defaultPriority,
|
|
5566
|
+
queue: options.queue ?? defaults.defaultQueue
|
|
5567
|
+
},
|
|
5568
|
+
transferred: {
|
|
5569
|
+
assignee: options.assignee,
|
|
5570
|
+
dueInMs: Math.min(options.dueInMs ?? defaults.defaultDueInMs, 20 * 60000),
|
|
5571
|
+
name: `${name}-transfer-check`,
|
|
5572
|
+
priority: options.priority ?? defaults.defaultPriority,
|
|
5573
|
+
queue: name === "warm-transfer" ? options.queue ?? defaults.defaultQueue : "transfer-verification"
|
|
5574
|
+
},
|
|
5575
|
+
voicemail: {
|
|
5576
|
+
assignee: options.assignee,
|
|
5577
|
+
dueInMs: options.dueInMs ?? defaults.defaultDueInMs,
|
|
5578
|
+
name: `${name}-voicemail`,
|
|
5579
|
+
priority: options.priority ?? defaults.defaultPriority,
|
|
5580
|
+
queue: options.queue ?? defaults.defaultQueue
|
|
5581
|
+
}
|
|
5582
|
+
};
|
|
5583
|
+
const taskAssignmentRules = [
|
|
5584
|
+
{
|
|
5585
|
+
assign: options.escalationAssignee ?? options.assignee,
|
|
5586
|
+
description: `Route urgent ${name} work to the escalation lane.`,
|
|
5587
|
+
name: `${name}-urgent-routing`,
|
|
5588
|
+
queue: options.escalationQueue ?? defaults.escalationQueue,
|
|
5589
|
+
when: {
|
|
5590
|
+
priority: "urgent"
|
|
5591
|
+
}
|
|
5592
|
+
}
|
|
5593
|
+
].filter((rule) => rule.assign || rule.queue);
|
|
5594
|
+
return {
|
|
5595
|
+
createTaskFromReview: ({ disposition, review }) => buildRecipeTask({
|
|
5596
|
+
defaults,
|
|
5597
|
+
disposition,
|
|
5598
|
+
options,
|
|
5599
|
+
review
|
|
5600
|
+
}),
|
|
5601
|
+
description: defaults.description,
|
|
5602
|
+
name,
|
|
5603
|
+
taskAssignmentRules,
|
|
5604
|
+
taskPolicies
|
|
5605
|
+
};
|
|
5606
|
+
};
|
|
5607
|
+
|
|
5608
|
+
// src/assistantMemory.ts
|
|
5609
|
+
var createMemoryId = (input) => `${input.assistantId}:${input.namespace}:${input.key}`;
|
|
5610
|
+
var createVoiceAssistantMemoryRecord = (input) => {
|
|
5611
|
+
const now = Date.now();
|
|
5612
|
+
return {
|
|
5613
|
+
...input,
|
|
5614
|
+
createdAt: input.createdAt ?? input.updatedAt ?? now,
|
|
5615
|
+
updatedAt: input.updatedAt ?? now
|
|
5616
|
+
};
|
|
5617
|
+
};
|
|
5618
|
+
var createVoiceMemoryAssistantMemoryStore = () => {
|
|
5619
|
+
const records = new Map;
|
|
5620
|
+
return {
|
|
5621
|
+
delete: async (input) => {
|
|
5622
|
+
records.delete(createMemoryId(input));
|
|
5623
|
+
},
|
|
5624
|
+
get: async (input) => records.get(createMemoryId(input)),
|
|
5625
|
+
list: async (input) => [...records.values()].filter((record) => record.assistantId === input.assistantId && (input.namespace === undefined || record.namespace === input.namespace)).sort((left, right) => right.updatedAt - left.updatedAt),
|
|
5626
|
+
set: async (input) => {
|
|
5627
|
+
const id = createMemoryId(input);
|
|
5628
|
+
const existing = records.get(id);
|
|
5629
|
+
const record = createVoiceAssistantMemoryRecord({
|
|
5630
|
+
...input,
|
|
5631
|
+
createdAt: input.createdAt ?? existing?.createdAt,
|
|
5632
|
+
updatedAt: input.updatedAt
|
|
5633
|
+
});
|
|
5634
|
+
records.set(id, record);
|
|
5635
|
+
return record;
|
|
5636
|
+
}
|
|
5637
|
+
};
|
|
5638
|
+
};
|
|
5639
|
+
var resolveVoiceAssistantMemoryNamespace = async (input) => typeof input.memory.namespace === "function" ? await input.memory.namespace(input) : input.memory.namespace;
|
|
5640
|
+
var createVoiceAssistantMemoryHandle = async (input) => {
|
|
5641
|
+
const namespace = await resolveVoiceAssistantMemoryNamespace({
|
|
5642
|
+
assistantId: input.assistantId,
|
|
5643
|
+
context: input.context,
|
|
5644
|
+
memory: input.memory,
|
|
5645
|
+
session: input.session
|
|
5646
|
+
});
|
|
5647
|
+
const trace = async (event) => {
|
|
5648
|
+
await input.trace?.append({
|
|
5649
|
+
at: Date.now(),
|
|
5650
|
+
payload: {
|
|
5651
|
+
assistantId: input.assistantId,
|
|
5652
|
+
namespace,
|
|
5653
|
+
...event
|
|
5654
|
+
},
|
|
5655
|
+
scenarioId: input.session.scenarioId,
|
|
5656
|
+
sessionId: input.session.id,
|
|
5657
|
+
type: "assistant.memory"
|
|
5658
|
+
});
|
|
5659
|
+
};
|
|
5660
|
+
return {
|
|
5661
|
+
delete: async (key) => {
|
|
5662
|
+
await input.memory.store.delete({
|
|
5663
|
+
assistantId: input.assistantId,
|
|
5664
|
+
key,
|
|
5665
|
+
namespace
|
|
5666
|
+
});
|
|
5667
|
+
await trace({
|
|
5668
|
+
action: "delete",
|
|
5669
|
+
key
|
|
5670
|
+
});
|
|
5671
|
+
},
|
|
5672
|
+
get: async (key) => {
|
|
5673
|
+
const record = await input.memory.store.get({
|
|
5674
|
+
assistantId: input.assistantId,
|
|
5675
|
+
key,
|
|
5676
|
+
namespace
|
|
5677
|
+
});
|
|
5678
|
+
await trace({
|
|
5679
|
+
action: "get",
|
|
5680
|
+
found: Boolean(record),
|
|
5681
|
+
key
|
|
5682
|
+
});
|
|
5683
|
+
return record?.value;
|
|
5684
|
+
},
|
|
5685
|
+
list: async () => {
|
|
5686
|
+
const records = await input.memory.store.list({
|
|
5687
|
+
assistantId: input.assistantId,
|
|
5688
|
+
namespace
|
|
5689
|
+
});
|
|
5690
|
+
await trace({
|
|
5691
|
+
action: "list",
|
|
5692
|
+
count: records.length
|
|
5693
|
+
});
|
|
5694
|
+
return records;
|
|
5695
|
+
},
|
|
5696
|
+
namespace,
|
|
5697
|
+
set: async (key, value, metadata) => {
|
|
5698
|
+
const record = await input.memory.store.set({
|
|
5699
|
+
assistantId: input.assistantId,
|
|
5700
|
+
key,
|
|
5701
|
+
metadata,
|
|
5702
|
+
namespace,
|
|
5703
|
+
value
|
|
5704
|
+
});
|
|
5705
|
+
await trace({
|
|
5706
|
+
action: "set",
|
|
5707
|
+
key
|
|
5708
|
+
});
|
|
5709
|
+
return record;
|
|
5710
|
+
}
|
|
5711
|
+
};
|
|
5712
|
+
};
|
|
5713
|
+
|
|
5714
|
+
// src/assistant.ts
|
|
5715
|
+
var hashString = (value) => {
|
|
5716
|
+
let hash = 2166136261;
|
|
5717
|
+
for (let index = 0;index < value.length; index += 1) {
|
|
5718
|
+
hash ^= value.charCodeAt(index);
|
|
5719
|
+
hash = Math.imul(hash, 16777619);
|
|
5720
|
+
}
|
|
5721
|
+
return hash >>> 0;
|
|
5722
|
+
};
|
|
5723
|
+
var increment = (record, key) => {
|
|
5724
|
+
record[key] = (record[key] ?? 0) + 1;
|
|
5725
|
+
};
|
|
5726
|
+
var resolveOutcome = (result) => {
|
|
5727
|
+
if (result.transfer) {
|
|
5728
|
+
return "transferred";
|
|
5729
|
+
}
|
|
5730
|
+
if (result.escalate) {
|
|
5731
|
+
return "escalated";
|
|
5732
|
+
}
|
|
5733
|
+
if (result.voicemail) {
|
|
5734
|
+
return "voicemail";
|
|
5735
|
+
}
|
|
5736
|
+
if (result.noAnswer) {
|
|
5737
|
+
return "no-answer";
|
|
5738
|
+
}
|
|
5739
|
+
if (result.complete) {
|
|
5740
|
+
return "completed";
|
|
5741
|
+
}
|
|
5742
|
+
return "continued";
|
|
5743
|
+
};
|
|
5744
|
+
var resolveArtifactPlanName = (artifactPlan) => {
|
|
5745
|
+
const preset = artifactPlan?.preset;
|
|
5746
|
+
if (!preset) {
|
|
5747
|
+
return artifactPlan?.ops ? "custom" : undefined;
|
|
5748
|
+
}
|
|
5749
|
+
return typeof preset === "string" ? preset : preset.name;
|
|
5750
|
+
};
|
|
5751
|
+
var appendAssistantTrace = async (input) => {
|
|
5752
|
+
await input.trace?.append({
|
|
5753
|
+
at: Date.now(),
|
|
5754
|
+
payload: {
|
|
5755
|
+
assistantId: input.assistantId,
|
|
5756
|
+
...input.event
|
|
5757
|
+
},
|
|
5758
|
+
scenarioId: input.session.scenarioId,
|
|
5759
|
+
sessionId: input.session.id,
|
|
5760
|
+
turnId: input.turnId,
|
|
5761
|
+
type: input.type
|
|
5762
|
+
});
|
|
5763
|
+
};
|
|
5764
|
+
var resolvePresetOps = (artifactPlan) => {
|
|
5765
|
+
const preset = artifactPlan?.preset;
|
|
5766
|
+
if (!preset) {
|
|
5767
|
+
return artifactPlan?.ops;
|
|
5768
|
+
}
|
|
5769
|
+
const recipe = typeof preset === "string" ? resolveVoiceOutcomeRecipe(preset) : resolveVoiceOutcomeRecipe(preset.name, preset.options);
|
|
5770
|
+
return {
|
|
5771
|
+
...recipe,
|
|
5772
|
+
...artifactPlan?.ops
|
|
5773
|
+
};
|
|
5774
|
+
};
|
|
5775
|
+
var mergeOps = (base, override) => {
|
|
5776
|
+
if (!base && !override) {
|
|
5777
|
+
return;
|
|
5778
|
+
}
|
|
5779
|
+
return {
|
|
5780
|
+
...base,
|
|
5781
|
+
...override,
|
|
5782
|
+
taskAssignmentRules: base?.taskAssignmentRules || override?.taskAssignmentRules ? [
|
|
5783
|
+
...base?.taskAssignmentRules ?? [],
|
|
5784
|
+
...override?.taskAssignmentRules ?? []
|
|
5785
|
+
] : undefined,
|
|
5786
|
+
taskPolicies: base?.taskPolicies || override?.taskPolicies ? {
|
|
5787
|
+
...base?.taskPolicies ?? {},
|
|
5788
|
+
...override?.taskPolicies ?? {}
|
|
5789
|
+
} : undefined
|
|
5790
|
+
};
|
|
5791
|
+
};
|
|
5792
|
+
var createVoiceExperiment = (options) => {
|
|
5793
|
+
if (!options.variants.length) {
|
|
5794
|
+
throw new Error("createVoiceExperiment requires at least one variant.");
|
|
5795
|
+
}
|
|
5796
|
+
const firstVariant = options.variants[0];
|
|
5797
|
+
return {
|
|
5798
|
+
id: options.id,
|
|
5799
|
+
resolve: (input) => {
|
|
5800
|
+
const selected = options.selectVariant?.({
|
|
5801
|
+
...input,
|
|
5802
|
+
variants: options.variants
|
|
5803
|
+
});
|
|
5804
|
+
if (selected && typeof selected !== "object") {
|
|
5805
|
+
const variant = options.variants.find((item) => item.id === selected);
|
|
5806
|
+
if (variant) {
|
|
5807
|
+
return variant;
|
|
5808
|
+
}
|
|
5809
|
+
}
|
|
5810
|
+
if (selected && typeof selected === "object" && "id" in selected) {
|
|
5811
|
+
return selected;
|
|
5812
|
+
}
|
|
5813
|
+
const totalWeight = options.variants.reduce((total, variant) => total + Math.max(0, variant.weight ?? 1), 0);
|
|
5814
|
+
if (totalWeight <= 0) {
|
|
5815
|
+
return firstVariant;
|
|
5816
|
+
}
|
|
5817
|
+
const bucket = hashString(`${options.id}:${input.assistantId}:${input.session.id}`) % totalWeight;
|
|
5818
|
+
let cursor = 0;
|
|
5819
|
+
for (const variant of options.variants) {
|
|
5820
|
+
cursor += Math.max(0, variant.weight ?? 1);
|
|
5821
|
+
if (bucket < cursor) {
|
|
5822
|
+
return variant;
|
|
5823
|
+
}
|
|
5824
|
+
}
|
|
5825
|
+
return firstVariant;
|
|
5826
|
+
},
|
|
5827
|
+
variants: options.variants
|
|
5828
|
+
};
|
|
5829
|
+
};
|
|
5830
|
+
var createVoiceAssistant = (options) => {
|
|
5831
|
+
const ops = mergeOps(resolvePresetOps(options.artifactPlan), options.ops);
|
|
5832
|
+
const artifactPlanName = resolveArtifactPlanName(options.artifactPlan);
|
|
5833
|
+
let agent;
|
|
5834
|
+
const baseModelOptions = "model" in options && options.model ? {
|
|
5835
|
+
maxToolRounds: options.maxToolRounds,
|
|
5836
|
+
model: options.model,
|
|
5837
|
+
system: options.system,
|
|
5838
|
+
tools: options.tools
|
|
5839
|
+
} : undefined;
|
|
5840
|
+
if ("agent" in options && options.agent) {
|
|
5841
|
+
agent = options.agent;
|
|
5842
|
+
} else if ("agents" in options && options.agents) {
|
|
5843
|
+
agent = createVoiceAgentSquad({
|
|
5844
|
+
agents: options.agents,
|
|
5845
|
+
defaultAgentId: options.defaultAgentId,
|
|
5846
|
+
id: options.id,
|
|
5847
|
+
maxHandoffsPerTurn: options.maxHandoffsPerTurn,
|
|
5848
|
+
selectAgent: options.selectAgent,
|
|
5849
|
+
trace: options.trace
|
|
5850
|
+
});
|
|
5851
|
+
} else {
|
|
5852
|
+
agent = createVoiceAgent({
|
|
5853
|
+
id: options.id,
|
|
5854
|
+
maxToolRounds: options.maxToolRounds,
|
|
5855
|
+
model: options.model,
|
|
5856
|
+
system: options.system,
|
|
5857
|
+
trace: options.trace,
|
|
5858
|
+
tools: options.tools
|
|
5859
|
+
});
|
|
5860
|
+
}
|
|
5861
|
+
const onTurn = async (input) => {
|
|
5862
|
+
const memory = options.memory ? await createVoiceAssistantMemoryHandle({
|
|
5863
|
+
assistantId: options.id,
|
|
5864
|
+
context: input.context,
|
|
5865
|
+
memory: options.memory,
|
|
5866
|
+
session: input.session,
|
|
5867
|
+
trace: options.trace
|
|
5868
|
+
}) : undefined;
|
|
5869
|
+
const guardrailInput = {
|
|
5870
|
+
...input,
|
|
5871
|
+
assistantId: options.id,
|
|
5872
|
+
memory
|
|
5873
|
+
};
|
|
5874
|
+
if (memory) {
|
|
5875
|
+
await options.memoryLifecycle?.beforeTurn?.({
|
|
5876
|
+
...input,
|
|
5877
|
+
assistantId: options.id,
|
|
5878
|
+
memory
|
|
5879
|
+
});
|
|
5880
|
+
}
|
|
5881
|
+
const blocked = await options.guardrails?.beforeTurn?.(guardrailInput);
|
|
5882
|
+
if (blocked) {
|
|
5883
|
+
if (memory) {
|
|
5884
|
+
await options.memoryLifecycle?.afterTurn?.({
|
|
5885
|
+
...input,
|
|
5886
|
+
assistantId: options.id,
|
|
5887
|
+
memory,
|
|
5888
|
+
result: blocked
|
|
5889
|
+
});
|
|
5890
|
+
}
|
|
5891
|
+
await appendAssistantTrace({
|
|
5892
|
+
assistantId: options.id,
|
|
5893
|
+
event: {
|
|
5894
|
+
action: "blocked",
|
|
5895
|
+
artifactPlan: artifactPlanName,
|
|
5896
|
+
outcome: resolveOutcome(blocked)
|
|
5897
|
+
},
|
|
5898
|
+
session: input.session,
|
|
5899
|
+
trace: options.trace,
|
|
5900
|
+
turnId: input.turn.id,
|
|
5901
|
+
type: "assistant.guardrail"
|
|
5902
|
+
});
|
|
5903
|
+
await appendAssistantTrace({
|
|
5904
|
+
assistantId: options.id,
|
|
5905
|
+
event: {
|
|
5906
|
+
artifactPlan: artifactPlanName,
|
|
5907
|
+
blocked: true,
|
|
5908
|
+
experimentId: options.experiment?.id,
|
|
5909
|
+
outcome: resolveOutcome(blocked)
|
|
5910
|
+
},
|
|
5911
|
+
session: input.session,
|
|
5912
|
+
trace: options.trace,
|
|
5913
|
+
turnId: input.turn.id,
|
|
5914
|
+
type: "assistant.run"
|
|
5915
|
+
});
|
|
5916
|
+
return blocked;
|
|
5917
|
+
}
|
|
5918
|
+
const startedAt = Date.now();
|
|
5919
|
+
const variant = options.experiment?.resolve({
|
|
5920
|
+
assistantId: options.id,
|
|
5921
|
+
context: input.context,
|
|
5922
|
+
session: input.session,
|
|
5923
|
+
turnId: input.turn.id
|
|
5924
|
+
});
|
|
5925
|
+
const runner = variant && baseModelOptions ? createVoiceAgent({
|
|
5926
|
+
id: `${options.id}:${variant.id}`,
|
|
5927
|
+
maxToolRounds: variant.maxToolRounds ?? baseModelOptions.maxToolRounds,
|
|
5928
|
+
model: variant.model ?? baseModelOptions.model,
|
|
5929
|
+
system: variant.system ?? baseModelOptions.system,
|
|
5930
|
+
trace: options.trace,
|
|
5931
|
+
tools: variant.tools ?? baseModelOptions.tools
|
|
5932
|
+
}) : agent;
|
|
5933
|
+
const runResult = await runner.run(input) ?? {};
|
|
5934
|
+
const result = runResult;
|
|
5935
|
+
const guarded = await options.guardrails?.afterTurn?.({
|
|
5936
|
+
...guardrailInput,
|
|
5937
|
+
result
|
|
5938
|
+
});
|
|
5939
|
+
const finalResult = guarded ?? result;
|
|
5940
|
+
if (memory) {
|
|
5941
|
+
await options.memoryLifecycle?.afterTurn?.({
|
|
5942
|
+
...input,
|
|
5943
|
+
assistantId: options.id,
|
|
5944
|
+
memory,
|
|
5945
|
+
result: finalResult
|
|
5946
|
+
});
|
|
5947
|
+
}
|
|
5948
|
+
if (guarded) {
|
|
5949
|
+
await appendAssistantTrace({
|
|
5950
|
+
assistantId: options.id,
|
|
5951
|
+
event: {
|
|
5952
|
+
action: "rewritten",
|
|
5953
|
+
artifactPlan: artifactPlanName,
|
|
5954
|
+
experimentId: options.experiment?.id,
|
|
5955
|
+
outcome: resolveOutcome(finalResult),
|
|
5956
|
+
variantId: variant?.id
|
|
5957
|
+
},
|
|
5958
|
+
session: input.session,
|
|
5959
|
+
trace: options.trace,
|
|
5960
|
+
turnId: input.turn.id,
|
|
5961
|
+
type: "assistant.guardrail"
|
|
5962
|
+
});
|
|
5963
|
+
}
|
|
5964
|
+
await appendAssistantTrace({
|
|
5965
|
+
assistantId: options.id,
|
|
5966
|
+
event: {
|
|
5967
|
+
artifactPlan: artifactPlanName,
|
|
5968
|
+
blocked: false,
|
|
5969
|
+
elapsedMs: Date.now() - startedAt,
|
|
5970
|
+
escalated: Boolean(finalResult.escalate),
|
|
5971
|
+
experimentId: options.experiment?.id,
|
|
5972
|
+
outcome: resolveOutcome(finalResult),
|
|
5973
|
+
toolNames: result.toolResults?.map((tool) => tool.toolName) ?? [],
|
|
5974
|
+
transferred: Boolean(finalResult.transfer),
|
|
5975
|
+
variantId: variant?.id
|
|
5976
|
+
},
|
|
5977
|
+
session: input.session,
|
|
5978
|
+
trace: options.trace,
|
|
5979
|
+
turnId: input.turn.id,
|
|
5980
|
+
type: "assistant.run"
|
|
5981
|
+
});
|
|
5982
|
+
return finalResult;
|
|
5983
|
+
};
|
|
5984
|
+
return {
|
|
5985
|
+
agent,
|
|
5986
|
+
id: options.id,
|
|
5987
|
+
onTurn,
|
|
5988
|
+
ops,
|
|
5989
|
+
route: (overrides) => ({
|
|
5990
|
+
...overrides,
|
|
5991
|
+
onComplete: overrides.onComplete ?? (() => {
|
|
5992
|
+
return;
|
|
5993
|
+
}),
|
|
5994
|
+
onTurn
|
|
5995
|
+
})
|
|
5996
|
+
};
|
|
5997
|
+
};
|
|
5998
|
+
var summarizeVoiceAssistantRuns = async (input) => {
|
|
5999
|
+
const events = Array.isArray(input) ? input : input.events ?? await input.store?.list() ?? [];
|
|
6000
|
+
const assistantRuns = events.filter((event) => event.type === "assistant.run");
|
|
6001
|
+
const guardrails = events.filter((event) => event.type === "assistant.guardrail");
|
|
6002
|
+
const byAssistant = new Map;
|
|
6003
|
+
const getSummary = (assistantId) => {
|
|
6004
|
+
let summary = byAssistant.get(assistantId);
|
|
6005
|
+
if (!summary) {
|
|
6006
|
+
summary = {
|
|
6007
|
+
assistantId,
|
|
6008
|
+
artifactPlans: {},
|
|
6009
|
+
blockedGuardrailCount: 0,
|
|
6010
|
+
elapsedCount: 0,
|
|
6011
|
+
elapsedTotal: 0,
|
|
6012
|
+
escalationCount: 0,
|
|
6013
|
+
experiments: {},
|
|
6014
|
+
guardrailCount: 0,
|
|
6015
|
+
memory: {
|
|
6016
|
+
deletes: 0,
|
|
6017
|
+
gets: 0,
|
|
6018
|
+
lists: 0,
|
|
6019
|
+
sets: 0
|
|
6020
|
+
},
|
|
6021
|
+
outcomes: {},
|
|
6022
|
+
runCount: 0,
|
|
6023
|
+
sessionIds: new Set,
|
|
6024
|
+
sessions: 0,
|
|
6025
|
+
toolCalls: {},
|
|
6026
|
+
transferCount: 0,
|
|
6027
|
+
variants: {}
|
|
6028
|
+
};
|
|
6029
|
+
byAssistant.set(assistantId, summary);
|
|
6030
|
+
}
|
|
6031
|
+
return summary;
|
|
6032
|
+
};
|
|
6033
|
+
for (const event of assistantRuns) {
|
|
6034
|
+
const assistantId = typeof event.payload.assistantId === "string" ? event.payload.assistantId : "unknown";
|
|
6035
|
+
const summary = getSummary(assistantId);
|
|
6036
|
+
summary.runCount += 1;
|
|
6037
|
+
summary.sessionIds.add(event.sessionId);
|
|
6038
|
+
if (typeof event.payload.artifactPlan === "string") {
|
|
6039
|
+
increment(summary.artifactPlans, event.payload.artifactPlan);
|
|
6040
|
+
}
|
|
6041
|
+
if (typeof event.payload.experimentId === "string") {
|
|
6042
|
+
increment(summary.experiments, event.payload.experimentId);
|
|
6043
|
+
}
|
|
6044
|
+
if (typeof event.payload.variantId === "string") {
|
|
6045
|
+
increment(summary.variants, event.payload.variantId);
|
|
6046
|
+
}
|
|
6047
|
+
if (typeof event.payload.outcome === "string") {
|
|
6048
|
+
increment(summary.outcomes, event.payload.outcome);
|
|
6049
|
+
}
|
|
6050
|
+
if (event.payload.escalated === true) {
|
|
6051
|
+
summary.escalationCount += 1;
|
|
6052
|
+
}
|
|
6053
|
+
if (event.payload.transferred === true) {
|
|
6054
|
+
summary.transferCount += 1;
|
|
6055
|
+
}
|
|
6056
|
+
if (event.payload.blocked === true) {
|
|
6057
|
+
summary.blockedGuardrailCount += 1;
|
|
6058
|
+
}
|
|
6059
|
+
if (typeof event.payload.elapsedMs === "number") {
|
|
6060
|
+
summary.elapsedCount += 1;
|
|
6061
|
+
summary.elapsedTotal += event.payload.elapsedMs;
|
|
6062
|
+
}
|
|
6063
|
+
if (Array.isArray(event.payload.toolNames)) {
|
|
6064
|
+
for (const toolName of event.payload.toolNames) {
|
|
6065
|
+
if (typeof toolName === "string") {
|
|
6066
|
+
increment(summary.toolCalls, toolName);
|
|
6067
|
+
}
|
|
6068
|
+
}
|
|
6069
|
+
}
|
|
6070
|
+
}
|
|
6071
|
+
for (const event of guardrails) {
|
|
6072
|
+
const assistantId = typeof event.payload.assistantId === "string" ? event.payload.assistantId : "unknown";
|
|
6073
|
+
const summary = getSummary(assistantId);
|
|
6074
|
+
summary.guardrailCount += 1;
|
|
6075
|
+
}
|
|
6076
|
+
for (const event of events.filter((event2) => event2.type === "assistant.memory")) {
|
|
6077
|
+
const assistantId = typeof event.payload.assistantId === "string" ? event.payload.assistantId : "unknown";
|
|
6078
|
+
const summary = getSummary(assistantId);
|
|
6079
|
+
switch (event.payload.action) {
|
|
6080
|
+
case "delete":
|
|
6081
|
+
summary.memory.deletes += 1;
|
|
6082
|
+
break;
|
|
6083
|
+
case "get":
|
|
6084
|
+
summary.memory.gets += 1;
|
|
6085
|
+
break;
|
|
6086
|
+
case "list":
|
|
6087
|
+
summary.memory.lists += 1;
|
|
6088
|
+
break;
|
|
6089
|
+
case "set":
|
|
6090
|
+
summary.memory.sets += 1;
|
|
6091
|
+
break;
|
|
6092
|
+
}
|
|
6093
|
+
}
|
|
6094
|
+
const assistants = [...byAssistant.values()].map(({ elapsedCount, elapsedTotal, sessionIds, ...summary }) => ({
|
|
6095
|
+
...summary,
|
|
6096
|
+
averageElapsedMs: elapsedCount > 0 ? Math.round(elapsedTotal / elapsedCount) : undefined,
|
|
6097
|
+
sessions: sessionIds.size
|
|
6098
|
+
}));
|
|
6099
|
+
return {
|
|
6100
|
+
assistants: assistants.sort((left, right) => left.assistantId.localeCompare(right.assistantId)),
|
|
6101
|
+
totalRuns: assistantRuns.length
|
|
5369
6102
|
};
|
|
5370
6103
|
};
|
|
5371
6104
|
// src/fileStore.ts
|
|
@@ -6052,6 +6785,7 @@ var listJsonFiles = async (directory) => {
|
|
|
6052
6785
|
};
|
|
6053
6786
|
var encodeStoreId = (id) => `${encodeURIComponent(id)}.json`;
|
|
6054
6787
|
var resolveFilePath = (directory, id) => join(directory, encodeStoreId(id));
|
|
6788
|
+
var createMemoryStoreId = (input) => `${input.assistantId}:${input.namespace}:${input.key}`;
|
|
6055
6789
|
var readJsonFile = async (path) => JSON.parse(await readFile(path, "utf8"));
|
|
6056
6790
|
var writeJsonFile = async (path, value, options) => {
|
|
6057
6791
|
await mkdir(options.directory, {
|
|
@@ -6271,6 +7005,40 @@ var createVoiceFileTraceSinkDeliveryStore = (options) => {
|
|
|
6271
7005
|
};
|
|
6272
7006
|
return { get, list, remove, set };
|
|
6273
7007
|
};
|
|
7008
|
+
var createVoiceFileAssistantMemoryStore = (options) => {
|
|
7009
|
+
const get = async (input) => {
|
|
7010
|
+
const path = resolveFilePath(options.directory, createMemoryStoreId(input));
|
|
7011
|
+
try {
|
|
7012
|
+
return await readJsonFile(path);
|
|
7013
|
+
} catch (error) {
|
|
7014
|
+
if (error.code === "ENOENT") {
|
|
7015
|
+
return;
|
|
7016
|
+
}
|
|
7017
|
+
throw error;
|
|
7018
|
+
}
|
|
7019
|
+
};
|
|
7020
|
+
const list = async (input) => {
|
|
7021
|
+
const files = await listJsonFiles(options.directory);
|
|
7022
|
+
const records = await Promise.all(files.map((file) => readJsonFile(file)));
|
|
7023
|
+
return records.filter((record) => record.assistantId === input.assistantId && (input.namespace === undefined || record.namespace === input.namespace)).sort((left, right) => right.updatedAt - left.updatedAt);
|
|
7024
|
+
};
|
|
7025
|
+
const set = async (input) => {
|
|
7026
|
+
const existing = await get(input);
|
|
7027
|
+
const record = createVoiceAssistantMemoryRecord({
|
|
7028
|
+
...input,
|
|
7029
|
+
createdAt: input.createdAt ?? existing?.createdAt,
|
|
7030
|
+
updatedAt: input.updatedAt
|
|
7031
|
+
});
|
|
7032
|
+
await writeJsonFile(resolveFilePath(options.directory, createMemoryStoreId(record)), record, options);
|
|
7033
|
+
return record;
|
|
7034
|
+
};
|
|
7035
|
+
const remove = async (input) => {
|
|
7036
|
+
await rm(resolveFilePath(options.directory, createMemoryStoreId(input)), {
|
|
7037
|
+
force: true
|
|
7038
|
+
});
|
|
7039
|
+
};
|
|
7040
|
+
return { delete: remove, get, list, set };
|
|
7041
|
+
};
|
|
6274
7042
|
var createVoiceFileRuntimeStorage = (options) => ({
|
|
6275
7043
|
events: createVoiceFileIntegrationEventStore({
|
|
6276
7044
|
...options,
|
|
@@ -6280,6 +7048,10 @@ var createVoiceFileRuntimeStorage = (options) => ({
|
|
|
6280
7048
|
...options,
|
|
6281
7049
|
directory: join(options.directory, "external-objects")
|
|
6282
7050
|
}),
|
|
7051
|
+
memories: createVoiceFileAssistantMemoryStore({
|
|
7052
|
+
...options,
|
|
7053
|
+
directory: join(options.directory, "memories")
|
|
7054
|
+
}),
|
|
6283
7055
|
reviews: createVoiceFileReviewStore({
|
|
6284
7056
|
...options,
|
|
6285
7057
|
directory: join(options.directory, "reviews")
|
|
@@ -6312,6 +7084,672 @@ var createStoredVoiceExternalObjectMap = (mapping) => createVoiceExternalObjectM
|
|
|
6312
7084
|
sourceId: mapping.sourceId,
|
|
6313
7085
|
sourceType: mapping.sourceType
|
|
6314
7086
|
});
|
|
7087
|
+
// src/modelAdapters.ts
|
|
7088
|
+
var OUTPUT_SCHEMA = {
|
|
7089
|
+
additionalProperties: false,
|
|
7090
|
+
properties: {
|
|
7091
|
+
assistantText: {
|
|
7092
|
+
type: "string"
|
|
7093
|
+
},
|
|
7094
|
+
complete: {
|
|
7095
|
+
type: "boolean"
|
|
7096
|
+
},
|
|
7097
|
+
escalate: {
|
|
7098
|
+
additionalProperties: false,
|
|
7099
|
+
properties: {
|
|
7100
|
+
metadata: {
|
|
7101
|
+
additionalProperties: true,
|
|
7102
|
+
type: "object"
|
|
7103
|
+
},
|
|
7104
|
+
reason: {
|
|
7105
|
+
type: "string"
|
|
7106
|
+
}
|
|
7107
|
+
},
|
|
7108
|
+
required: ["reason"],
|
|
7109
|
+
type: "object"
|
|
7110
|
+
},
|
|
7111
|
+
noAnswer: {
|
|
7112
|
+
additionalProperties: false,
|
|
7113
|
+
properties: {
|
|
7114
|
+
metadata: {
|
|
7115
|
+
additionalProperties: true,
|
|
7116
|
+
type: "object"
|
|
7117
|
+
}
|
|
7118
|
+
},
|
|
7119
|
+
type: "object"
|
|
7120
|
+
},
|
|
7121
|
+
result: {
|
|
7122
|
+
additionalProperties: true,
|
|
7123
|
+
type: "object"
|
|
7124
|
+
},
|
|
7125
|
+
transfer: {
|
|
7126
|
+
additionalProperties: false,
|
|
7127
|
+
properties: {
|
|
7128
|
+
metadata: {
|
|
7129
|
+
additionalProperties: true,
|
|
7130
|
+
type: "object"
|
|
7131
|
+
},
|
|
7132
|
+
reason: {
|
|
7133
|
+
type: "string"
|
|
7134
|
+
},
|
|
7135
|
+
target: {
|
|
7136
|
+
type: "string"
|
|
7137
|
+
}
|
|
7138
|
+
},
|
|
7139
|
+
required: ["target"],
|
|
7140
|
+
type: "object"
|
|
7141
|
+
},
|
|
7142
|
+
voicemail: {
|
|
7143
|
+
additionalProperties: false,
|
|
7144
|
+
properties: {
|
|
7145
|
+
metadata: {
|
|
7146
|
+
additionalProperties: true,
|
|
7147
|
+
type: "object"
|
|
7148
|
+
}
|
|
7149
|
+
},
|
|
7150
|
+
type: "object"
|
|
7151
|
+
}
|
|
7152
|
+
},
|
|
7153
|
+
type: "object"
|
|
7154
|
+
};
|
|
7155
|
+
var ROUTE_RESULT_INSTRUCTION = "Return only a JSON object with assistantText, complete, transfer, escalate, voicemail, noAnswer, and result when you are not calling tools. Only set transfer, escalate, voicemail, or noAnswer when the user explicitly asks for that lifecycle outcome or a tool result says that exact outcome. Do not infer voicemail from generic words like voice, voice app, or voice integration.";
|
|
7156
|
+
var stripJSONCodeFence = (value) => {
|
|
7157
|
+
const trimmed = value.trim();
|
|
7158
|
+
const match = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
|
|
7159
|
+
return match?.[1]?.trim() ?? value;
|
|
7160
|
+
};
|
|
7161
|
+
var parseJSON = (value) => {
|
|
7162
|
+
try {
|
|
7163
|
+
const parsed = JSON.parse(stripJSONCodeFence(value));
|
|
7164
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
7165
|
+
} catch {
|
|
7166
|
+
return {
|
|
7167
|
+
assistantText: value
|
|
7168
|
+
};
|
|
7169
|
+
}
|
|
7170
|
+
};
|
|
7171
|
+
var parseJSONValue = (value) => {
|
|
7172
|
+
try {
|
|
7173
|
+
return JSON.parse(value);
|
|
7174
|
+
} catch {
|
|
7175
|
+
return value;
|
|
7176
|
+
}
|
|
7177
|
+
};
|
|
7178
|
+
var getMessageToolCalls = (message) => {
|
|
7179
|
+
const toolCalls = message.metadata?.toolCalls;
|
|
7180
|
+
return Array.isArray(toolCalls) ? toolCalls.filter((toolCall) => toolCall && typeof toolCall === "object" && typeof toolCall.name === "string") : [];
|
|
7181
|
+
};
|
|
7182
|
+
var createHTTPError = (provider, response) => new Error(`${provider} voice assistant model failed: HTTP ${response.status}`);
|
|
7183
|
+
var sleep4 = (ms) => new Promise((resolve2) => {
|
|
7184
|
+
setTimeout(resolve2, ms);
|
|
7185
|
+
});
|
|
7186
|
+
var errorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
7187
|
+
var defaultIsRateLimitError = (error) => /(\b429\b|rate limit|quota|too many requests)/i.test(errorMessage(error));
|
|
7188
|
+
var normalizeRouteOutput = (output) => {
|
|
7189
|
+
const result = {};
|
|
7190
|
+
if (typeof output.assistantText === "string") {
|
|
7191
|
+
result.assistantText = output.assistantText;
|
|
7192
|
+
}
|
|
7193
|
+
if (typeof output.complete === "boolean") {
|
|
7194
|
+
result.complete = output.complete;
|
|
7195
|
+
}
|
|
7196
|
+
if (output.result !== undefined) {
|
|
7197
|
+
result.result = output.result;
|
|
7198
|
+
}
|
|
7199
|
+
if (output.transfer && typeof output.transfer === "object") {
|
|
7200
|
+
const transfer = output.transfer;
|
|
7201
|
+
if (typeof transfer.target === "string") {
|
|
7202
|
+
result.transfer = {
|
|
7203
|
+
metadata: transfer.metadata && typeof transfer.metadata === "object" ? transfer.metadata : undefined,
|
|
7204
|
+
reason: typeof transfer.reason === "string" ? transfer.reason : undefined,
|
|
7205
|
+
target: transfer.target
|
|
7206
|
+
};
|
|
7207
|
+
}
|
|
7208
|
+
}
|
|
7209
|
+
if (output.escalate && typeof output.escalate === "object") {
|
|
7210
|
+
const escalate = output.escalate;
|
|
7211
|
+
if (typeof escalate.reason === "string") {
|
|
7212
|
+
result.escalate = {
|
|
7213
|
+
metadata: escalate.metadata && typeof escalate.metadata === "object" ? escalate.metadata : undefined,
|
|
7214
|
+
reason: escalate.reason
|
|
7215
|
+
};
|
|
7216
|
+
}
|
|
7217
|
+
}
|
|
7218
|
+
if (output.voicemail && typeof output.voicemail === "object") {
|
|
7219
|
+
const voicemail = output.voicemail;
|
|
7220
|
+
result.voicemail = {
|
|
7221
|
+
metadata: voicemail.metadata && typeof voicemail.metadata === "object" ? voicemail.metadata : undefined
|
|
7222
|
+
};
|
|
7223
|
+
}
|
|
7224
|
+
if (output.noAnswer && typeof output.noAnswer === "object") {
|
|
7225
|
+
const noAnswer = output.noAnswer;
|
|
7226
|
+
result.noAnswer = {
|
|
7227
|
+
metadata: noAnswer.metadata && typeof noAnswer.metadata === "object" ? noAnswer.metadata : undefined
|
|
7228
|
+
};
|
|
7229
|
+
}
|
|
7230
|
+
return result;
|
|
7231
|
+
};
|
|
7232
|
+
var createJSONVoiceAssistantModel = (options) => ({
|
|
7233
|
+
generate: async (input) => {
|
|
7234
|
+
const output = await options.generate(input);
|
|
7235
|
+
if ("assistantText" in output || "toolCalls" in output || "complete" in output || "transfer" in output || "escalate" in output) {
|
|
7236
|
+
return output;
|
|
7237
|
+
}
|
|
7238
|
+
return options.mapOutput?.(output) ?? normalizeRouteOutput(output);
|
|
7239
|
+
}
|
|
7240
|
+
});
|
|
7241
|
+
var createVoiceProviderRouter = (options) => {
|
|
7242
|
+
const providerIds = Object.keys(options.providers);
|
|
7243
|
+
const firstProvider = providerIds[0];
|
|
7244
|
+
const resolveOrder = async (input) => {
|
|
7245
|
+
const selectedProvider = await options.selectProvider?.(input);
|
|
7246
|
+
const fallbackOrder = typeof options.fallback === "function" ? await options.fallback(input) : options.fallback;
|
|
7247
|
+
const preferred = selectedProvider ?? fallbackOrder?.[0] ?? firstProvider;
|
|
7248
|
+
const seen = new Set;
|
|
7249
|
+
const order = [];
|
|
7250
|
+
for (const provider of [
|
|
7251
|
+
preferred,
|
|
7252
|
+
...fallbackOrder ?? [],
|
|
7253
|
+
...providerIds
|
|
7254
|
+
]) {
|
|
7255
|
+
if (!provider || seen.has(provider) || !options.providers[provider]) {
|
|
7256
|
+
continue;
|
|
7257
|
+
}
|
|
7258
|
+
seen.add(provider);
|
|
7259
|
+
order.push(provider);
|
|
7260
|
+
}
|
|
7261
|
+
return {
|
|
7262
|
+
order,
|
|
7263
|
+
selectedProvider: preferred
|
|
7264
|
+
};
|
|
7265
|
+
};
|
|
7266
|
+
const emit = async (event, input) => {
|
|
7267
|
+
await options.onProviderEvent?.(event, input);
|
|
7268
|
+
};
|
|
7269
|
+
return {
|
|
7270
|
+
generate: async (input) => {
|
|
7271
|
+
const { order, selectedProvider } = await resolveOrder(input);
|
|
7272
|
+
if (!selectedProvider || order.length === 0) {
|
|
7273
|
+
throw new Error("Voice provider router has no available providers.");
|
|
7274
|
+
}
|
|
7275
|
+
let lastError;
|
|
7276
|
+
for (const [index, provider] of order.entries()) {
|
|
7277
|
+
const model = options.providers[provider];
|
|
7278
|
+
if (!model) {
|
|
7279
|
+
continue;
|
|
7280
|
+
}
|
|
7281
|
+
const startedAt = Date.now();
|
|
7282
|
+
try {
|
|
7283
|
+
const output = await model.generate(input);
|
|
7284
|
+
await emit({
|
|
7285
|
+
at: Date.now(),
|
|
7286
|
+
elapsedMs: Date.now() - startedAt,
|
|
7287
|
+
fallbackProvider: provider === selectedProvider ? undefined : provider,
|
|
7288
|
+
provider,
|
|
7289
|
+
recovered: provider !== selectedProvider,
|
|
7290
|
+
selectedProvider,
|
|
7291
|
+
status: provider === selectedProvider ? "success" : "fallback"
|
|
7292
|
+
}, input);
|
|
7293
|
+
return output;
|
|
7294
|
+
} catch (error) {
|
|
7295
|
+
lastError = error;
|
|
7296
|
+
const hasNextProvider = index < order.length - 1;
|
|
7297
|
+
const isProviderError = options.isProviderError?.(error, provider) ?? true;
|
|
7298
|
+
const nextProvider = hasNextProvider ? order[index + 1] : undefined;
|
|
7299
|
+
await emit({
|
|
7300
|
+
at: Date.now(),
|
|
7301
|
+
elapsedMs: Date.now() - startedAt,
|
|
7302
|
+
error: errorMessage(error),
|
|
7303
|
+
fallbackProvider: isProviderError ? nextProvider : undefined,
|
|
7304
|
+
provider,
|
|
7305
|
+
rateLimited: options.isRateLimitError?.(error, provider) ?? defaultIsRateLimitError(error),
|
|
7306
|
+
selectedProvider,
|
|
7307
|
+
status: "error"
|
|
7308
|
+
}, input);
|
|
7309
|
+
if (!hasNextProvider || !isProviderError) {
|
|
7310
|
+
throw error;
|
|
7311
|
+
}
|
|
7312
|
+
}
|
|
7313
|
+
}
|
|
7314
|
+
throw lastError ?? new Error("Voice provider router did not run a provider.");
|
|
7315
|
+
}
|
|
7316
|
+
};
|
|
7317
|
+
};
|
|
7318
|
+
var messageToOpenAIInput = (message) => {
|
|
7319
|
+
if (message.role === "tool") {
|
|
7320
|
+
return [
|
|
7321
|
+
{
|
|
7322
|
+
call_id: message.toolCallId ?? message.name ?? crypto.randomUUID(),
|
|
7323
|
+
output: message.content,
|
|
7324
|
+
type: "function_call_output"
|
|
7325
|
+
}
|
|
7326
|
+
];
|
|
7327
|
+
}
|
|
7328
|
+
const toolCalls = getMessageToolCalls(message);
|
|
7329
|
+
if (message.role === "assistant" && toolCalls.length) {
|
|
7330
|
+
return toolCalls.map((toolCall) => ({
|
|
7331
|
+
arguments: JSON.stringify(toolCall.args),
|
|
7332
|
+
call_id: toolCall.id ?? crypto.randomUUID(),
|
|
7333
|
+
name: toolCall.name,
|
|
7334
|
+
type: "function_call"
|
|
7335
|
+
}));
|
|
7336
|
+
}
|
|
7337
|
+
return [
|
|
7338
|
+
{
|
|
7339
|
+
content: message.content,
|
|
7340
|
+
role: message.role === "system" ? "developer" : message.role
|
|
7341
|
+
}
|
|
7342
|
+
];
|
|
7343
|
+
};
|
|
7344
|
+
var messagesToOpenAIInput = (messages) => messages.flatMap(messageToOpenAIInput);
|
|
7345
|
+
var messageToAnthropicMessage = (message) => {
|
|
7346
|
+
if (message.role === "system") {
|
|
7347
|
+
return;
|
|
7348
|
+
}
|
|
7349
|
+
if (message.role === "tool") {
|
|
7350
|
+
if (!message.toolCallId) {
|
|
7351
|
+
return {
|
|
7352
|
+
content: `Tool result from ${message.name ?? "tool"}: ${message.content}`,
|
|
7353
|
+
role: "user"
|
|
7354
|
+
};
|
|
7355
|
+
}
|
|
7356
|
+
return {
|
|
7357
|
+
content: [
|
|
7358
|
+
{
|
|
7359
|
+
content: message.content,
|
|
7360
|
+
tool_use_id: message.toolCallId,
|
|
7361
|
+
type: "tool_result"
|
|
7362
|
+
}
|
|
7363
|
+
],
|
|
7364
|
+
role: "user"
|
|
7365
|
+
};
|
|
7366
|
+
}
|
|
7367
|
+
const toolCalls = getMessageToolCalls(message);
|
|
7368
|
+
if (message.role === "assistant" && toolCalls.length) {
|
|
7369
|
+
return {
|
|
7370
|
+
content: [
|
|
7371
|
+
...message.content ? [
|
|
7372
|
+
{
|
|
7373
|
+
text: message.content,
|
|
7374
|
+
type: "text"
|
|
7375
|
+
}
|
|
7376
|
+
] : [],
|
|
7377
|
+
...toolCalls.map((toolCall) => ({
|
|
7378
|
+
id: toolCall.id ?? crypto.randomUUID(),
|
|
7379
|
+
input: toolCall.args,
|
|
7380
|
+
name: toolCall.name,
|
|
7381
|
+
type: "tool_use"
|
|
7382
|
+
}))
|
|
7383
|
+
],
|
|
7384
|
+
role: "assistant"
|
|
7385
|
+
};
|
|
7386
|
+
}
|
|
7387
|
+
return {
|
|
7388
|
+
content: message.content,
|
|
7389
|
+
role: message.role
|
|
7390
|
+
};
|
|
7391
|
+
};
|
|
7392
|
+
var toGeminiSchema = (schema) => {
|
|
7393
|
+
const next = {};
|
|
7394
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
7395
|
+
if (key === "additionalProperties") {
|
|
7396
|
+
continue;
|
|
7397
|
+
}
|
|
7398
|
+
if (key === "type" && typeof value === "string") {
|
|
7399
|
+
next[key] = value.toUpperCase();
|
|
7400
|
+
continue;
|
|
7401
|
+
}
|
|
7402
|
+
if (Array.isArray(value)) {
|
|
7403
|
+
next[key] = value.map((item) => item && typeof item === "object" ? toGeminiSchema(item) : item);
|
|
7404
|
+
continue;
|
|
7405
|
+
}
|
|
7406
|
+
if (value && typeof value === "object") {
|
|
7407
|
+
next[key] = toGeminiSchema(value);
|
|
7408
|
+
continue;
|
|
7409
|
+
}
|
|
7410
|
+
next[key] = value;
|
|
7411
|
+
}
|
|
7412
|
+
return next;
|
|
7413
|
+
};
|
|
7414
|
+
var messageToGeminiContent = (message) => {
|
|
7415
|
+
if (message.role === "system") {
|
|
7416
|
+
return;
|
|
7417
|
+
}
|
|
7418
|
+
if (message.role === "tool") {
|
|
7419
|
+
return {
|
|
7420
|
+
parts: [
|
|
7421
|
+
{
|
|
7422
|
+
functionResponse: {
|
|
7423
|
+
id: message.toolCallId,
|
|
7424
|
+
name: message.name ?? "tool",
|
|
7425
|
+
response: {
|
|
7426
|
+
result: parseJSONValue(message.content)
|
|
7427
|
+
}
|
|
7428
|
+
}
|
|
7429
|
+
}
|
|
7430
|
+
],
|
|
7431
|
+
role: "user"
|
|
7432
|
+
};
|
|
7433
|
+
}
|
|
7434
|
+
const toolCalls = getMessageToolCalls(message);
|
|
7435
|
+
if (message.role === "assistant" && toolCalls.length) {
|
|
7436
|
+
return {
|
|
7437
|
+
parts: [
|
|
7438
|
+
...message.content ? [
|
|
7439
|
+
{
|
|
7440
|
+
text: message.content
|
|
7441
|
+
}
|
|
7442
|
+
] : [],
|
|
7443
|
+
...toolCalls.map((toolCall) => ({
|
|
7444
|
+
functionCall: {
|
|
7445
|
+
args: toolCall.args,
|
|
7446
|
+
id: toolCall.id,
|
|
7447
|
+
name: toolCall.name
|
|
7448
|
+
}
|
|
7449
|
+
}))
|
|
7450
|
+
],
|
|
7451
|
+
role: "model"
|
|
7452
|
+
};
|
|
7453
|
+
}
|
|
7454
|
+
return {
|
|
7455
|
+
parts: [
|
|
7456
|
+
{
|
|
7457
|
+
text: message.content
|
|
7458
|
+
}
|
|
7459
|
+
],
|
|
7460
|
+
role: message.role === "assistant" ? "model" : "user"
|
|
7461
|
+
};
|
|
7462
|
+
};
|
|
7463
|
+
var extractText = (response) => {
|
|
7464
|
+
if (typeof response.output_text === "string") {
|
|
7465
|
+
return response.output_text;
|
|
7466
|
+
}
|
|
7467
|
+
const output = Array.isArray(response.output) ? response.output : [];
|
|
7468
|
+
for (const item of output) {
|
|
7469
|
+
if (!item || typeof item !== "object") {
|
|
7470
|
+
continue;
|
|
7471
|
+
}
|
|
7472
|
+
const record = item;
|
|
7473
|
+
const content = Array.isArray(record.content) ? record.content : [];
|
|
7474
|
+
for (const contentItem of content) {
|
|
7475
|
+
if (!contentItem || typeof contentItem !== "object") {
|
|
7476
|
+
continue;
|
|
7477
|
+
}
|
|
7478
|
+
const contentRecord = contentItem;
|
|
7479
|
+
if (typeof contentRecord.text === "string") {
|
|
7480
|
+
return contentRecord.text;
|
|
7481
|
+
}
|
|
7482
|
+
}
|
|
7483
|
+
}
|
|
7484
|
+
return "";
|
|
7485
|
+
};
|
|
7486
|
+
var extractToolCalls = (response) => {
|
|
7487
|
+
const output = Array.isArray(response.output) ? response.output : [];
|
|
7488
|
+
const toolCalls = [];
|
|
7489
|
+
for (const item of output) {
|
|
7490
|
+
if (!item || typeof item !== "object") {
|
|
7491
|
+
continue;
|
|
7492
|
+
}
|
|
7493
|
+
const record = item;
|
|
7494
|
+
if (record.type !== "function_call" || typeof record.name !== "string") {
|
|
7495
|
+
continue;
|
|
7496
|
+
}
|
|
7497
|
+
const args = typeof record.arguments === "string" ? parseJSON(record.arguments) : {};
|
|
7498
|
+
toolCalls.push({
|
|
7499
|
+
args,
|
|
7500
|
+
id: typeof record.call_id === "string" ? record.call_id : typeof record.id === "string" ? record.id : undefined,
|
|
7501
|
+
name: record.name
|
|
7502
|
+
});
|
|
7503
|
+
}
|
|
7504
|
+
return toolCalls;
|
|
7505
|
+
};
|
|
7506
|
+
var createOpenAIVoiceAssistantModel = (options) => {
|
|
7507
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
7508
|
+
const baseUrl = options.baseUrl ?? "https://api.openai.com/v1";
|
|
7509
|
+
const model = options.model ?? "gpt-4.1-mini";
|
|
7510
|
+
return {
|
|
7511
|
+
generate: async (input) => {
|
|
7512
|
+
const response = await fetchImpl(`${baseUrl.replace(/\/$/, "")}/responses`, {
|
|
7513
|
+
body: JSON.stringify({
|
|
7514
|
+
input: messagesToOpenAIInput(input.messages),
|
|
7515
|
+
instructions: [
|
|
7516
|
+
input.system,
|
|
7517
|
+
"Return a JSON object with assistantText, complete, transfer, escalate, voicemail, noAnswer, and result when you are not calling tools."
|
|
7518
|
+
].filter(Boolean).join(`
|
|
7519
|
+
|
|
7520
|
+
`),
|
|
7521
|
+
max_output_tokens: options.maxOutputTokens,
|
|
7522
|
+
model,
|
|
7523
|
+
temperature: options.temperature,
|
|
7524
|
+
text: {
|
|
7525
|
+
format: {
|
|
7526
|
+
name: "voice_route_result",
|
|
7527
|
+
schema: OUTPUT_SCHEMA,
|
|
7528
|
+
strict: false,
|
|
7529
|
+
type: "json_schema"
|
|
7530
|
+
}
|
|
7531
|
+
},
|
|
7532
|
+
tool_choice: input.tools.length ? "auto" : "none",
|
|
7533
|
+
tools: input.tools.map((tool) => ({
|
|
7534
|
+
description: tool.description,
|
|
7535
|
+
name: tool.name,
|
|
7536
|
+
parameters: tool.parameters ?? {
|
|
7537
|
+
additionalProperties: true,
|
|
7538
|
+
type: "object"
|
|
7539
|
+
},
|
|
7540
|
+
strict: false,
|
|
7541
|
+
type: "function"
|
|
7542
|
+
}))
|
|
7543
|
+
}),
|
|
7544
|
+
headers: {
|
|
7545
|
+
authorization: `Bearer ${options.apiKey}`,
|
|
7546
|
+
"content-type": "application/json"
|
|
7547
|
+
},
|
|
7548
|
+
method: "POST"
|
|
7549
|
+
});
|
|
7550
|
+
if (!response.ok) {
|
|
7551
|
+
throw createHTTPError("OpenAI", response);
|
|
7552
|
+
}
|
|
7553
|
+
const body = await response.json();
|
|
7554
|
+
if (body.usage && typeof body.usage === "object") {
|
|
7555
|
+
await options.onUsage?.(body.usage);
|
|
7556
|
+
}
|
|
7557
|
+
const toolCalls = extractToolCalls(body);
|
|
7558
|
+
if (toolCalls.length) {
|
|
7559
|
+
return {
|
|
7560
|
+
toolCalls
|
|
7561
|
+
};
|
|
7562
|
+
}
|
|
7563
|
+
return normalizeRouteOutput(parseJSON(extractText(body)));
|
|
7564
|
+
}
|
|
7565
|
+
};
|
|
7566
|
+
};
|
|
7567
|
+
var extractAnthropicText = (response) => {
|
|
7568
|
+
const content = Array.isArray(response.content) ? response.content : [];
|
|
7569
|
+
return content.map((item) => item && typeof item === "object" && item.type === "text" && typeof item.text === "string" ? item.text : "").filter(Boolean).join(`
|
|
7570
|
+
`);
|
|
7571
|
+
};
|
|
7572
|
+
var extractAnthropicToolCalls = (response) => {
|
|
7573
|
+
const content = Array.isArray(response.content) ? response.content : [];
|
|
7574
|
+
const toolCalls = [];
|
|
7575
|
+
for (const item of content) {
|
|
7576
|
+
if (!item || typeof item !== "object") {
|
|
7577
|
+
continue;
|
|
7578
|
+
}
|
|
7579
|
+
const record = item;
|
|
7580
|
+
if (record.type !== "tool_use" || typeof record.name !== "string") {
|
|
7581
|
+
continue;
|
|
7582
|
+
}
|
|
7583
|
+
toolCalls.push({
|
|
7584
|
+
args: record.input && typeof record.input === "object" ? record.input : {},
|
|
7585
|
+
id: typeof record.id === "string" ? record.id : undefined,
|
|
7586
|
+
name: record.name
|
|
7587
|
+
});
|
|
7588
|
+
}
|
|
7589
|
+
return toolCalls;
|
|
7590
|
+
};
|
|
7591
|
+
var createAnthropicVoiceAssistantModel = (options) => {
|
|
7592
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
7593
|
+
const baseUrl = options.baseUrl ?? "https://api.anthropic.com/v1";
|
|
7594
|
+
const model = options.model ?? "claude-sonnet-4-5";
|
|
7595
|
+
return {
|
|
7596
|
+
generate: async (input) => {
|
|
7597
|
+
const response = await fetchImpl(`${baseUrl.replace(/\/$/, "")}/messages`, {
|
|
7598
|
+
body: JSON.stringify({
|
|
7599
|
+
max_tokens: options.maxOutputTokens ?? 1024,
|
|
7600
|
+
messages: input.messages.map(messageToAnthropicMessage).filter(Boolean),
|
|
7601
|
+
model,
|
|
7602
|
+
system: [input.system, ROUTE_RESULT_INSTRUCTION].filter(Boolean).join(`
|
|
7603
|
+
|
|
7604
|
+
`),
|
|
7605
|
+
temperature: options.temperature,
|
|
7606
|
+
tool_choice: input.tools.length ? { type: "auto" } : { type: "none" },
|
|
7607
|
+
tools: input.tools.map((tool) => ({
|
|
7608
|
+
description: tool.description,
|
|
7609
|
+
input_schema: tool.parameters ?? {
|
|
7610
|
+
additionalProperties: true,
|
|
7611
|
+
type: "object"
|
|
7612
|
+
},
|
|
7613
|
+
name: tool.name
|
|
7614
|
+
}))
|
|
7615
|
+
}),
|
|
7616
|
+
headers: {
|
|
7617
|
+
"anthropic-version": options.version ?? "2023-06-01",
|
|
7618
|
+
"content-type": "application/json",
|
|
7619
|
+
"x-api-key": options.apiKey
|
|
7620
|
+
},
|
|
7621
|
+
method: "POST"
|
|
7622
|
+
});
|
|
7623
|
+
if (!response.ok) {
|
|
7624
|
+
throw createHTTPError("Anthropic", response);
|
|
7625
|
+
}
|
|
7626
|
+
const body = await response.json();
|
|
7627
|
+
if (body.usage && typeof body.usage === "object") {
|
|
7628
|
+
await options.onUsage?.(body.usage);
|
|
7629
|
+
}
|
|
7630
|
+
const toolCalls = extractAnthropicToolCalls(body);
|
|
7631
|
+
if (toolCalls.length) {
|
|
7632
|
+
return {
|
|
7633
|
+
assistantText: extractAnthropicText(body) || undefined,
|
|
7634
|
+
toolCalls
|
|
7635
|
+
};
|
|
7636
|
+
}
|
|
7637
|
+
return normalizeRouteOutput(parseJSON(extractAnthropicText(body)));
|
|
7638
|
+
}
|
|
7639
|
+
};
|
|
7640
|
+
};
|
|
7641
|
+
var extractGeminiCandidateParts = (response) => {
|
|
7642
|
+
const candidates = Array.isArray(response.candidates) ? response.candidates : [];
|
|
7643
|
+
const first = candidates[0];
|
|
7644
|
+
if (!first || typeof first !== "object") {
|
|
7645
|
+
return [];
|
|
7646
|
+
}
|
|
7647
|
+
const content = first.content;
|
|
7648
|
+
if (!content || typeof content !== "object") {
|
|
7649
|
+
return [];
|
|
7650
|
+
}
|
|
7651
|
+
const parts = content.parts;
|
|
7652
|
+
return Array.isArray(parts) ? parts : [];
|
|
7653
|
+
};
|
|
7654
|
+
var extractGeminiText = (response) => extractGeminiCandidateParts(response).map((part) => part && typeof part === "object" && typeof part.text === "string" ? part.text : "").filter(Boolean).join(`
|
|
7655
|
+
`);
|
|
7656
|
+
var extractGeminiToolCalls = (response) => {
|
|
7657
|
+
const toolCalls = [];
|
|
7658
|
+
for (const part of extractGeminiCandidateParts(response)) {
|
|
7659
|
+
if (!part || typeof part !== "object") {
|
|
7660
|
+
continue;
|
|
7661
|
+
}
|
|
7662
|
+
const functionCall = part.functionCall;
|
|
7663
|
+
if (!functionCall || typeof functionCall !== "object") {
|
|
7664
|
+
continue;
|
|
7665
|
+
}
|
|
7666
|
+
const record = functionCall;
|
|
7667
|
+
if (typeof record.name !== "string") {
|
|
7668
|
+
continue;
|
|
7669
|
+
}
|
|
7670
|
+
toolCalls.push({
|
|
7671
|
+
args: record.args && typeof record.args === "object" ? record.args : {},
|
|
7672
|
+
id: typeof record.id === "string" ? record.id : undefined,
|
|
7673
|
+
name: record.name
|
|
7674
|
+
});
|
|
7675
|
+
}
|
|
7676
|
+
return toolCalls;
|
|
7677
|
+
};
|
|
7678
|
+
var createGeminiVoiceAssistantModel = (options) => {
|
|
7679
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
7680
|
+
const baseUrl = options.baseUrl ?? "https://generativelanguage.googleapis.com/v1beta";
|
|
7681
|
+
const model = options.model ?? "gemini-2.5-flash";
|
|
7682
|
+
const maxRetries = Math.max(0, options.maxRetries ?? 2);
|
|
7683
|
+
return {
|
|
7684
|
+
generate: async (input) => {
|
|
7685
|
+
const endpoint = `${baseUrl.replace(/\/$/, "")}/models/${encodeURIComponent(model)}:generateContent?key=${encodeURIComponent(options.apiKey)}`;
|
|
7686
|
+
let response;
|
|
7687
|
+
for (let attempt = 0;attempt <= maxRetries; attempt += 1) {
|
|
7688
|
+
response = await fetchImpl(endpoint, {
|
|
7689
|
+
body: JSON.stringify({
|
|
7690
|
+
contents: input.messages.map(messageToGeminiContent).filter(Boolean),
|
|
7691
|
+
generationConfig: {
|
|
7692
|
+
maxOutputTokens: options.maxOutputTokens,
|
|
7693
|
+
...input.tools.length ? {} : {
|
|
7694
|
+
responseMimeType: "application/json",
|
|
7695
|
+
responseSchema: toGeminiSchema(OUTPUT_SCHEMA)
|
|
7696
|
+
},
|
|
7697
|
+
temperature: options.temperature
|
|
7698
|
+
},
|
|
7699
|
+
systemInstruction: {
|
|
7700
|
+
parts: [
|
|
7701
|
+
{
|
|
7702
|
+
text: [input.system, ROUTE_RESULT_INSTRUCTION].filter(Boolean).join(`
|
|
7703
|
+
|
|
7704
|
+
`)
|
|
7705
|
+
}
|
|
7706
|
+
]
|
|
7707
|
+
},
|
|
7708
|
+
tools: input.tools.length ? [
|
|
7709
|
+
{
|
|
7710
|
+
functionDeclarations: input.tools.map((tool) => ({
|
|
7711
|
+
description: tool.description,
|
|
7712
|
+
name: tool.name,
|
|
7713
|
+
parameters: toGeminiSchema(tool.parameters ?? {
|
|
7714
|
+
additionalProperties: true,
|
|
7715
|
+
type: "object"
|
|
7716
|
+
})
|
|
7717
|
+
}))
|
|
7718
|
+
}
|
|
7719
|
+
] : undefined
|
|
7720
|
+
}),
|
|
7721
|
+
headers: {
|
|
7722
|
+
"content-type": "application/json"
|
|
7723
|
+
},
|
|
7724
|
+
method: "POST"
|
|
7725
|
+
});
|
|
7726
|
+
if (response.ok || response.status !== 429 && response.status < 500 || attempt === maxRetries) {
|
|
7727
|
+
break;
|
|
7728
|
+
}
|
|
7729
|
+
const retryAfter = Number(response.headers.get("retry-after"));
|
|
7730
|
+
await sleep4(Number.isFinite(retryAfter) && retryAfter > 0 ? retryAfter * 1000 : 500 * 2 ** attempt);
|
|
7731
|
+
}
|
|
7732
|
+
if (!response) {
|
|
7733
|
+
throw new Error("Gemini voice assistant model failed: no response");
|
|
7734
|
+
}
|
|
7735
|
+
if (!response.ok) {
|
|
7736
|
+
throw createHTTPError("Gemini", response);
|
|
7737
|
+
}
|
|
7738
|
+
const body = await response.json();
|
|
7739
|
+
if (body.usageMetadata && typeof body.usageMetadata === "object") {
|
|
7740
|
+
await options.onUsage?.(body.usageMetadata);
|
|
7741
|
+
}
|
|
7742
|
+
const toolCalls = extractGeminiToolCalls(body);
|
|
7743
|
+
if (toolCalls.length) {
|
|
7744
|
+
return {
|
|
7745
|
+
assistantText: extractGeminiText(body) || undefined,
|
|
7746
|
+
toolCalls
|
|
7747
|
+
};
|
|
7748
|
+
}
|
|
7749
|
+
return normalizeRouteOutput(parseJSON(extractGeminiText(body)));
|
|
7750
|
+
}
|
|
7751
|
+
};
|
|
7752
|
+
};
|
|
6315
7753
|
// src/sqliteStore.ts
|
|
6316
7754
|
import { Database } from "bun:sqlite";
|
|
6317
7755
|
var normalizeTableNameSegment = (value) => value.trim().replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "voice";
|
|
@@ -7509,10 +8947,10 @@ var createVoiceOpsTaskProcessorWorker = (options) => ({
|
|
|
7509
8947
|
result.completed += 1;
|
|
7510
8948
|
} catch (error) {
|
|
7511
8949
|
await options.onError?.(error, task);
|
|
7512
|
-
const
|
|
8950
|
+
const errorMessage2 = error instanceof Error ? error.message : String(error);
|
|
7513
8951
|
const failedTask = failVoiceOpsTask(task, {
|
|
7514
8952
|
actor: task.claimedBy ?? "ops-worker",
|
|
7515
|
-
error:
|
|
8953
|
+
error: errorMessage2
|
|
7516
8954
|
});
|
|
7517
8955
|
if (shouldDeadLetterTask(failedTask, options.maxFailures)) {
|
|
7518
8956
|
const deadLetterTask = deadLetterVoiceOpsTask(failedTask, {
|
|
@@ -7987,230 +9425,6 @@ var resolveVoiceOpsPreset = (name, overrides = {}) => {
|
|
|
7987
9425
|
taskPolicies: mergePolicies(preset.taskPolicies, overrides.taskPolicies)
|
|
7988
9426
|
};
|
|
7989
9427
|
};
|
|
7990
|
-
// src/outcomeRecipes.ts
|
|
7991
|
-
var RECIPE_DEFAULTS = {
|
|
7992
|
-
"appointment-booking": {
|
|
7993
|
-
completedAction: "Verify appointment details, confirm calendar state, and send any required confirmation.",
|
|
7994
|
-
completedDescription: "The call completed an appointment-booking flow and should be checked against the scheduling system.",
|
|
7995
|
-
completedKind: "appointment-booking",
|
|
7996
|
-
completedTitle: "Confirm booked appointment",
|
|
7997
|
-
defaultCompletedCreatesTask: true,
|
|
7998
|
-
defaultDueInMs: 30 * 60000,
|
|
7999
|
-
defaultPriority: "normal",
|
|
8000
|
-
defaultQueue: "appointments",
|
|
8001
|
-
description: "Creates appointment confirmation work for completed calls and callback/retry work for missed booking attempts.",
|
|
8002
|
-
escalationQueue: "appointments-escalations"
|
|
8003
|
-
},
|
|
8004
|
-
"lead-qualification": {
|
|
8005
|
-
completedAction: "Review qualification signals, update CRM fields, and route the lead to the right owner.",
|
|
8006
|
-
completedDescription: "The call completed a lead-qualification flow and should be reviewed for sales follow-up.",
|
|
8007
|
-
completedKind: "lead-qualification",
|
|
8008
|
-
completedTitle: "Review qualified lead",
|
|
8009
|
-
defaultCompletedCreatesTask: true,
|
|
8010
|
-
defaultDueInMs: 15 * 60000,
|
|
8011
|
-
defaultPriority: "high",
|
|
8012
|
-
defaultQueue: "sales-leads",
|
|
8013
|
-
description: "Creates sales follow-up work for completed qualification calls and fast callbacks for missed leads.",
|
|
8014
|
-
escalationQueue: "sales-escalations"
|
|
8015
|
-
},
|
|
8016
|
-
"support-triage": {
|
|
8017
|
-
completedAction: "Review the triage result, confirm the support category, and route any unresolved issue.",
|
|
8018
|
-
completedDescription: "The call completed support triage and may need queue routing or human follow-up.",
|
|
8019
|
-
completedKind: "support-triage",
|
|
8020
|
-
completedTitle: "Review support triage",
|
|
8021
|
-
defaultCompletedCreatesTask: true,
|
|
8022
|
-
defaultDueInMs: 20 * 60000,
|
|
8023
|
-
defaultPriority: "normal",
|
|
8024
|
-
defaultQueue: "support-triage",
|
|
8025
|
-
description: "Creates support triage work for completed calls and urgent escalation/callback work for unresolved callers.",
|
|
8026
|
-
escalationQueue: "support-escalations"
|
|
8027
|
-
},
|
|
8028
|
-
"voicemail-callback": {
|
|
8029
|
-
completedAction: "No callback is required for completed calls.",
|
|
8030
|
-
completedDescription: "The call completed without requiring voicemail follow-up.",
|
|
8031
|
-
completedKind: "callback",
|
|
8032
|
-
completedTitle: "Completed call",
|
|
8033
|
-
defaultCompletedCreatesTask: false,
|
|
8034
|
-
defaultDueInMs: 15 * 60000,
|
|
8035
|
-
defaultPriority: "high",
|
|
8036
|
-
defaultQueue: "callbacks",
|
|
8037
|
-
description: "Creates callback work for voicemail, no-answer, failed, or escalated calls while ignoring completed calls.",
|
|
8038
|
-
escalationQueue: "callback-escalations"
|
|
8039
|
-
},
|
|
8040
|
-
"warm-transfer": {
|
|
8041
|
-
completedAction: "Confirm the handoff target received the caller context and close the transfer loop.",
|
|
8042
|
-
completedDescription: "The call is part of a warm-transfer flow and should be verified downstream.",
|
|
8043
|
-
completedKind: "transfer-check",
|
|
8044
|
-
completedTitle: "Verify warm transfer",
|
|
8045
|
-
defaultCompletedCreatesTask: false,
|
|
8046
|
-
defaultDueInMs: 10 * 60000,
|
|
8047
|
-
defaultPriority: "normal",
|
|
8048
|
-
defaultQueue: "transfer-verification",
|
|
8049
|
-
description: "Creates transfer verification work for transferred calls and escalation work when the handoff fails.",
|
|
8050
|
-
escalationQueue: "transfer-escalations"
|
|
8051
|
-
}
|
|
8052
|
-
};
|
|
8053
|
-
var buildRecipeTask = (input) => {
|
|
8054
|
-
const createdAt = input.review.generatedAt ?? Date.now();
|
|
8055
|
-
const queue = input.options.queue ?? input.defaults.defaultQueue;
|
|
8056
|
-
const target = input.options.target ?? input.review.postCall?.target;
|
|
8057
|
-
const common = {
|
|
8058
|
-
assignee: input.options.assignee,
|
|
8059
|
-
createdAt,
|
|
8060
|
-
history: [
|
|
8061
|
-
{
|
|
8062
|
-
actor: "system",
|
|
8063
|
-
at: createdAt,
|
|
8064
|
-
detail: input.review.postCall?.summary,
|
|
8065
|
-
type: "created"
|
|
8066
|
-
}
|
|
8067
|
-
],
|
|
8068
|
-
id: `${input.review.id}:${input.defaults.completedKind}`,
|
|
8069
|
-
intakeId: input.review.id,
|
|
8070
|
-
outcome: input.review.summary.outcome,
|
|
8071
|
-
priority: input.options.priority ?? input.defaults.defaultPriority,
|
|
8072
|
-
queue,
|
|
8073
|
-
reviewId: input.review.id,
|
|
8074
|
-
status: "open",
|
|
8075
|
-
target,
|
|
8076
|
-
updatedAt: createdAt
|
|
8077
|
-
};
|
|
8078
|
-
switch (input.disposition) {
|
|
8079
|
-
case "completed":
|
|
8080
|
-
if (!(input.options.completedCreatesTask ?? input.defaults.defaultCompletedCreatesTask)) {
|
|
8081
|
-
return null;
|
|
8082
|
-
}
|
|
8083
|
-
return {
|
|
8084
|
-
...common,
|
|
8085
|
-
description: input.defaults.completedDescription,
|
|
8086
|
-
kind: input.defaults.completedKind,
|
|
8087
|
-
recommendedAction: input.defaults.completedAction,
|
|
8088
|
-
title: target ? `${input.defaults.completedTitle}: ${target}` : input.defaults.completedTitle
|
|
8089
|
-
};
|
|
8090
|
-
case "voicemail":
|
|
8091
|
-
return {
|
|
8092
|
-
...common,
|
|
8093
|
-
description: input.review.postCall?.summary ?? "The caller reached voicemail and needs a callback.",
|
|
8094
|
-
id: `${input.review.id}:callback`,
|
|
8095
|
-
kind: "callback",
|
|
8096
|
-
recommendedAction: input.review.postCall?.recommendedAction ?? "Call the customer back and continue the original flow.",
|
|
8097
|
-
title: target ? `Call back ${target}` : "Call back voicemail lead"
|
|
8098
|
-
};
|
|
8099
|
-
case "no-answer":
|
|
8100
|
-
return {
|
|
8101
|
-
...common,
|
|
8102
|
-
description: input.review.postCall?.summary ?? "The call did not reach a live respondent and should be retried.",
|
|
8103
|
-
id: `${input.review.id}:retry`,
|
|
8104
|
-
kind: "callback",
|
|
8105
|
-
recommendedAction: input.review.postCall?.recommendedAction ?? "Retry the call or schedule a callback.",
|
|
8106
|
-
title: "Retry no-answer call"
|
|
8107
|
-
};
|
|
8108
|
-
case "transferred":
|
|
8109
|
-
return {
|
|
8110
|
-
...common,
|
|
8111
|
-
description: input.review.postCall?.summary ?? "The call was transferred and should be verified downstream.",
|
|
8112
|
-
id: `${input.review.id}:transfer-check`,
|
|
8113
|
-
kind: "transfer-check",
|
|
8114
|
-
recommendedAction: input.review.postCall?.recommendedAction ?? "Confirm the receiving team got the caller context.",
|
|
8115
|
-
title: target ? `Verify transfer to ${target}` : "Verify call transfer"
|
|
8116
|
-
};
|
|
8117
|
-
case "escalated":
|
|
8118
|
-
return {
|
|
8119
|
-
...common,
|
|
8120
|
-
description: input.review.postCall?.summary ?? "The call escalated and needs human review.",
|
|
8121
|
-
id: `${input.review.id}:escalation`,
|
|
8122
|
-
kind: "escalation",
|
|
8123
|
-
priority: "urgent",
|
|
8124
|
-
queue: input.options.escalationQueue ?? input.defaults.escalationQueue,
|
|
8125
|
-
assignee: input.options.escalationAssignee ?? input.options.assignee,
|
|
8126
|
-
recommendedAction: input.review.postCall?.recommendedAction ?? "Review the escalated call and respond immediately.",
|
|
8127
|
-
title: "Review escalated call"
|
|
8128
|
-
};
|
|
8129
|
-
case "failed":
|
|
8130
|
-
case "closed":
|
|
8131
|
-
return {
|
|
8132
|
-
...common,
|
|
8133
|
-
description: input.review.postCall?.summary ?? "The call ended before successful completion and needs review.",
|
|
8134
|
-
id: `${input.review.id}:retry-review`,
|
|
8135
|
-
kind: "retry-review",
|
|
8136
|
-
priority: "high",
|
|
8137
|
-
recommendedAction: input.review.postCall?.recommendedAction ?? "Inspect the call and decide whether to retry, escalate, or close.",
|
|
8138
|
-
title: "Inspect incomplete call"
|
|
8139
|
-
};
|
|
8140
|
-
default:
|
|
8141
|
-
return null;
|
|
8142
|
-
}
|
|
8143
|
-
};
|
|
8144
|
-
var resolveVoiceOutcomeRecipe = (name, options = {}) => {
|
|
8145
|
-
const defaults = RECIPE_DEFAULTS[name];
|
|
8146
|
-
const taskPolicies = {
|
|
8147
|
-
completed: {
|
|
8148
|
-
assignee: options.assignee,
|
|
8149
|
-
dueInMs: options.dueInMs ?? defaults.defaultDueInMs,
|
|
8150
|
-
name: `${name}-completed`,
|
|
8151
|
-
priority: options.priority ?? defaults.defaultPriority,
|
|
8152
|
-
queue: options.queue ?? defaults.defaultQueue
|
|
8153
|
-
},
|
|
8154
|
-
escalated: {
|
|
8155
|
-
assignee: options.escalationAssignee ?? options.assignee,
|
|
8156
|
-
dueInMs: Math.min(options.dueInMs ?? defaults.defaultDueInMs, 10 * 60000),
|
|
8157
|
-
name: `${name}-escalation`,
|
|
8158
|
-
priority: "urgent",
|
|
8159
|
-
queue: options.escalationQueue ?? defaults.escalationQueue
|
|
8160
|
-
},
|
|
8161
|
-
failed: {
|
|
8162
|
-
assignee: options.assignee,
|
|
8163
|
-
dueInMs: options.dueInMs ?? defaults.defaultDueInMs,
|
|
8164
|
-
name: `${name}-failed-review`,
|
|
8165
|
-
priority: "high",
|
|
8166
|
-
queue: options.queue ?? defaults.defaultQueue
|
|
8167
|
-
},
|
|
8168
|
-
"no-answer": {
|
|
8169
|
-
assignee: options.assignee,
|
|
8170
|
-
dueInMs: options.dueInMs ?? defaults.defaultDueInMs,
|
|
8171
|
-
name: `${name}-no-answer`,
|
|
8172
|
-
priority: options.priority ?? defaults.defaultPriority,
|
|
8173
|
-
queue: options.queue ?? defaults.defaultQueue
|
|
8174
|
-
},
|
|
8175
|
-
transferred: {
|
|
8176
|
-
assignee: options.assignee,
|
|
8177
|
-
dueInMs: Math.min(options.dueInMs ?? defaults.defaultDueInMs, 20 * 60000),
|
|
8178
|
-
name: `${name}-transfer-check`,
|
|
8179
|
-
priority: options.priority ?? defaults.defaultPriority,
|
|
8180
|
-
queue: name === "warm-transfer" ? options.queue ?? defaults.defaultQueue : "transfer-verification"
|
|
8181
|
-
},
|
|
8182
|
-
voicemail: {
|
|
8183
|
-
assignee: options.assignee,
|
|
8184
|
-
dueInMs: options.dueInMs ?? defaults.defaultDueInMs,
|
|
8185
|
-
name: `${name}-voicemail`,
|
|
8186
|
-
priority: options.priority ?? defaults.defaultPriority,
|
|
8187
|
-
queue: options.queue ?? defaults.defaultQueue
|
|
8188
|
-
}
|
|
8189
|
-
};
|
|
8190
|
-
const taskAssignmentRules = [
|
|
8191
|
-
{
|
|
8192
|
-
assign: options.escalationAssignee ?? options.assignee,
|
|
8193
|
-
description: `Route urgent ${name} work to the escalation lane.`,
|
|
8194
|
-
name: `${name}-urgent-routing`,
|
|
8195
|
-
queue: options.escalationQueue ?? defaults.escalationQueue,
|
|
8196
|
-
when: {
|
|
8197
|
-
priority: "urgent"
|
|
8198
|
-
}
|
|
8199
|
-
}
|
|
8200
|
-
].filter((rule) => rule.assign || rule.queue);
|
|
8201
|
-
return {
|
|
8202
|
-
createTaskFromReview: ({ disposition, review }) => buildRecipeTask({
|
|
8203
|
-
defaults,
|
|
8204
|
-
disposition,
|
|
8205
|
-
options,
|
|
8206
|
-
review
|
|
8207
|
-
}),
|
|
8208
|
-
description: defaults.description,
|
|
8209
|
-
name,
|
|
8210
|
-
taskAssignmentRules,
|
|
8211
|
-
taskPolicies
|
|
8212
|
-
};
|
|
8213
|
-
};
|
|
8214
9428
|
// src/correction.ts
|
|
8215
9429
|
var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8216
9430
|
var buildAliasMatcher = (alias) => new RegExp(`(?<![\\p{L}\\p{N}'])${escapeRegExp(alias)}(?![\\p{L}\\p{N}'])`, "giu");
|
|
@@ -8990,6 +10204,7 @@ export {
|
|
|
8990
10204
|
summarizeVoiceOpsTaskQueue,
|
|
8991
10205
|
summarizeVoiceOpsTaskAnalytics,
|
|
8992
10206
|
summarizeVoiceIntegrationEvents,
|
|
10207
|
+
summarizeVoiceAssistantRuns,
|
|
8993
10208
|
startVoiceOpsTask,
|
|
8994
10209
|
shapeTelephonyAssistantText,
|
|
8995
10210
|
selectVoiceTraceEventsForPrune,
|
|
@@ -9001,6 +10216,7 @@ export {
|
|
|
9001
10216
|
resolveVoiceOpsTaskAssignment,
|
|
9002
10217
|
resolveVoiceOpsTaskAgeBucket,
|
|
9003
10218
|
resolveVoiceOpsPreset,
|
|
10219
|
+
resolveVoiceAssistantMemoryNamespace,
|
|
9004
10220
|
resolveTurnDetectionConfig,
|
|
9005
10221
|
resolveAudioConditioningConfig,
|
|
9006
10222
|
requeueVoiceOpsTask,
|
|
@@ -9061,6 +10277,7 @@ export {
|
|
|
9061
10277
|
createVoiceReviewSavedEvent,
|
|
9062
10278
|
createVoiceRedisTaskLeaseCoordinator,
|
|
9063
10279
|
createVoiceRedisIdempotencyStore,
|
|
10280
|
+
createVoiceProviderRouter,
|
|
9064
10281
|
createVoicePostgresTraceSinkDeliveryStore,
|
|
9065
10282
|
createVoicePostgresTraceEventStore,
|
|
9066
10283
|
createVoicePostgresTaskStore,
|
|
@@ -9076,6 +10293,7 @@ export {
|
|
|
9076
10293
|
createVoiceMemoryTraceSinkDeliveryStore,
|
|
9077
10294
|
createVoiceMemoryTraceEventStore,
|
|
9078
10295
|
createVoiceMemoryStore,
|
|
10296
|
+
createVoiceMemoryAssistantMemoryStore,
|
|
9079
10297
|
createVoiceLinearIssueUpdateSink,
|
|
9080
10298
|
createVoiceLinearIssueSyncSinks,
|
|
9081
10299
|
createVoiceLinearIssueSink,
|
|
@@ -9095,13 +10313,18 @@ export {
|
|
|
9095
10313
|
createVoiceFileReviewStore,
|
|
9096
10314
|
createVoiceFileIntegrationEventStore,
|
|
9097
10315
|
createVoiceFileExternalObjectMapStore,
|
|
10316
|
+
createVoiceFileAssistantMemoryStore,
|
|
9098
10317
|
createVoiceExternalObjectMapId,
|
|
9099
10318
|
createVoiceExternalObjectMap,
|
|
10319
|
+
createVoiceExperiment,
|
|
9100
10320
|
createVoiceCallReviewRecorder,
|
|
9101
10321
|
createVoiceCallReviewFromSession,
|
|
9102
10322
|
createVoiceCallReviewFromLiveTelephonyReport,
|
|
9103
10323
|
createVoiceCallCompletedEvent,
|
|
9104
10324
|
createVoiceCRMActivitySink,
|
|
10325
|
+
createVoiceAssistantMemoryRecord,
|
|
10326
|
+
createVoiceAssistantMemoryHandle,
|
|
10327
|
+
createVoiceAssistant,
|
|
9105
10328
|
createVoiceAgentTool,
|
|
9106
10329
|
createVoiceAgentSquad,
|
|
9107
10330
|
createVoiceAgent,
|
|
@@ -9113,9 +10336,13 @@ export {
|
|
|
9113
10336
|
createStoredVoiceCallReviewArtifact,
|
|
9114
10337
|
createRiskyTurnCorrectionHandler,
|
|
9115
10338
|
createPhraseHintCorrectionHandler,
|
|
10339
|
+
createOpenAIVoiceAssistantModel,
|
|
10340
|
+
createJSONVoiceAssistantModel,
|
|
9116
10341
|
createId,
|
|
10342
|
+
createGeminiVoiceAssistantModel,
|
|
9117
10343
|
createDomainPhraseHints,
|
|
9118
10344
|
createDomainLexicon,
|
|
10345
|
+
createAnthropicVoiceAssistantModel,
|
|
9119
10346
|
conditionAudioChunk,
|
|
9120
10347
|
completeVoiceOpsTask,
|
|
9121
10348
|
claimVoiceOpsTask,
|