@absolutejs/voice 0.0.22-beta.3 → 0.0.22-beta.31
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/angular/index.d.ts +1 -0
- package/dist/angular/index.js +172 -2
- package/dist/angular/voice-provider-status.service.d.ts +12 -0
- package/dist/angular/voice-stream.service.d.ts +2 -0
- package/dist/assistant.d.ts +20 -0
- package/dist/assistantHealth.d.ts +81 -0
- package/dist/assistantMemory.d.ts +63 -0
- package/dist/client/actions.d.ts +22 -0
- package/dist/client/connection.d.ts +3 -0
- package/dist/client/htmxBootstrap.js +44 -2
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +125 -2
- package/dist/client/providerStatus.d.ts +19 -0
- package/dist/fileStore.d.ts +5 -2
- package/dist/handoff.d.ts +54 -0
- package/dist/handoffHealth.d.ts +94 -0
- package/dist/index.d.ts +20 -4
- package/dist/index.js +2509 -21
- package/dist/modelAdapters.d.ts +93 -0
- package/dist/opsWebhook.d.ts +126 -0
- package/dist/providerHealth.d.ts +78 -0
- package/dist/queue.d.ts +52 -0
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.js +148 -2
- package/dist/react/useVoiceController.d.ts +2 -0
- package/dist/react/useVoiceProviderStatus.d.ts +8 -0
- package/dist/react/useVoiceStream.d.ts +2 -0
- package/dist/sessionReplay.d.ts +175 -0
- package/dist/svelte/createVoiceProviderStatus.d.ts +8 -0
- package/dist/svelte/index.d.ts +1 -0
- package/dist/svelte/index.js +127 -2
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.js +1310 -7
- package/dist/testing/providerSimulator.d.ts +44 -0
- package/dist/trace.d.ts +1 -1
- package/dist/types.d.ts +84 -2
- package/dist/vue/index.d.ts +1 -0
- package/dist/vue/index.js +161 -2
- package/dist/vue/useVoiceProviderStatus.d.ts +9 -0
- package/dist/vue/useVoiceStream.d.ts +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { VoiceAgentModel, VoiceAgentModelInput, VoiceAgentModelOutput } from './agent';
|
|
2
|
+
import type { VoiceSessionRecord } from './types';
|
|
3
|
+
export type VoiceJSONAssistantModelHandler<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = (input: VoiceAgentModelInput<TContext, TSession>) => Promise<Record<string, unknown> | VoiceAgentModelOutput<TResult>> | Record<string, unknown> | VoiceAgentModelOutput<TResult>;
|
|
4
|
+
export type VoiceJSONAssistantModelOptions<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown> = {
|
|
5
|
+
generate: VoiceJSONAssistantModelHandler<TContext, TSession, TResult>;
|
|
6
|
+
mapOutput?: (output: Record<string, unknown>) => VoiceAgentModelOutput<TResult>;
|
|
7
|
+
};
|
|
8
|
+
export type OpenAIVoiceAssistantModelOptions = {
|
|
9
|
+
apiKey: string;
|
|
10
|
+
baseUrl?: string;
|
|
11
|
+
fetch?: typeof fetch;
|
|
12
|
+
maxOutputTokens?: number;
|
|
13
|
+
model?: string;
|
|
14
|
+
onUsage?: (usage: Record<string, unknown>) => Promise<void> | void;
|
|
15
|
+
temperature?: number;
|
|
16
|
+
};
|
|
17
|
+
export type AnthropicVoiceAssistantModelOptions = {
|
|
18
|
+
apiKey: string;
|
|
19
|
+
baseUrl?: string;
|
|
20
|
+
fetch?: typeof fetch;
|
|
21
|
+
maxOutputTokens?: number;
|
|
22
|
+
model?: string;
|
|
23
|
+
onUsage?: (usage: Record<string, unknown>) => Promise<void> | void;
|
|
24
|
+
temperature?: number;
|
|
25
|
+
version?: string;
|
|
26
|
+
};
|
|
27
|
+
export type GeminiVoiceAssistantModelOptions = {
|
|
28
|
+
apiKey: string;
|
|
29
|
+
baseUrl?: string;
|
|
30
|
+
fetch?: typeof fetch;
|
|
31
|
+
maxOutputTokens?: number;
|
|
32
|
+
maxRetries?: number;
|
|
33
|
+
model?: string;
|
|
34
|
+
onUsage?: (usage: Record<string, unknown>) => Promise<void> | void;
|
|
35
|
+
temperature?: number;
|
|
36
|
+
};
|
|
37
|
+
export type VoiceProviderRouterEvent<TProvider extends string = string> = {
|
|
38
|
+
at: number;
|
|
39
|
+
elapsedMs: number;
|
|
40
|
+
error?: string;
|
|
41
|
+
fallbackProvider?: TProvider;
|
|
42
|
+
provider: TProvider;
|
|
43
|
+
providerHealth?: VoiceProviderRouterProviderHealth<TProvider>;
|
|
44
|
+
rateLimited?: boolean;
|
|
45
|
+
recovered?: boolean;
|
|
46
|
+
selectedProvider: TProvider;
|
|
47
|
+
suppressionRemainingMs?: number;
|
|
48
|
+
suppressedUntil?: number;
|
|
49
|
+
status: 'error' | 'fallback' | 'success';
|
|
50
|
+
};
|
|
51
|
+
export type VoiceProviderRouterFallbackMode = 'never' | 'provider-error' | 'rate-limit';
|
|
52
|
+
export type VoiceProviderRouterPolicy<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TProvider extends string = string> = 'ordered' | 'prefer-cheapest' | 'prefer-fastest' | 'prefer-selected' | {
|
|
53
|
+
allowProviders?: readonly TProvider[] | ((input: VoiceAgentModelInput<TContext, TSession>) => readonly TProvider[] | Promise<readonly TProvider[]>);
|
|
54
|
+
fallbackMode?: VoiceProviderRouterFallbackMode;
|
|
55
|
+
strategy?: 'ordered' | 'prefer-cheapest' | 'prefer-fastest' | 'prefer-selected';
|
|
56
|
+
};
|
|
57
|
+
export type VoiceProviderRouterProviderProfile = {
|
|
58
|
+
cost?: number;
|
|
59
|
+
latencyMs?: number;
|
|
60
|
+
priority?: number;
|
|
61
|
+
};
|
|
62
|
+
export type VoiceProviderRouterHealthOptions = {
|
|
63
|
+
cooldownMs?: number;
|
|
64
|
+
failureThreshold?: number;
|
|
65
|
+
now?: () => number;
|
|
66
|
+
rateLimitCooldownMs?: number;
|
|
67
|
+
};
|
|
68
|
+
export type VoiceProviderRouterProviderHealth<TProvider extends string = string> = {
|
|
69
|
+
consecutiveFailures: number;
|
|
70
|
+
lastFailureAt?: number;
|
|
71
|
+
lastRateLimitedAt?: number;
|
|
72
|
+
provider: TProvider;
|
|
73
|
+
status: 'healthy' | 'suppressed';
|
|
74
|
+
suppressedUntil?: number;
|
|
75
|
+
};
|
|
76
|
+
export type VoiceProviderRouterOptions<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown, TProvider extends string = string> = {
|
|
77
|
+
allowProviders?: readonly TProvider[] | ((input: VoiceAgentModelInput<TContext, TSession>) => readonly TProvider[] | Promise<readonly TProvider[]>);
|
|
78
|
+
fallback?: TProvider[] | ((input: VoiceAgentModelInput<TContext, TSession>) => readonly TProvider[] | Promise<readonly TProvider[]>);
|
|
79
|
+
fallbackMode?: VoiceProviderRouterFallbackMode;
|
|
80
|
+
isProviderError?: (error: unknown, provider: TProvider) => boolean;
|
|
81
|
+
isRateLimitError?: (error: unknown, provider: TProvider) => boolean;
|
|
82
|
+
onProviderEvent?: (event: VoiceProviderRouterEvent<TProvider>, input: VoiceAgentModelInput<TContext, TSession>) => Promise<void> | void;
|
|
83
|
+
policy?: VoiceProviderRouterPolicy<TContext, TSession, TProvider>;
|
|
84
|
+
providerHealth?: boolean | VoiceProviderRouterHealthOptions;
|
|
85
|
+
providerProfiles?: Partial<Record<TProvider, VoiceProviderRouterProviderProfile>>;
|
|
86
|
+
providers: Partial<Record<TProvider, VoiceAgentModel<TContext, TSession, TResult>>>;
|
|
87
|
+
selectProvider?: (input: VoiceAgentModelInput<TContext, TSession>) => TProvider | undefined | Promise<TProvider | undefined>;
|
|
88
|
+
};
|
|
89
|
+
export declare const createJSONVoiceAssistantModel: <TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown>(options: VoiceJSONAssistantModelOptions<TContext, TSession, TResult>) => VoiceAgentModel<TContext, TSession, TResult>;
|
|
90
|
+
export declare const createVoiceProviderRouter: <TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown, TProvider extends string = string>(options: VoiceProviderRouterOptions<TContext, TSession, TResult, TProvider>) => VoiceAgentModel<TContext, TSession, TResult>;
|
|
91
|
+
export declare const createOpenAIVoiceAssistantModel: <TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown>(options: OpenAIVoiceAssistantModelOptions) => VoiceAgentModel<TContext, TSession, TResult>;
|
|
92
|
+
export declare const createAnthropicVoiceAssistantModel: <TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown>(options: AnthropicVoiceAssistantModelOptions) => VoiceAgentModel<TContext, TSession, TResult>;
|
|
93
|
+
export declare const createGeminiVoiceAssistantModel: <TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown>(options: GeminiVoiceAssistantModelOptions) => VoiceAgentModel<TContext, TSession, TResult>;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Elysia } from 'elysia';
|
|
2
|
+
import type { StoredVoiceIntegrationEvent, VoiceIntegrationEventType } from './ops';
|
|
3
|
+
import type { VoiceIntegrationHTTPSinkOptions, VoiceIntegrationSink } from './opsSinks';
|
|
4
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
5
|
+
export type VoiceOpsWebhookLinkResolver = string | ((input: {
|
|
6
|
+
event: StoredVoiceIntegrationEvent;
|
|
7
|
+
}) => MaybePromise<string | undefined>);
|
|
8
|
+
export type VoiceOpsWebhookEntity = {
|
|
9
|
+
disposition?: string;
|
|
10
|
+
outcome?: string;
|
|
11
|
+
priority?: string;
|
|
12
|
+
queue?: string;
|
|
13
|
+
reviewId?: string;
|
|
14
|
+
scenarioId?: string;
|
|
15
|
+
sessionId?: string;
|
|
16
|
+
status?: string;
|
|
17
|
+
target?: string;
|
|
18
|
+
taskId?: string;
|
|
19
|
+
};
|
|
20
|
+
export type VoiceOpsWebhookEnvelope = {
|
|
21
|
+
entity: VoiceOpsWebhookEntity;
|
|
22
|
+
event: {
|
|
23
|
+
createdAt: number;
|
|
24
|
+
id: string;
|
|
25
|
+
payload: Record<string, unknown>;
|
|
26
|
+
type: VoiceIntegrationEventType;
|
|
27
|
+
};
|
|
28
|
+
links?: {
|
|
29
|
+
event?: string;
|
|
30
|
+
replay?: string;
|
|
31
|
+
review?: string;
|
|
32
|
+
task?: string;
|
|
33
|
+
};
|
|
34
|
+
schemaVersion: 1;
|
|
35
|
+
source: 'absolutejs-voice';
|
|
36
|
+
};
|
|
37
|
+
export type VoiceOpsWebhookSinkOptions = Omit<VoiceIntegrationHTTPSinkOptions<VoiceOpsWebhookEnvelope>, 'body'> & {
|
|
38
|
+
baseUrl?: string;
|
|
39
|
+
eventHref?: VoiceOpsWebhookLinkResolver;
|
|
40
|
+
replayHref?: VoiceOpsWebhookLinkResolver;
|
|
41
|
+
reviewHref?: VoiceOpsWebhookLinkResolver;
|
|
42
|
+
taskHref?: VoiceOpsWebhookLinkResolver;
|
|
43
|
+
};
|
|
44
|
+
export type VoiceOpsWebhookVerificationResult = {
|
|
45
|
+
ok: true;
|
|
46
|
+
} | {
|
|
47
|
+
ok: false;
|
|
48
|
+
reason: 'invalid-signature' | 'missing-secret' | 'missing-signature' | 'missing-timestamp' | 'stale-timestamp' | 'unsupported-algorithm';
|
|
49
|
+
};
|
|
50
|
+
export type VoiceOpsWebhookReceiverRoutesOptions = {
|
|
51
|
+
onEnvelope?: (input: {
|
|
52
|
+
envelope: VoiceOpsWebhookEnvelope;
|
|
53
|
+
request: Request;
|
|
54
|
+
}) => MaybePromise<void>;
|
|
55
|
+
path?: string;
|
|
56
|
+
signingSecret?: string;
|
|
57
|
+
toleranceMs?: number;
|
|
58
|
+
};
|
|
59
|
+
export declare const createVoiceOpsWebhookEnvelope: (input: {
|
|
60
|
+
baseUrl?: string;
|
|
61
|
+
event: StoredVoiceIntegrationEvent;
|
|
62
|
+
eventHref?: VoiceOpsWebhookLinkResolver;
|
|
63
|
+
replayHref?: VoiceOpsWebhookLinkResolver;
|
|
64
|
+
reviewHref?: VoiceOpsWebhookLinkResolver;
|
|
65
|
+
taskHref?: VoiceOpsWebhookLinkResolver;
|
|
66
|
+
}) => Promise<VoiceOpsWebhookEnvelope>;
|
|
67
|
+
export declare const createVoiceOpsWebhookSink: (options: VoiceOpsWebhookSinkOptions) => VoiceIntegrationSink;
|
|
68
|
+
export declare const verifyVoiceOpsWebhookSignature: (input: {
|
|
69
|
+
body: string;
|
|
70
|
+
now?: number;
|
|
71
|
+
secret?: string;
|
|
72
|
+
signature?: string | null;
|
|
73
|
+
timestamp?: string | null;
|
|
74
|
+
toleranceMs?: number;
|
|
75
|
+
}) => Promise<VoiceOpsWebhookVerificationResult>;
|
|
76
|
+
export declare const createVoiceOpsWebhookReceiverRoutes: (options?: VoiceOpsWebhookReceiverRoutesOptions) => Elysia<"", {
|
|
77
|
+
decorator: {};
|
|
78
|
+
store: {};
|
|
79
|
+
derive: {};
|
|
80
|
+
resolve: {};
|
|
81
|
+
}, {
|
|
82
|
+
typebox: {};
|
|
83
|
+
error: {};
|
|
84
|
+
}, {
|
|
85
|
+
schema: {};
|
|
86
|
+
standaloneSchema: {};
|
|
87
|
+
macro: {};
|
|
88
|
+
macroFn: {};
|
|
89
|
+
parser: {};
|
|
90
|
+
response: {};
|
|
91
|
+
}, {
|
|
92
|
+
[x: string]: {
|
|
93
|
+
post: {
|
|
94
|
+
body: unknown;
|
|
95
|
+
params: {};
|
|
96
|
+
query: unknown;
|
|
97
|
+
headers: unknown;
|
|
98
|
+
response: {
|
|
99
|
+
200: {
|
|
100
|
+
ok: boolean;
|
|
101
|
+
reason: "invalid-signature" | "missing-secret" | "missing-signature" | "missing-timestamp" | "stale-timestamp" | "unsupported-algorithm";
|
|
102
|
+
eventId?: undefined;
|
|
103
|
+
type?: undefined;
|
|
104
|
+
} | {
|
|
105
|
+
eventId: string;
|
|
106
|
+
ok: boolean;
|
|
107
|
+
type: VoiceIntegrationEventType;
|
|
108
|
+
reason?: undefined;
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
}, {
|
|
114
|
+
derive: {};
|
|
115
|
+
resolve: {};
|
|
116
|
+
schema: {};
|
|
117
|
+
standaloneSchema: {};
|
|
118
|
+
response: {};
|
|
119
|
+
}, {
|
|
120
|
+
derive: {};
|
|
121
|
+
resolve: {};
|
|
122
|
+
schema: {};
|
|
123
|
+
standaloneSchema: {};
|
|
124
|
+
response: {};
|
|
125
|
+
}>;
|
|
126
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Elysia } from 'elysia';
|
|
2
|
+
import type { StoredVoiceTraceEvent, VoiceTraceEventStore } from './trace';
|
|
3
|
+
export type VoiceProviderHealthStatus = 'healthy' | 'idle' | 'rate-limited' | 'degraded' | 'recoverable' | 'suppressed';
|
|
4
|
+
export type VoiceProviderHealthSummary<TProvider extends string = string> = {
|
|
5
|
+
averageElapsedMs?: number;
|
|
6
|
+
errorCount: number;
|
|
7
|
+
fallbackCount: number;
|
|
8
|
+
lastError?: string;
|
|
9
|
+
lastErrorAt?: number;
|
|
10
|
+
lastSuccessAt?: number;
|
|
11
|
+
provider: TProvider;
|
|
12
|
+
rateLimited: boolean;
|
|
13
|
+
recommended: boolean;
|
|
14
|
+
runCount: number;
|
|
15
|
+
status: VoiceProviderHealthStatus;
|
|
16
|
+
suppressionRemainingMs?: number;
|
|
17
|
+
suppressedUntil?: number;
|
|
18
|
+
};
|
|
19
|
+
export type VoiceProviderHealthSummaryOptions<TProvider extends string = string> = {
|
|
20
|
+
events?: StoredVoiceTraceEvent[];
|
|
21
|
+
now?: number;
|
|
22
|
+
providers?: readonly TProvider[];
|
|
23
|
+
store?: VoiceTraceEventStore;
|
|
24
|
+
};
|
|
25
|
+
export type VoiceProviderHealthHandlerOptions<TProvider extends string = string> = VoiceProviderHealthSummaryOptions<TProvider>;
|
|
26
|
+
export type VoiceProviderHealthHTMLHandlerOptions<TProvider extends string = string> = VoiceProviderHealthHandlerOptions<TProvider> & {
|
|
27
|
+
headers?: HeadersInit;
|
|
28
|
+
render?: (providers: VoiceProviderHealthSummary<TProvider>[]) => string | Promise<string>;
|
|
29
|
+
};
|
|
30
|
+
export type VoiceProviderHealthRoutesOptions<TProvider extends string = string> = VoiceProviderHealthHTMLHandlerOptions<TProvider> & {
|
|
31
|
+
htmlPath?: false | string;
|
|
32
|
+
name?: string;
|
|
33
|
+
path?: string;
|
|
34
|
+
};
|
|
35
|
+
export declare const summarizeVoiceProviderHealth: <TProvider extends string = string>(input: StoredVoiceTraceEvent[] | VoiceProviderHealthSummaryOptions<TProvider>) => Promise<VoiceProviderHealthSummary<TProvider>[]>;
|
|
36
|
+
export declare const renderVoiceProviderHealthHTML: (providers: VoiceProviderHealthSummary[]) => string;
|
|
37
|
+
export declare const createVoiceProviderHealthJSONHandler: <TProvider extends string = string>(options: VoiceProviderHealthHandlerOptions<TProvider>) => () => Promise<VoiceProviderHealthSummary<TProvider>[]>;
|
|
38
|
+
export declare const createVoiceProviderHealthHTMLHandler: <TProvider extends string = string>(options: VoiceProviderHealthHTMLHandlerOptions<TProvider>) => () => Promise<Response>;
|
|
39
|
+
export declare const createVoiceProviderHealthRoutes: <TProvider extends string = string>(options: VoiceProviderHealthRoutesOptions<TProvider>) => Elysia<"", {
|
|
40
|
+
decorator: {};
|
|
41
|
+
store: {};
|
|
42
|
+
derive: {};
|
|
43
|
+
resolve: {};
|
|
44
|
+
}, {
|
|
45
|
+
typebox: {};
|
|
46
|
+
error: {};
|
|
47
|
+
}, {
|
|
48
|
+
schema: {};
|
|
49
|
+
standaloneSchema: {};
|
|
50
|
+
macro: {};
|
|
51
|
+
macroFn: {};
|
|
52
|
+
parser: {};
|
|
53
|
+
response: {};
|
|
54
|
+
}, {
|
|
55
|
+
[x: string]: {
|
|
56
|
+
get: {
|
|
57
|
+
body: unknown;
|
|
58
|
+
params: {};
|
|
59
|
+
query: unknown;
|
|
60
|
+
headers: unknown;
|
|
61
|
+
response: {
|
|
62
|
+
200: VoiceProviderHealthSummary<TProvider>[];
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
}, {
|
|
67
|
+
derive: {};
|
|
68
|
+
resolve: {};
|
|
69
|
+
schema: {};
|
|
70
|
+
standaloneSchema: {};
|
|
71
|
+
response: {};
|
|
72
|
+
}, {
|
|
73
|
+
derive: {};
|
|
74
|
+
resolve: {};
|
|
75
|
+
schema: {};
|
|
76
|
+
standaloneSchema: {};
|
|
77
|
+
response: {};
|
|
78
|
+
}>;
|
package/dist/queue.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { RedisClient } from 'bun';
|
|
2
2
|
import type { VoiceIntegrationSink } from './opsSinks';
|
|
3
3
|
import type { VoiceTraceRedactionConfig, VoiceTraceSink, VoiceTraceSinkDeliveryRecord, VoiceTraceSinkDeliveryStore, VoiceTraceSinkDeliveryQueueStatus } from './trace';
|
|
4
|
+
import type { StoredVoiceHandoffDelivery, VoiceHandoffAdapter, VoiceHandoffDeliveryQueueStatus, VoiceHandoffDeliveryStore, VoiceSessionHandle, VoiceSessionRecord } from './types';
|
|
4
5
|
import type { VoiceOpsTaskPriority, StoredVoiceOpsTask, StoredVoiceIntegrationEvent, VoiceIntegrationDeliveryStatus, VoiceIntegrationEventStore, VoiceIntegrationWebhookConfig, VoiceOpsTaskKind, VoiceOpsTaskStatus, VoiceOpsTaskStore } from './ops';
|
|
5
6
|
export type VoiceOpsTaskLease = {
|
|
6
7
|
expiresAt: number;
|
|
@@ -159,6 +160,50 @@ export type VoiceTraceSinkDeliveryQueueSummary = {
|
|
|
159
160
|
skipped: number;
|
|
160
161
|
total: number;
|
|
161
162
|
};
|
|
163
|
+
export type VoiceHandoffDeliveryWorkerOptions<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown, TDelivery extends StoredVoiceHandoffDelivery<TContext, TSession, TResult> = StoredVoiceHandoffDelivery<TContext, TSession, TResult>> = {
|
|
164
|
+
adapters: VoiceHandoffAdapter<TContext, TSession, TResult>[];
|
|
165
|
+
api: VoiceSessionHandle<TContext, TSession, TResult>;
|
|
166
|
+
deadLetters?: VoiceHandoffDeliveryStore<TDelivery>;
|
|
167
|
+
deliveries: VoiceHandoffDeliveryStore<TDelivery>;
|
|
168
|
+
failMode?: 'record' | 'throw';
|
|
169
|
+
idempotency?: VoiceIdempotencyStore;
|
|
170
|
+
idempotencyTtlSeconds?: number;
|
|
171
|
+
leaseMs?: number;
|
|
172
|
+
leases: VoiceRedisTaskLeaseCoordinator;
|
|
173
|
+
maxFailures?: number;
|
|
174
|
+
onDeadLetter?: (delivery: TDelivery) => Promise<void> | void;
|
|
175
|
+
statuses?: VoiceHandoffDeliveryQueueStatus[];
|
|
176
|
+
workerId: string;
|
|
177
|
+
};
|
|
178
|
+
export type VoiceHandoffDeliveryWorkerResult = {
|
|
179
|
+
alreadyProcessed: number;
|
|
180
|
+
attempted: number;
|
|
181
|
+
deadLettered: number;
|
|
182
|
+
delivered: number;
|
|
183
|
+
failed: number;
|
|
184
|
+
skipped: number;
|
|
185
|
+
};
|
|
186
|
+
export type VoiceHandoffDeliveryWorkerLoopOptions<TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown, TDelivery extends StoredVoiceHandoffDelivery<TContext, TSession, TResult> = StoredVoiceHandoffDelivery<TContext, TSession, TResult>> = {
|
|
187
|
+
onError?: (error: unknown) => Promise<void> | void;
|
|
188
|
+
pollIntervalMs?: number;
|
|
189
|
+
worker: ReturnType<typeof createVoiceHandoffDeliveryWorker<TContext, TSession, TResult, TDelivery>>;
|
|
190
|
+
};
|
|
191
|
+
export type VoiceHandoffDeliveryWorkerLoop = {
|
|
192
|
+
isRunning: () => boolean;
|
|
193
|
+
start: () => void;
|
|
194
|
+
stop: () => void;
|
|
195
|
+
tick: () => Promise<VoiceHandoffDeliveryWorkerResult>;
|
|
196
|
+
};
|
|
197
|
+
export type VoiceHandoffDeliveryQueueSummary = {
|
|
198
|
+
byAction: Array<[StoredVoiceHandoffDelivery['action'], number]>;
|
|
199
|
+
deadLettered: number;
|
|
200
|
+
delivered: number;
|
|
201
|
+
failed: number;
|
|
202
|
+
pending: number;
|
|
203
|
+
retryEligible: number;
|
|
204
|
+
skipped: number;
|
|
205
|
+
total: number;
|
|
206
|
+
};
|
|
162
207
|
export type VoiceOpsTaskWorkerOptions<TTask extends StoredVoiceOpsTask = StoredVoiceOpsTask> = {
|
|
163
208
|
leaseMs?: number;
|
|
164
209
|
leases: VoiceRedisTaskLeaseCoordinator;
|
|
@@ -252,6 +297,9 @@ export declare const summarizeVoiceIntegrationEvents: <TEvent extends StoredVoic
|
|
|
252
297
|
export declare const summarizeVoiceTraceSinkDeliveries: <TDelivery extends VoiceTraceSinkDeliveryRecord = VoiceTraceSinkDeliveryRecord>(deliveries: TDelivery[], input?: {
|
|
253
298
|
deadLetters?: VoiceTraceSinkDeliveryStore<TDelivery>;
|
|
254
299
|
}) => Promise<VoiceTraceSinkDeliveryQueueSummary> | VoiceTraceSinkDeliveryQueueSummary;
|
|
300
|
+
export declare const summarizeVoiceHandoffDeliveries: <TDelivery extends StoredVoiceHandoffDelivery = StoredVoiceHandoffDelivery>(deliveries: TDelivery[], input?: {
|
|
301
|
+
deadLetters?: VoiceHandoffDeliveryStore<TDelivery>;
|
|
302
|
+
}) => Promise<VoiceHandoffDeliveryQueueSummary> | VoiceHandoffDeliveryQueueSummary;
|
|
255
303
|
export declare const summarizeVoiceOpsTaskQueue: <TTask extends StoredVoiceOpsTask = StoredVoiceOpsTask>(tasks: TTask[], input?: {
|
|
256
304
|
deadLetters?: VoiceOpsTaskStore<TTask>;
|
|
257
305
|
}) => Promise<VoiceOpsTaskQueueSummary> | VoiceOpsTaskQueueSummary;
|
|
@@ -269,6 +317,10 @@ export declare const createVoiceTraceSinkDeliveryWorker: <TDelivery extends Voic
|
|
|
269
317
|
drain: () => Promise<VoiceTraceSinkDeliveryWorkerResult>;
|
|
270
318
|
};
|
|
271
319
|
export declare const createVoiceTraceSinkDeliveryWorkerLoop: <TDelivery extends VoiceTraceSinkDeliveryRecord = VoiceTraceSinkDeliveryRecord>(options: VoiceTraceSinkDeliveryWorkerLoopOptions<TDelivery>) => VoiceTraceSinkDeliveryWorkerLoop;
|
|
320
|
+
export declare const createVoiceHandoffDeliveryWorker: <TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown, TDelivery extends StoredVoiceHandoffDelivery<TContext, TSession, TResult> = StoredVoiceHandoffDelivery<TContext, TSession, TResult>>(options: VoiceHandoffDeliveryWorkerOptions<TContext, TSession, TResult, TDelivery>) => {
|
|
321
|
+
drain: () => Promise<VoiceHandoffDeliveryWorkerResult>;
|
|
322
|
+
};
|
|
323
|
+
export declare const createVoiceHandoffDeliveryWorkerLoop: <TContext = unknown, TSession extends VoiceSessionRecord = VoiceSessionRecord, TResult = unknown, TDelivery extends StoredVoiceHandoffDelivery<TContext, TSession, TResult> = StoredVoiceHandoffDelivery<TContext, TSession, TResult>>(options: VoiceHandoffDeliveryWorkerLoopOptions<TContext, TSession, TResult, TDelivery>) => VoiceHandoffDeliveryWorkerLoop;
|
|
272
324
|
export declare const createVoiceOpsTaskWorker: <TTask extends StoredVoiceOpsTask = StoredVoiceOpsTask>(options: VoiceOpsTaskWorkerOptions<TTask>) => VoiceOpsTaskWorker<TTask>;
|
|
273
325
|
export declare const createVoiceOpsTaskProcessorWorker: <TTask extends StoredVoiceOpsTask = StoredVoiceOpsTask>(options: VoiceOpsTaskProcessorWorkerOptions<TTask>) => {
|
|
274
326
|
drain: () => Promise<VoiceOpsTaskProcessorWorkerResult>;
|
package/dist/react/index.d.ts
CHANGED
package/dist/react/index.js
CHANGED
|
@@ -120,6 +120,12 @@ var serverMessageToAction = (message) => {
|
|
|
120
120
|
sessionId: message.sessionId,
|
|
121
121
|
type: "complete"
|
|
122
122
|
};
|
|
123
|
+
case "call_lifecycle":
|
|
124
|
+
return {
|
|
125
|
+
event: message.event,
|
|
126
|
+
sessionId: message.sessionId,
|
|
127
|
+
type: "call_lifecycle"
|
|
128
|
+
};
|
|
123
129
|
case "error":
|
|
124
130
|
return {
|
|
125
131
|
message: normalizeErrorMessage(message.message),
|
|
@@ -163,7 +169,7 @@ var DEFAULT_SCENARIO_QUERY_PARAM = "scenarioId";
|
|
|
163
169
|
var noop = () => {};
|
|
164
170
|
var noopUnsubscribe = () => noop;
|
|
165
171
|
var NOOP_CONNECTION = {
|
|
166
|
-
|
|
172
|
+
callControl: noop,
|
|
167
173
|
close: noop,
|
|
168
174
|
endTurn: noop,
|
|
169
175
|
getReadyState: () => WS_CLOSED,
|
|
@@ -171,6 +177,7 @@ var NOOP_CONNECTION = {
|
|
|
171
177
|
getSessionId: () => "",
|
|
172
178
|
send: noop,
|
|
173
179
|
sendAudio: noop,
|
|
180
|
+
start: () => {},
|
|
174
181
|
subscribe: noopUnsubscribe
|
|
175
182
|
};
|
|
176
183
|
var createSessionId = () => crypto.randomUUID();
|
|
@@ -192,6 +199,7 @@ var isVoiceServerMessage = (value) => {
|
|
|
192
199
|
switch (value.type) {
|
|
193
200
|
case "audio":
|
|
194
201
|
case "assistant":
|
|
202
|
+
case "call_lifecycle":
|
|
195
203
|
case "complete":
|
|
196
204
|
case "error":
|
|
197
205
|
case "final":
|
|
@@ -332,6 +340,12 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
332
340
|
const endTurn = () => {
|
|
333
341
|
send({ type: "end_turn" });
|
|
334
342
|
};
|
|
343
|
+
const callControl = (message) => {
|
|
344
|
+
send({
|
|
345
|
+
...message,
|
|
346
|
+
type: "call_control"
|
|
347
|
+
});
|
|
348
|
+
};
|
|
335
349
|
const close = () => {
|
|
336
350
|
clearTimers();
|
|
337
351
|
if (state.ws) {
|
|
@@ -349,7 +363,7 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
349
363
|
};
|
|
350
364
|
connect();
|
|
351
365
|
return {
|
|
352
|
-
|
|
366
|
+
callControl,
|
|
353
367
|
close,
|
|
354
368
|
endTurn,
|
|
355
369
|
getReadyState: () => state.ws?.readyState ?? WS_CLOSED,
|
|
@@ -357,6 +371,7 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
357
371
|
getSessionId: () => state.sessionId,
|
|
358
372
|
send,
|
|
359
373
|
sendAudio,
|
|
374
|
+
start,
|
|
360
375
|
subscribe
|
|
361
376
|
};
|
|
362
377
|
};
|
|
@@ -365,6 +380,7 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
365
380
|
var createInitialState = () => ({
|
|
366
381
|
assistantAudio: [],
|
|
367
382
|
assistantTexts: [],
|
|
383
|
+
call: null,
|
|
368
384
|
error: null,
|
|
369
385
|
isConnected: false,
|
|
370
386
|
scenarioId: null,
|
|
@@ -408,6 +424,20 @@ var createVoiceStreamStore = () => {
|
|
|
408
424
|
status: "completed"
|
|
409
425
|
};
|
|
410
426
|
break;
|
|
427
|
+
case "call_lifecycle":
|
|
428
|
+
state = {
|
|
429
|
+
...state,
|
|
430
|
+
call: {
|
|
431
|
+
...state.call,
|
|
432
|
+
disposition: action.event.type === "end" ? action.event.disposition : state.call?.disposition,
|
|
433
|
+
endedAt: action.event.type === "end" ? action.event.at : state.call?.endedAt,
|
|
434
|
+
events: [...state.call?.events ?? [], action.event],
|
|
435
|
+
lastEventAt: action.event.at,
|
|
436
|
+
startedAt: state.call?.startedAt ?? action.event.at
|
|
437
|
+
},
|
|
438
|
+
sessionId: action.sessionId
|
|
439
|
+
};
|
|
440
|
+
break;
|
|
411
441
|
case "connected":
|
|
412
442
|
state = {
|
|
413
443
|
...state,
|
|
@@ -494,6 +524,9 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
494
524
|
}
|
|
495
525
|
});
|
|
496
526
|
return {
|
|
527
|
+
callControl(message) {
|
|
528
|
+
connection.callControl(message);
|
|
529
|
+
},
|
|
497
530
|
close() {
|
|
498
531
|
unsubscribeConnection();
|
|
499
532
|
connection.close();
|
|
@@ -537,6 +570,9 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
537
570
|
get assistantAudio() {
|
|
538
571
|
return store.getSnapshot().assistantAudio;
|
|
539
572
|
},
|
|
573
|
+
get call() {
|
|
574
|
+
return store.getSnapshot().call;
|
|
575
|
+
},
|
|
540
576
|
sendAudio(audio) {
|
|
541
577
|
connection.sendAudio(audio);
|
|
542
578
|
},
|
|
@@ -553,6 +589,7 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
553
589
|
var EMPTY_SNAPSHOT = {
|
|
554
590
|
assistantAudio: [],
|
|
555
591
|
assistantTexts: [],
|
|
592
|
+
call: null,
|
|
556
593
|
error: null,
|
|
557
594
|
isConnected: false,
|
|
558
595
|
partial: "",
|
|
@@ -570,6 +607,7 @@ var useVoiceStream = (path, options = {}) => {
|
|
|
570
607
|
const snapshot = useSyncExternalStore(stream.subscribe, stream.getSnapshot, stream.getServerSnapshot) ?? EMPTY_SNAPSHOT;
|
|
571
608
|
return {
|
|
572
609
|
...snapshot,
|
|
610
|
+
callControl: (message) => stream.callControl(message),
|
|
573
611
|
close: () => stream.close(),
|
|
574
612
|
endTurn: () => stream.endTurn(),
|
|
575
613
|
sendAudio: (audio) => stream.sendAudio(audio)
|
|
@@ -1040,6 +1078,7 @@ var resolveVoiceRuntimePreset = (name = "default") => {
|
|
|
1040
1078
|
var createInitialState2 = (stream) => ({
|
|
1041
1079
|
assistantAudio: [...stream.assistantAudio],
|
|
1042
1080
|
assistantTexts: [...stream.assistantTexts],
|
|
1081
|
+
call: stream.call,
|
|
1043
1082
|
error: stream.error,
|
|
1044
1083
|
isConnected: stream.isConnected,
|
|
1045
1084
|
isRecording: false,
|
|
@@ -1069,6 +1108,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1069
1108
|
...state,
|
|
1070
1109
|
assistantAudio: [...stream.assistantAudio],
|
|
1071
1110
|
assistantTexts: [...stream.assistantTexts],
|
|
1111
|
+
call: stream.call,
|
|
1072
1112
|
error: stream.error,
|
|
1073
1113
|
isConnected: stream.isConnected,
|
|
1074
1114
|
partial: stream.partial,
|
|
@@ -1146,6 +1186,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1146
1186
|
bindHTMX(bindingOptions) {
|
|
1147
1187
|
return bindVoiceHTMX(stream, bindingOptions);
|
|
1148
1188
|
},
|
|
1189
|
+
callControl: (message) => stream.callControl(message),
|
|
1149
1190
|
close,
|
|
1150
1191
|
endTurn: () => stream.endTurn(),
|
|
1151
1192
|
get error() {
|
|
@@ -1198,6 +1239,9 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1198
1239
|
},
|
|
1199
1240
|
get assistantAudio() {
|
|
1200
1241
|
return state.assistantAudio;
|
|
1242
|
+
},
|
|
1243
|
+
get call() {
|
|
1244
|
+
return state.call;
|
|
1201
1245
|
}
|
|
1202
1246
|
};
|
|
1203
1247
|
};
|
|
@@ -1206,6 +1250,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1206
1250
|
var EMPTY_SNAPSHOT2 = {
|
|
1207
1251
|
assistantAudio: [],
|
|
1208
1252
|
assistantTexts: [],
|
|
1253
|
+
call: null,
|
|
1209
1254
|
error: null,
|
|
1210
1255
|
isConnected: false,
|
|
1211
1256
|
isRecording: false,
|
|
@@ -1226,6 +1271,7 @@ var useVoiceController = (path, options = {}) => {
|
|
|
1226
1271
|
return {
|
|
1227
1272
|
...snapshot,
|
|
1228
1273
|
bindHTMX: controller.bindHTMX,
|
|
1274
|
+
callControl: (message) => controller.callControl(message),
|
|
1229
1275
|
close: () => controller.close(),
|
|
1230
1276
|
endTurn: () => controller.endTurn(),
|
|
1231
1277
|
sendAudio: (audio) => controller.sendAudio(audio),
|
|
@@ -1234,7 +1280,107 @@ var useVoiceController = (path, options = {}) => {
|
|
|
1234
1280
|
toggleRecording: () => controller.toggleRecording()
|
|
1235
1281
|
};
|
|
1236
1282
|
};
|
|
1283
|
+
// src/react/useVoiceProviderStatus.tsx
|
|
1284
|
+
import { useEffect as useEffect3, useRef as useRef3, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
1285
|
+
|
|
1286
|
+
// src/client/providerStatus.ts
|
|
1287
|
+
var fetchVoiceProviderStatus = async (path = "/api/provider-status", options = {}) => {
|
|
1288
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
1289
|
+
const response = await fetchImpl(path);
|
|
1290
|
+
if (!response.ok) {
|
|
1291
|
+
throw new Error(`Voice provider status failed: HTTP ${response.status}`);
|
|
1292
|
+
}
|
|
1293
|
+
return await response.json();
|
|
1294
|
+
};
|
|
1295
|
+
var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {}) => {
|
|
1296
|
+
const listeners = new Set;
|
|
1297
|
+
let closed = false;
|
|
1298
|
+
let timer;
|
|
1299
|
+
let snapshot = {
|
|
1300
|
+
error: null,
|
|
1301
|
+
isLoading: false,
|
|
1302
|
+
providers: []
|
|
1303
|
+
};
|
|
1304
|
+
const emit = () => {
|
|
1305
|
+
for (const listener of listeners) {
|
|
1306
|
+
listener();
|
|
1307
|
+
}
|
|
1308
|
+
};
|
|
1309
|
+
const refresh = async () => {
|
|
1310
|
+
if (closed) {
|
|
1311
|
+
return snapshot.providers;
|
|
1312
|
+
}
|
|
1313
|
+
snapshot = {
|
|
1314
|
+
...snapshot,
|
|
1315
|
+
error: null,
|
|
1316
|
+
isLoading: true
|
|
1317
|
+
};
|
|
1318
|
+
emit();
|
|
1319
|
+
try {
|
|
1320
|
+
const providers = await fetchVoiceProviderStatus(path, options);
|
|
1321
|
+
snapshot = {
|
|
1322
|
+
error: null,
|
|
1323
|
+
isLoading: false,
|
|
1324
|
+
providers,
|
|
1325
|
+
updatedAt: Date.now()
|
|
1326
|
+
};
|
|
1327
|
+
emit();
|
|
1328
|
+
return providers;
|
|
1329
|
+
} catch (error) {
|
|
1330
|
+
snapshot = {
|
|
1331
|
+
...snapshot,
|
|
1332
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1333
|
+
isLoading: false
|
|
1334
|
+
};
|
|
1335
|
+
emit();
|
|
1336
|
+
throw error;
|
|
1337
|
+
}
|
|
1338
|
+
};
|
|
1339
|
+
const close = () => {
|
|
1340
|
+
closed = true;
|
|
1341
|
+
if (timer) {
|
|
1342
|
+
clearInterval(timer);
|
|
1343
|
+
timer = undefined;
|
|
1344
|
+
}
|
|
1345
|
+
listeners.clear();
|
|
1346
|
+
};
|
|
1347
|
+
if (options.intervalMs && options.intervalMs > 0) {
|
|
1348
|
+
timer = setInterval(() => {
|
|
1349
|
+
refresh().catch(() => {});
|
|
1350
|
+
}, options.intervalMs);
|
|
1351
|
+
}
|
|
1352
|
+
return {
|
|
1353
|
+
close,
|
|
1354
|
+
getServerSnapshot: () => snapshot,
|
|
1355
|
+
getSnapshot: () => snapshot,
|
|
1356
|
+
refresh,
|
|
1357
|
+
subscribe: (listener) => {
|
|
1358
|
+
listeners.add(listener);
|
|
1359
|
+
return () => {
|
|
1360
|
+
listeners.delete(listener);
|
|
1361
|
+
};
|
|
1362
|
+
}
|
|
1363
|
+
};
|
|
1364
|
+
};
|
|
1365
|
+
|
|
1366
|
+
// src/react/useVoiceProviderStatus.tsx
|
|
1367
|
+
var useVoiceProviderStatus = (path = "/api/provider-status", options = {}) => {
|
|
1368
|
+
const storeRef = useRef3(null);
|
|
1369
|
+
if (!storeRef.current) {
|
|
1370
|
+
storeRef.current = createVoiceProviderStatusStore(path, options);
|
|
1371
|
+
}
|
|
1372
|
+
const store = storeRef.current;
|
|
1373
|
+
useEffect3(() => {
|
|
1374
|
+
store.refresh().catch(() => {});
|
|
1375
|
+
return () => store.close();
|
|
1376
|
+
}, [store]);
|
|
1377
|
+
return {
|
|
1378
|
+
...useSyncExternalStore3(store.subscribe, store.getSnapshot, store.getServerSnapshot),
|
|
1379
|
+
refresh: store.refresh
|
|
1380
|
+
};
|
|
1381
|
+
};
|
|
1237
1382
|
export {
|
|
1238
1383
|
useVoiceStream,
|
|
1384
|
+
useVoiceProviderStatus,
|
|
1239
1385
|
useVoiceController
|
|
1240
1386
|
};
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { VoiceControllerOptions } from '../types';
|
|
2
2
|
export declare const useVoiceController: <TResult = unknown>(path: string, options?: VoiceControllerOptions) => {
|
|
3
3
|
bindHTMX: (options: import("..").VoiceHTMXBindingOptions) => () => void;
|
|
4
|
+
callControl: (message: Parameters<(message: Omit<import("..").VoiceClientCallControlMessage, "type">) => void>[0]) => void;
|
|
4
5
|
close: () => void;
|
|
5
6
|
endTurn: () => void;
|
|
6
7
|
sendAudio: (audio: Uint8Array | ArrayBuffer) => void;
|
|
7
8
|
startRecording: () => Promise<void>;
|
|
8
9
|
stopRecording: () => void;
|
|
9
10
|
toggleRecording: () => Promise<void>;
|
|
11
|
+
call: import("..").VoiceCallLifecycleState | null;
|
|
10
12
|
sessionId: string | null;
|
|
11
13
|
scenarioId: string | null;
|
|
12
14
|
status: import("..").VoiceSessionStatus | "idle";
|