@absolutejs/voice 0.0.22-beta.122 → 0.0.22-beta.123
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 +17 -1
- package/dist/agent.d.ts +17 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +94 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -563,7 +563,21 @@ const billingAgent = createVoiceAgent({
|
|
|
563
563
|
const frontDesk = createVoiceAgentSquad({
|
|
564
564
|
id: 'front-desk',
|
|
565
565
|
defaultAgentId: 'support',
|
|
566
|
-
agents: [supportAgent, billingAgent]
|
|
566
|
+
agents: [supportAgent, billingAgent],
|
|
567
|
+
handoffPolicy: ({ handoff }) => {
|
|
568
|
+
if (handoff.targetAgentId === 'billing') {
|
|
569
|
+
return {
|
|
570
|
+
summary: 'Route verified billing requests to the billing specialist.',
|
|
571
|
+
metadata: { queue: 'billing' }
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
return {
|
|
576
|
+
allow: false,
|
|
577
|
+
reason: `No approved route for ${handoff.targetAgentId}.`,
|
|
578
|
+
escalate: { reason: 'unsupported-specialist' }
|
|
579
|
+
};
|
|
580
|
+
}
|
|
567
581
|
});
|
|
568
582
|
|
|
569
583
|
voice({
|
|
@@ -577,6 +591,8 @@ voice({
|
|
|
577
591
|
|
|
578
592
|
`createVoiceAgentSquad(...)` gives you squad-style specialization without locking your app into a hosted voice platform. An agent can return `handoff: { targetAgentId: 'billing' }`; the squad records the handoff, runs the target agent on the same turn, and still returns a standard `VoiceRouteResult`.
|
|
579
593
|
|
|
594
|
+
For production call centers, pass `handoffPolicy` to keep routing code-owned instead of dashboard-owned. The policy can allow a handoff, reroute it to a different specialist, merge handoff metadata, summarize the reason for the target agent, or block the handoff and return an escalation. Squad traces mark each handoff as `allowed`, `blocked`, `unknown-target`, or `max-exceeded`, so support teams can audit why a caller moved between specialists.
|
|
595
|
+
|
|
580
596
|
## Traces And Replay
|
|
581
597
|
|
|
582
598
|
Use trace stores when you want every call to be inspectable outside a hosted platform. Trace events are append-only records for model passes, tool calls, handoffs, agent results, call lifecycle, turn timing, errors, and cost telemetry.
|
package/dist/agent.d.ts
CHANGED
|
@@ -66,6 +66,14 @@ export type VoiceAgentRunResult<TResult = unknown> = VoiceRouteResult<TResult> &
|
|
|
66
66
|
messages: VoiceAgentMessage[];
|
|
67
67
|
toolResults: VoiceAgentToolResult[];
|
|
68
68
|
};
|
|
69
|
+
export type VoiceAgentSquadHandoffPolicyResult<TResult = unknown> = {
|
|
70
|
+
allow?: boolean;
|
|
71
|
+
escalate?: VoiceRouteResult<TResult>['escalate'];
|
|
72
|
+
metadata?: Record<string, unknown>;
|
|
73
|
+
reason?: string;
|
|
74
|
+
summary?: string;
|
|
75
|
+
targetAgentId?: string;
|
|
76
|
+
};
|
|
69
77
|
export type VoiceAgent<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = {
|
|
70
78
|
id: string;
|
|
71
79
|
onTurn: VoiceOnTurnObjectHandler<TContext, TSession, TResult>;
|
|
@@ -93,6 +101,15 @@ export type VoiceAgentOptions<TContext = unknown, TSession extends VoiceSessionR
|
|
|
93
101
|
export type VoiceAgentSquadOptions<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = {
|
|
94
102
|
agents: Array<VoiceAgent<TContext, TSession, TResult>>;
|
|
95
103
|
defaultAgentId: string;
|
|
104
|
+
handoffPolicy?: (input: {
|
|
105
|
+
context: TContext;
|
|
106
|
+
fromAgentId: string;
|
|
107
|
+
handoff: NonNullable<VoiceAgentModelOutput<TResult>['handoff']>;
|
|
108
|
+
messages: VoiceAgentMessage[];
|
|
109
|
+
session: TSession;
|
|
110
|
+
targetAgent?: VoiceAgent<TContext, TSession, TResult>;
|
|
111
|
+
turn: VoiceTurnRecord;
|
|
112
|
+
}) => Promise<VoiceAgentSquadHandoffPolicyResult<TResult> | void> | VoiceAgentSquadHandoffPolicyResult<TResult> | void;
|
|
96
113
|
id: string;
|
|
97
114
|
maxHandoffsPerTurn?: number;
|
|
98
115
|
onHandoff?: (input: {
|
package/dist/index.d.ts
CHANGED
|
@@ -81,7 +81,7 @@ export type { VoiceProductionReadinessAction, VoiceProductionReadinessCheck, Voi
|
|
|
81
81
|
export type { VoiceQualityLink, VoiceQualityMetric, VoiceQualityReport, VoiceQualityRoutesOptions, VoiceQualityStatus, VoiceQualityThresholds } from './qualityRoutes';
|
|
82
82
|
export type { VoiceResilienceIOSimulator, VoiceResilienceLink, VoiceResiliencePageData, VoiceResilienceRoutesOptions, VoiceResilienceSimulationProvider, VoiceRoutingKindSummary, VoiceRoutingDecisionSummary, VoiceRoutingDecisionSummaryOptions, VoiceRoutingEvent, VoiceRoutingEventKind, VoiceRoutingSessionSummary, VoiceRoutingSessionSummaryOptions } from './resilienceRoutes';
|
|
83
83
|
export type { VoiceIOProviderRouterEvent, VoiceIOProviderRouterOptions, VoiceIOProviderRouterPolicy, VoiceIOProviderRouterPolicyConfig, VoiceSTTProviderRouterOptions, VoiceTTSProviderRouterOptions } from './providerAdapters';
|
|
84
|
-
export type { VoiceAgent, VoiceAgentMessage, VoiceAgentMessageRole, VoiceAgentModel, VoiceAgentModelInput, VoiceAgentModelOutput, VoiceAgentOptions, VoiceAgentRunResult, VoiceAgentSquadOptions, VoiceAgentTool, VoiceAgentToolCall, VoiceAgentToolResult } from './agent';
|
|
84
|
+
export type { VoiceAgent, VoiceAgentMessage, VoiceAgentMessageRole, VoiceAgentModel, VoiceAgentModelInput, VoiceAgentModelOutput, VoiceAgentOptions, VoiceAgentRunResult, VoiceAgentSquadHandoffPolicyResult, VoiceAgentSquadOptions, VoiceAgentTool, VoiceAgentToolCall, VoiceAgentToolResult } from './agent';
|
|
85
85
|
export type { VoiceToolRetryDelay, VoiceToolRuntime, VoiceToolRuntimeExecuteInput, VoiceToolRuntimeOptions, VoiceToolRuntimeResult } from './toolRuntime';
|
|
86
86
|
export type { VoiceToolContractCase, VoiceToolContractCaseReport, VoiceToolContractDefinition, VoiceToolContractExpectation, VoiceToolContractHandlerOptions, VoiceToolContractHTMLHandlerOptions, VoiceToolContractIssue, VoiceToolContractReport, VoiceToolContractRoutesOptions, VoiceToolContractSuiteReport } from './toolContract';
|
|
87
87
|
export type { VoiceOpsRuntime, VoiceOpsRuntimeConfig, VoiceOpsRuntimeSummary, VoiceOpsRuntimeSinkWorkerConfig, VoiceOpsRuntimeTaskWorkerConfig, VoiceOpsRuntimeTickResult, VoiceOpsRuntimeWebhookWorkerConfig } from './opsRuntime';
|
package/dist/index.js
CHANGED
|
@@ -5827,21 +5827,80 @@ var createVoiceAgentSquad = (options) => {
|
|
|
5827
5827
|
});
|
|
5828
5828
|
toolResults.push(...result.toolResults);
|
|
5829
5829
|
for (let handoffCount = 0;result.handoff && handoffCount < maxHandoffs; handoffCount += 1) {
|
|
5830
|
-
const
|
|
5830
|
+
const originalTargetAgentId = result.handoff.targetAgentId;
|
|
5831
|
+
const policy = await options.handoffPolicy?.({
|
|
5832
|
+
context: input.context,
|
|
5833
|
+
fromAgentId: agent.id,
|
|
5834
|
+
handoff: result.handoff,
|
|
5835
|
+
messages,
|
|
5836
|
+
session: input.session,
|
|
5837
|
+
targetAgent: agents.get(originalTargetAgentId),
|
|
5838
|
+
turn: input.turn
|
|
5839
|
+
});
|
|
5840
|
+
const targetAgentId = normalizeText3(policy?.targetAgentId) || originalTargetAgentId;
|
|
5841
|
+
const nextAgent = agents.get(targetAgentId);
|
|
5842
|
+
const handoffReason = policy?.summary ?? policy?.reason ?? result.handoff.reason;
|
|
5843
|
+
const handoffMetadata = {
|
|
5844
|
+
...result.handoff.metadata,
|
|
5845
|
+
...policy?.metadata
|
|
5846
|
+
};
|
|
5847
|
+
const metadata = Object.keys(handoffMetadata).length > 0 ? handoffMetadata : undefined;
|
|
5848
|
+
if (policy?.allow === false) {
|
|
5849
|
+
await appendVoiceAgentTrace({
|
|
5850
|
+
agentId: options.id,
|
|
5851
|
+
event: {
|
|
5852
|
+
fromAgentId: agent.id,
|
|
5853
|
+
metadata,
|
|
5854
|
+
originalTargetAgentId,
|
|
5855
|
+
reason: handoffReason,
|
|
5856
|
+
status: "blocked",
|
|
5857
|
+
targetAgentId
|
|
5858
|
+
},
|
|
5859
|
+
session: input.session,
|
|
5860
|
+
trace: options.trace,
|
|
5861
|
+
turn: input.turn,
|
|
5862
|
+
type: "agent.handoff"
|
|
5863
|
+
});
|
|
5864
|
+
return {
|
|
5865
|
+
...result,
|
|
5866
|
+
escalate: result.escalate ?? policy.escalate ?? {
|
|
5867
|
+
metadata,
|
|
5868
|
+
reason: handoffReason ?? `Blocked handoff to ${targetAgentId}`
|
|
5869
|
+
},
|
|
5870
|
+
handoff: undefined,
|
|
5871
|
+
toolResults
|
|
5872
|
+
};
|
|
5873
|
+
}
|
|
5831
5874
|
if (!nextAgent) {
|
|
5875
|
+
await appendVoiceAgentTrace({
|
|
5876
|
+
agentId: options.id,
|
|
5877
|
+
event: {
|
|
5878
|
+
fromAgentId: agent.id,
|
|
5879
|
+
metadata,
|
|
5880
|
+
originalTargetAgentId,
|
|
5881
|
+
reason: handoffReason,
|
|
5882
|
+
status: "unknown-target",
|
|
5883
|
+
targetAgentId
|
|
5884
|
+
},
|
|
5885
|
+
session: input.session,
|
|
5886
|
+
trace: options.trace,
|
|
5887
|
+
turn: input.turn,
|
|
5888
|
+
type: "agent.handoff"
|
|
5889
|
+
});
|
|
5832
5890
|
return {
|
|
5833
5891
|
...result,
|
|
5834
5892
|
escalate: result.escalate ?? {
|
|
5835
|
-
metadata
|
|
5836
|
-
reason: `Unknown handoff target: ${
|
|
5893
|
+
metadata,
|
|
5894
|
+
reason: `Unknown handoff target: ${targetAgentId}`
|
|
5837
5895
|
},
|
|
5896
|
+
handoff: undefined,
|
|
5838
5897
|
toolResults
|
|
5839
5898
|
};
|
|
5840
5899
|
}
|
|
5841
5900
|
await options.onHandoff?.({
|
|
5842
5901
|
context: input.context,
|
|
5843
5902
|
fromAgentId: agent.id,
|
|
5844
|
-
reason:
|
|
5903
|
+
reason: handoffReason,
|
|
5845
5904
|
session: input.session,
|
|
5846
5905
|
targetAgentId: nextAgent.id,
|
|
5847
5906
|
turn: input.turn
|
|
@@ -5850,7 +5909,10 @@ var createVoiceAgentSquad = (options) => {
|
|
|
5850
5909
|
agentId: options.id,
|
|
5851
5910
|
event: {
|
|
5852
5911
|
fromAgentId: agent.id,
|
|
5853
|
-
|
|
5912
|
+
metadata,
|
|
5913
|
+
originalTargetAgentId: originalTargetAgentId === nextAgent.id ? undefined : originalTargetAgentId,
|
|
5914
|
+
reason: handoffReason,
|
|
5915
|
+
status: "allowed",
|
|
5854
5916
|
targetAgentId: nextAgent.id
|
|
5855
5917
|
},
|
|
5856
5918
|
session: input.session,
|
|
@@ -5859,8 +5921,8 @@ var createVoiceAgentSquad = (options) => {
|
|
|
5859
5921
|
type: "agent.handoff"
|
|
5860
5922
|
});
|
|
5861
5923
|
messages.push({
|
|
5862
|
-
content:
|
|
5863
|
-
metadata
|
|
5924
|
+
content: handoffReason ?? `Handoff to ${nextAgent.id}`,
|
|
5925
|
+
metadata,
|
|
5864
5926
|
name: nextAgent.id,
|
|
5865
5927
|
role: "system"
|
|
5866
5928
|
});
|
|
@@ -5872,6 +5934,31 @@ var createVoiceAgentSquad = (options) => {
|
|
|
5872
5934
|
});
|
|
5873
5935
|
toolResults.push(...result.toolResults);
|
|
5874
5936
|
}
|
|
5937
|
+
if (result.handoff) {
|
|
5938
|
+
await appendVoiceAgentTrace({
|
|
5939
|
+
agentId: options.id,
|
|
5940
|
+
event: {
|
|
5941
|
+
fromAgentId: agent.id,
|
|
5942
|
+
metadata: result.handoff.metadata,
|
|
5943
|
+
reason: result.handoff.reason,
|
|
5944
|
+
status: "max-exceeded",
|
|
5945
|
+
targetAgentId: result.handoff.targetAgentId
|
|
5946
|
+
},
|
|
5947
|
+
session: input.session,
|
|
5948
|
+
trace: options.trace,
|
|
5949
|
+
turn: input.turn,
|
|
5950
|
+
type: "agent.handoff"
|
|
5951
|
+
});
|
|
5952
|
+
return {
|
|
5953
|
+
...result,
|
|
5954
|
+
escalate: result.escalate ?? {
|
|
5955
|
+
metadata: result.handoff.metadata,
|
|
5956
|
+
reason: `Max handoffs exceeded: ${maxHandoffs}`
|
|
5957
|
+
},
|
|
5958
|
+
handoff: undefined,
|
|
5959
|
+
toolResults
|
|
5960
|
+
};
|
|
5961
|
+
}
|
|
5875
5962
|
return {
|
|
5876
5963
|
...result,
|
|
5877
5964
|
agentId,
|