@open-everywhere/adapters 0.5.0 → 0.7.0
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/agent/directory/okta.ts +41 -2
- package/agent/meetings/native-http.ts +72 -0
- package/agent/meetings/native-meet.ts +173 -0
- package/agent/meetings/native-sources.ts +14 -0
- package/agent/meetings/native-teams.ts +119 -0
- package/agent/meetings/native-zoom.ts +98 -0
- package/agent/model/gateway.ts +44 -4
- package/agent/model/meeting-gateway.ts +88 -0
- package/agent/model/transcription-routes.ts +347 -0
- package/agent/oe-oauth/config.ts +71 -3
- package/agent/oe-oauth/errors.ts +17 -0
- package/agent/oe-oauth/oauth-client.ts +118 -2
- package/agent/oe-oauth/token-vault.ts +359 -8
- package/agent/register-defaults.ts +11 -0
- package/agent/sandbox/long-lived-box.ts +464 -0
- package/dist/agent/directory/okta.d.ts +10 -0
- package/dist/agent/directory/okta.d.ts.map +1 -1
- package/dist/agent/directory/okta.js +34 -2
- package/dist/agent/directory/okta.js.map +1 -1
- package/dist/agent/meetings/native-http.d.ts +22 -0
- package/dist/agent/meetings/native-http.d.ts.map +1 -0
- package/dist/agent/meetings/native-http.js +61 -0
- package/dist/agent/meetings/native-http.js.map +1 -0
- package/dist/agent/meetings/native-meet.d.ts +6 -0
- package/dist/agent/meetings/native-meet.d.ts.map +1 -0
- package/dist/agent/meetings/native-meet.js +176 -0
- package/dist/agent/meetings/native-meet.js.map +1 -0
- package/dist/agent/meetings/native-sources.d.ts +2 -0
- package/dist/agent/meetings/native-sources.d.ts.map +1 -0
- package/dist/agent/meetings/native-sources.js +13 -0
- package/dist/agent/meetings/native-sources.js.map +1 -0
- package/dist/agent/meetings/native-teams.d.ts +6 -0
- package/dist/agent/meetings/native-teams.d.ts.map +1 -0
- package/dist/agent/meetings/native-teams.js +118 -0
- package/dist/agent/meetings/native-teams.js.map +1 -0
- package/dist/agent/meetings/native-zoom.d.ts +7 -0
- package/dist/agent/meetings/native-zoom.d.ts.map +1 -0
- package/dist/agent/meetings/native-zoom.js +98 -0
- package/dist/agent/meetings/native-zoom.js.map +1 -0
- package/dist/agent/model/gateway.d.ts +10 -0
- package/dist/agent/model/gateway.d.ts.map +1 -1
- package/dist/agent/model/gateway.js +43 -5
- package/dist/agent/model/gateway.js.map +1 -1
- package/dist/agent/model/meeting-gateway.d.ts +24 -0
- package/dist/agent/model/meeting-gateway.d.ts.map +1 -0
- package/dist/agent/model/meeting-gateway.js +75 -0
- package/dist/agent/model/meeting-gateway.js.map +1 -0
- package/dist/agent/model/transcription-routes.d.ts +89 -0
- package/dist/agent/model/transcription-routes.d.ts.map +1 -0
- package/dist/agent/model/transcription-routes.js +279 -0
- package/dist/agent/model/transcription-routes.js.map +1 -0
- package/dist/agent/oe-oauth/config.d.ts +28 -2
- package/dist/agent/oe-oauth/config.d.ts.map +1 -1
- package/dist/agent/oe-oauth/config.js +40 -1
- package/dist/agent/oe-oauth/config.js.map +1 -1
- package/dist/agent/oe-oauth/errors.d.ts +14 -0
- package/dist/agent/oe-oauth/errors.d.ts.map +1 -1
- package/dist/agent/oe-oauth/errors.js +15 -0
- package/dist/agent/oe-oauth/errors.js.map +1 -1
- package/dist/agent/oe-oauth/oauth-client.d.ts +46 -0
- package/dist/agent/oe-oauth/oauth-client.d.ts.map +1 -1
- package/dist/agent/oe-oauth/oauth-client.js +82 -1
- package/dist/agent/oe-oauth/oauth-client.js.map +1 -1
- package/dist/agent/oe-oauth/token-vault.d.ts +15 -0
- package/dist/agent/oe-oauth/token-vault.d.ts.map +1 -1
- package/dist/agent/oe-oauth/token-vault.js +317 -7
- package/dist/agent/oe-oauth/token-vault.js.map +1 -1
- package/dist/agent/register-defaults.d.ts.map +1 -1
- package/dist/agent/register-defaults.js +9 -0
- package/dist/agent/register-defaults.js.map +1 -1
- package/dist/agent/sandbox/long-lived-box.d.ts +70 -0
- package/dist/agent/sandbox/long-lived-box.d.ts.map +1 -0
- package/dist/agent/sandbox/long-lived-box.js +414 -0
- package/dist/agent/sandbox/long-lived-box.js.map +1 -0
- package/package.json +39 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// The Vercel AI Gateway model backend — the reference `ModelBackend`. Provider SELECTION is not pinned here:
|
|
2
2
|
// that is a gateway-operator concern, and `ModelRoute.providers` is only an optional per-route preference.
|
|
3
3
|
import { gateway, createGateway } from "ai";
|
|
4
|
-
import { hostPlaneFetch, liveIdentity, resolvePrimaryModel, } from "@open-everywhere/core/agent/adapter-api.js";
|
|
4
|
+
import { hostPlaneFetch, hostPlanePolicy, liveIdentity, resolvePrimaryModel, } from "@open-everywhere/core/agent/adapter-api.js";
|
|
5
5
|
/**
|
|
6
6
|
* THE GATEWAY TARGET — `OE_AI_GATEWAY_URL`, read once at module load: a target that changed mid-process would
|
|
7
7
|
* send two calls in one turn to two providers. Unset ⇒ the plain `gateway` export, byte-identical.
|
|
@@ -20,13 +20,46 @@ export function gatewayHost(baseUrl) {
|
|
|
20
20
|
return DEFAULT_GATEWAY_HOST;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
+
/** The one host this deployment's gateway calls reach — what every host-plane push must keep declaring. */
|
|
24
|
+
export const GATEWAY_TARGET_HOST = gatewayHost(GATEWAY_BASE_URL);
|
|
25
|
+
/**
|
|
26
|
+
* THE HOST-PLANE UNION (OPE-2470). The proxy REPLACES its host plane on every push; it never merges
|
|
27
|
+
* (deploy/egress-proxy/control/handlers.ts `setHostPlane`). So this process keeps ONE host set, and every
|
|
28
|
+
* host-plane call goes through ONE fetch that pushes the whole set: the turn model and the meeting bot's
|
|
29
|
+
* non-gateway transcription routes never push lists that drop each other. A caller adds its hosts with
|
|
30
|
+
* {@link sharedHostPlaneFetch} at boot; a grown set builds a new fetch, which pushes the union on its next call.
|
|
31
|
+
*/
|
|
32
|
+
const HOST_PLANE_HOSTS = [GATEWAY_TARGET_HOST];
|
|
33
|
+
let hostPlaneCurrent = hostPlaneFetch(HOST_PLANE_HOSTS);
|
|
34
|
+
let hostPlaneBuiltFor = HOST_PLANE_HOSTS.length;
|
|
23
35
|
/**
|
|
24
36
|
* THE MODEL CALL'S TRANSPORT ON THE SELF-HOST PROXY TIER (OPE-2406). With an egress proxy wired, the model call goes out
|
|
25
|
-
* on the app's HOST PLANE: the proxy decides it against the gateway host
|
|
26
|
-
*
|
|
27
|
-
*
|
|
37
|
+
* on the app's HOST PLANE: the proxy decides it against the host-plane list (the gateway host, plus the hosts of any
|
|
38
|
+
* non-gateway transcription route the app registers), never against a session's policy. That is what lets a turn reach
|
|
39
|
+
* its model while the session stays default-deny. Off that tier it is `undefined` and the provider keeps its default
|
|
40
|
+
* fetch, byte-identical to before. On it, the fetch always uses the newest union.
|
|
28
41
|
*/
|
|
29
|
-
const HOST_PLANE_FETCH =
|
|
42
|
+
const HOST_PLANE_FETCH = hostPlaneCurrent === undefined
|
|
43
|
+
? undefined
|
|
44
|
+
: (input, init) => {
|
|
45
|
+
if (hostPlaneBuiltFor !== HOST_PLANE_HOSTS.length) {
|
|
46
|
+
hostPlaneCurrent = hostPlaneFetch(HOST_PLANE_HOSTS);
|
|
47
|
+
hostPlaneBuiltFor = HOST_PLANE_HOSTS.length;
|
|
48
|
+
}
|
|
49
|
+
return hostPlaneCurrent(input, init);
|
|
50
|
+
};
|
|
51
|
+
/** Add `hosts` to this process's host plane and return the shared fetch (undefined off the proxy tier). */
|
|
52
|
+
export function sharedHostPlaneFetch(hosts) {
|
|
53
|
+
// Validate BEFORE the list grows: a wildcard host throws here, at registration, and never reaches the shared list,
|
|
54
|
+
// where it would fail every model turn at the next rebuild. A blank name is skipped.
|
|
55
|
+
const named = hosts.map((h) => h.trim()).filter((h) => h !== "");
|
|
56
|
+
if (HOST_PLANE_FETCH !== undefined)
|
|
57
|
+
hostPlanePolicy([...HOST_PLANE_HOSTS, ...named]);
|
|
58
|
+
for (const h of named)
|
|
59
|
+
if (!HOST_PLANE_HOSTS.includes(h))
|
|
60
|
+
HOST_PLANE_HOSTS.push(h);
|
|
61
|
+
return HOST_PLANE_FETCH;
|
|
62
|
+
}
|
|
30
63
|
/** The gateway provider this backend resolves model ids through — retargeted only when
|
|
31
64
|
* {@link GATEWAY_BASE_URL} names a different host. */
|
|
32
65
|
const provider = GATEWAY_BASE_URL || HOST_PLANE_FETCH
|
|
@@ -54,6 +87,11 @@ export function applyGatewayOptions(route, options, ids, defaults) {
|
|
|
54
87
|
return options;
|
|
55
88
|
return { ...options, providerOptions: { ...options.providerOptions, gateway: gatewayOpts } };
|
|
56
89
|
}
|
|
90
|
+
/** A gateway TRANSCRIPTION model, on the same provider (retarget and host-plane fetch included) the turn
|
|
91
|
+
* model uses. The meeting bot's `gateway` route (meeting-gateway.ts) reads it. */
|
|
92
|
+
export function gatewayTranscriptionModel(id) {
|
|
93
|
+
return provider.transcriptionModel(id);
|
|
94
|
+
}
|
|
57
95
|
/** The gateway ModelBackend (see core ModelBackend). */
|
|
58
96
|
export function gatewayModelBackend(defaults) {
|
|
59
97
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway.js","sourceRoot":"","sources":["../../../agent/model/gateway.ts"],"names":[],"mappings":"AAAA,6GAA6G;AAC7G,2GAA2G;AAE3G,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAC5C,OAAO,EAKL,cAAc,EACd,YAAY,EACZ,mBAAmB,GACpB,MAAM,4CAA4C,CAAC;AAIpD;;;GAGG;AACH,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,IAAI,EAAE,CAAC;AAE/D,wHAAwH;AACxH,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAE3D,0IAA0I;AAC1I,MAAM,UAAU,WAAW,CAAC,OAA2B;IACrD,IAAI,CAAC,OAAO;QAAE,OAAO,oBAAoB,CAAC;IAC1C,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,oBAAoB,CAAC;IAC9B,CAAC;AACH,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"gateway.js","sourceRoot":"","sources":["../../../agent/model/gateway.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type TranscriptionInput, type TranscriptionRoute } from "@open-everywhere/core/agent/adapter-api.js";
|
|
2
|
+
import { type GatewayRoutedDefaults } from "./gateway.js";
|
|
3
|
+
import { type RoleTranscript, type TranscriptionDeps, type TranscriptionRoleSpec } from "./transcription-routes.js";
|
|
4
|
+
/** The injectable transcription call, so the legacy route is testable with no network. */
|
|
5
|
+
export type TranscribeCall = (modelId: string, audio: Uint8Array, mediaType: string) => Promise<string>;
|
|
6
|
+
/** The legacy one-model route: the policy's `transcription.model` through the AI Gateway, with no fallback. */
|
|
7
|
+
export declare function gatewayTranscriptionRoute(call?: TranscribeCall): TranscriptionRoute;
|
|
8
|
+
/**
|
|
9
|
+
* The stack route: the core seam's `transcribe` (text only), plus `transcribeTimed`, which keeps the word and segment
|
|
10
|
+
* timestamps for the speaker alignment (OPE-2469) and says which route answered.
|
|
11
|
+
*/
|
|
12
|
+
export interface TimedTranscriptionRoute extends TranscriptionRoute {
|
|
13
|
+
transcribeTimed(input: TranscriptionInput, opts: {
|
|
14
|
+
readonly scope: string;
|
|
15
|
+
readonly prompt?: string;
|
|
16
|
+
}): Promise<RoleTranscript>;
|
|
17
|
+
}
|
|
18
|
+
export declare function stackTranscriptionRoute(role: TranscriptionRoleSpec, deps?: TranscriptionDeps): TimedTranscriptionRoute;
|
|
19
|
+
/**
|
|
20
|
+
* Boot registration from agent.ts, beside the dream judge: the recap rides the `utility` defaults, and the
|
|
21
|
+
* transcription route rides the stack's transcription role when the app passes one.
|
|
22
|
+
*/
|
|
23
|
+
export declare function registerGatewayMeetingModels(defaults: GatewayRoutedDefaults, transcription?: TranscriptionRoleSpec): void;
|
|
24
|
+
//# sourceMappingURL=meeting-gateway.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meeting-gateway.d.ts","sourceRoot":"","sources":["../../../agent/model/meeting-gateway.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAiF,KAAK,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,MAAM,4CAA4C,CAAC;AAC7L,OAAO,EAA6B,KAAK,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAErF,OAAO,EAA0C,KAAK,cAAc,EAAE,KAAK,iBAAiB,EAAE,KAAK,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAE5J,0FAA0F;AAC1F,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAQxG,+GAA+G;AAC/G,wBAAgB,yBAAyB,CAAC,IAAI,GAAE,cAAkC,GAAG,kBAAkB,CAUtG;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAwB,SAAQ,kBAAkB;IACjE,eAAe,CAAC,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACjI;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,qBAAqB,EAAE,IAAI,GAAE,iBAAsB,GAAG,uBAAuB,CAc1H;AAeD;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,qBAAqB,EAAE,aAAa,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAGzH"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// The meeting bot's two model calls (OPE-2459): the `gateway` transcription route, and the recap completion.
|
|
2
|
+
// Core owns both seams (meetings/transcription.ts); this file only fills them, so no meeting code calls a model SDK.
|
|
3
|
+
//
|
|
4
|
+
// TRANSCRIPTION (OPE-2470): one audio chunk per call, along the STACK'S TRANSCRIPTION ROLE — a primary route and a
|
|
5
|
+
// fallback route (transcription-routes.ts), named per stack in the app's `agent/model/stacks.ts`. A provider outage
|
|
6
|
+
// on the primary falls through to the fallback. The policy's route id stays `gateway` (core validates the id), but
|
|
7
|
+
// the role decides where the audio goes, and the approval card's sentence is derived from the role. With a role
|
|
8
|
+
// registered, the policy's `transcription.model` is NOT read.
|
|
9
|
+
//
|
|
10
|
+
// LEGACY: `registerGatewayMeetingModels(defaults)` with no role keeps the one-model route on the policy's
|
|
11
|
+
// `transcription.model`, for an app that has no transcription role yet.
|
|
12
|
+
//
|
|
13
|
+
// RECAP: one tool-less completion on the scope's `utility` route — the same route and call shape the dream
|
|
14
|
+
// judge uses. The prompt carries the fenced, untrusted transcript (core meetings/recap.ts).
|
|
15
|
+
import { experimental_transcribe as transcribe, generateText, gateway } from "ai";
|
|
16
|
+
import { registerMeetingCompletion, registerTranscriptionRoute } from "@open-everywhere/core/agent/adapter-api.js";
|
|
17
|
+
import { gatewayTranscriptionModel } from "./gateway.js";
|
|
18
|
+
import { resolvedDreamCallSettings } from "./dream-judge.js";
|
|
19
|
+
import { roleDisclosure, transcribeWithFallback } from "./transcription-routes.js";
|
|
20
|
+
// The SDK reads the container format from the bytes themselves, so the media type is not forwarded.
|
|
21
|
+
const defaultTranscribe = async (modelId, audio) => {
|
|
22
|
+
const result = await transcribe({ model: gatewayTranscriptionModel(modelId), audio });
|
|
23
|
+
return result.text;
|
|
24
|
+
};
|
|
25
|
+
/** The legacy one-model route: the policy's `transcription.model` through the AI Gateway, with no fallback. */
|
|
26
|
+
export function gatewayTranscriptionRoute(call = defaultTranscribe) {
|
|
27
|
+
return {
|
|
28
|
+
id: "gateway",
|
|
29
|
+
disclosure: "Audio goes, one minute at a time, through this deployment's own AI Gateway to its transcription model.",
|
|
30
|
+
async transcribe(input, opts) {
|
|
31
|
+
if (input.kind !== "audio")
|
|
32
|
+
throw new Error("the gateway transcription route transcribes audio — this bot sent text");
|
|
33
|
+
if (opts.model === undefined)
|
|
34
|
+
throw new Error("the gateway transcription route needs transcription.model in the meeting policy");
|
|
35
|
+
return await call(opts.model, input.data, input.mediaType);
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function stackTranscriptionRoute(role, deps = {}) {
|
|
40
|
+
const run = transcribeWithFallback(role, deps);
|
|
41
|
+
const timed = async (input, opts) => {
|
|
42
|
+
if (input.kind !== "audio")
|
|
43
|
+
throw new Error("the gateway transcription route transcribes audio — this bot sent text");
|
|
44
|
+
return await run({ audio: input.data, mediaType: input.mediaType, ...(opts.prompt !== undefined ? { prompt: opts.prompt } : {}) });
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
id: "gateway",
|
|
48
|
+
disclosure: roleDisclosure(role),
|
|
49
|
+
transcribeTimed: timed,
|
|
50
|
+
async transcribe(input, opts) {
|
|
51
|
+
return (await timed(input, { scope: opts.scope })).text;
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function gatewayMeetingCompletion(defaults) {
|
|
56
|
+
return async (scope, prompt) => {
|
|
57
|
+
const s = resolvedDreamCallSettings(scope, defaults);
|
|
58
|
+
const { text } = await generateText({
|
|
59
|
+
model: gateway(s.id),
|
|
60
|
+
prompt,
|
|
61
|
+
...(s.reasoning !== undefined ? { reasoning: s.reasoning } : {}),
|
|
62
|
+
...(s.providerOptions !== undefined ? { providerOptions: s.providerOptions } : {}),
|
|
63
|
+
});
|
|
64
|
+
return text;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Boot registration from agent.ts, beside the dream judge: the recap rides the `utility` defaults, and the
|
|
69
|
+
* transcription route rides the stack's transcription role when the app passes one.
|
|
70
|
+
*/
|
|
71
|
+
export function registerGatewayMeetingModels(defaults, transcription) {
|
|
72
|
+
registerTranscriptionRoute(transcription === undefined ? gatewayTranscriptionRoute() : stackTranscriptionRoute(transcription));
|
|
73
|
+
registerMeetingCompletion(gatewayMeetingCompletion(defaults));
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=meeting-gateway.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meeting-gateway.js","sourceRoot":"","sources":["../../../agent/model/meeting-gateway.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/** How a route reaches its model. */
|
|
2
|
+
export type TranscriptionVia = "gateway" | "deepinfra" | "self-hosted";
|
|
3
|
+
/** One route of the transcription role. */
|
|
4
|
+
export interface TranscriptionRouteSpec {
|
|
5
|
+
readonly via: TranscriptionVia;
|
|
6
|
+
/** The model: a gateway id (`gateway`), a DeepInfra model path (`deepinfra`), or the served model name (`self-hosted`). */
|
|
7
|
+
readonly id: string;
|
|
8
|
+
/** The server's OpenAI-compatible base URL, e.g. `http://qwen3-asr:8000/v1`. Required for `self-hosted`, refused elsewhere. */
|
|
9
|
+
readonly baseUrl?: string;
|
|
10
|
+
}
|
|
11
|
+
/** The transcription role of one stack: a primary route and an optional fallback route. */
|
|
12
|
+
export interface TranscriptionRoleSpec {
|
|
13
|
+
readonly primary: TranscriptionRouteSpec;
|
|
14
|
+
readonly fallback?: TranscriptionRouteSpec;
|
|
15
|
+
}
|
|
16
|
+
/** One timed span of the transcript, in seconds from the start of the chunk. */
|
|
17
|
+
export interface TimedSpan {
|
|
18
|
+
readonly text: string;
|
|
19
|
+
readonly startSecond: number;
|
|
20
|
+
readonly endSecond: number;
|
|
21
|
+
}
|
|
22
|
+
/** One chunk's transcript. `words` and `segments` are empty when the route returns no timestamps. */
|
|
23
|
+
export interface TimedTranscript {
|
|
24
|
+
readonly text: string;
|
|
25
|
+
readonly segments: readonly TimedSpan[];
|
|
26
|
+
readonly words: readonly TimedSpan[];
|
|
27
|
+
readonly durationSeconds?: number;
|
|
28
|
+
/** The provider's own cost for the call, in USD, when it reports one (the Gateway and DeepInfra do). */
|
|
29
|
+
readonly costUsd?: number;
|
|
30
|
+
}
|
|
31
|
+
/** What one route call receives. `prompt` is context text (the previous chunk's tail, names) for a model that takes one. */
|
|
32
|
+
export interface TranscribeRequest {
|
|
33
|
+
readonly audio: Uint8Array;
|
|
34
|
+
readonly mediaType: string;
|
|
35
|
+
readonly prompt?: string;
|
|
36
|
+
readonly abortSignal?: AbortSignal;
|
|
37
|
+
}
|
|
38
|
+
/** The injectable seams, so every transport is testable with no network. */
|
|
39
|
+
export interface TranscriptionDeps {
|
|
40
|
+
/** The `gateway` transport. Default: the AI SDK's `transcribe` on the deployment's gateway provider. */
|
|
41
|
+
readonly gateway?: (modelId: string, req: TranscribeRequest) => Promise<TimedTranscript>;
|
|
42
|
+
/** The HTTP client for `deepinfra` and `self-hosted`. Default: the host-plane fetch on the proxy tier, else `fetch`. */
|
|
43
|
+
readonly fetch?: typeof fetch;
|
|
44
|
+
/** The host-plane seam: declare hosts, get the proxy-tier fetch (undefined off the tier). Default: gateway.ts `sharedHostPlaneFetch`. */
|
|
45
|
+
readonly hostPlane?: (hosts: readonly string[]) => typeof fetch | undefined;
|
|
46
|
+
/** Resolve the DeepInfra key. Default: {@link storeOnlySecret}. */
|
|
47
|
+
readonly secret?: (name: string) => Promise<string>;
|
|
48
|
+
/** One attempt's time limit, ms. Default {@link ATTEMPT_TIMEOUT_MS}. */
|
|
49
|
+
readonly attemptTimeoutMs?: number;
|
|
50
|
+
/** Where a fall-through is reported. Default: `console.warn`. */
|
|
51
|
+
readonly warn?: (message: string) => void;
|
|
52
|
+
}
|
|
53
|
+
/** The secret-store name of the DeepInfra key. A fixed name in code, so no config line can point it at another secret. */
|
|
54
|
+
export declare const DEEPINFRA_SECRET = "DEEPINFRA_API_KEY";
|
|
55
|
+
/** Refuse a malformed route at boot, not at the first chunk of a live meeting. */
|
|
56
|
+
export declare function assertTranscriptionRole(role: TranscriptionRoleSpec): void;
|
|
57
|
+
/** The approval card's sentence: every place the audio can go, in the order it is tried. */
|
|
58
|
+
export declare function roleDisclosure(role: TranscriptionRoleSpec): string;
|
|
59
|
+
/**
|
|
60
|
+
* Resolve a key from the DB-backed secret store, and from nothing else.
|
|
61
|
+
*
|
|
62
|
+
* `getOperatorSecret` falls back to an env var of the same name (its migration on-ramp). The DeepInfra key is not
|
|
63
|
+
* infrastructure, so it has no env home: a value that resolved from the environment is refused, and the refusal
|
|
64
|
+
* names the fix. The same rule as the SIEM export token (core audit/siem-export.ts).
|
|
65
|
+
*/
|
|
66
|
+
export declare function storeOnlySecret(name: string, resolve?: (name: string) => Promise<{
|
|
67
|
+
readonly value: string;
|
|
68
|
+
readonly source: string;
|
|
69
|
+
}>): Promise<string>;
|
|
70
|
+
/** Parse an OpenAI-compatible `verbose_json` body, or DeepInfra's native body (the same field names). */
|
|
71
|
+
export declare function parseTranscriptionBody(body: unknown): TimedTranscript;
|
|
72
|
+
/**
|
|
73
|
+
* The hosts a role's routes reach on the host plane: the gateway host FIRST, then every non-gateway route host.
|
|
74
|
+
* They join the process-wide host set in gateway.ts (`sharedHostPlaneFetch`), so the one shared fetch pushes the
|
|
75
|
+
* union and neither the turn model nor a transcription route drops the other's host.
|
|
76
|
+
*/
|
|
77
|
+
export declare function roleHostPlaneHosts(role: TranscriptionRoleSpec): string[];
|
|
78
|
+
/** The transport for one route. Exported for the bake-off harness, which calls each route on its own. */
|
|
79
|
+
export declare function routeTransport(r: TranscriptionRouteSpec, deps?: TranscriptionDeps): (req: TranscribeRequest) => Promise<TimedTranscript>;
|
|
80
|
+
/** Which route answered. */
|
|
81
|
+
export interface RoleTranscript extends TimedTranscript {
|
|
82
|
+
readonly answeredBy: "primary" | "fallback";
|
|
83
|
+
readonly route: TranscriptionRouteSpec;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Build the role's transcriber: primary, then fallback on any failure. The routes are validated here, at build time.
|
|
87
|
+
*/
|
|
88
|
+
export declare function transcribeWithFallback(role: TranscriptionRoleSpec, deps?: TranscriptionDeps): (req: TranscribeRequest) => Promise<RoleTranscript>;
|
|
89
|
+
//# sourceMappingURL=transcription-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcription-routes.d.ts","sourceRoot":"","sources":["../../../agent/model/transcription-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
// THE TRANSCRIPTION ROLE'S TRANSPORTS (OPE-2470) — speech to text as a model-stack role with a primary and a
|
|
2
|
+
// fallback route. The app's `agent/model/stacks.ts` names the routes per stack; this file sends one audio chunk
|
|
3
|
+
// along them and returns the text with its timestamps.
|
|
4
|
+
//
|
|
5
|
+
// THREE TRANSPORTS. Each route names one:
|
|
6
|
+
// • `gateway` — the deployment's own AI Gateway (`gatewayTranscriptionModel`, the same provider and the same
|
|
7
|
+
// host plane as the turn model). The Gateway returns segments with start and end seconds; on
|
|
8
|
+
// `spacexai/grok-stt` each segment is one word (probed 2026-10-11).
|
|
9
|
+
// • `deepinfra` — DeepInfra's native inference endpoint for an open-weights speech model. It returns `segments`
|
|
10
|
+
// and `words`, each with `start` and `end` in seconds (DeepInfra's API page, 2026-10-11). The
|
|
11
|
+
// key is the `DEEPINFRA_API_KEY` entry of the DB secret store (`oe secret set`), and NEVER the
|
|
12
|
+
// environment: see {@link storeOnlySecret}.
|
|
13
|
+
// • `self-hosted` — an OpenAI-compatible `/audio/transcriptions` server that the deployer runs (vLLM serving
|
|
14
|
+
// Qwen3-ASR). Its base URL is config in the stack, not a secret. The call asks for
|
|
15
|
+
// `verbose_json` with word and segment timestamps and keeps whatever the server returns.
|
|
16
|
+
//
|
|
17
|
+
// THE FALLBACK. {@link transcribeWithFallback} tries the primary route, and on ANY failure (an outage, a 4xx from a
|
|
18
|
+
// provider allow-list, a timeout) tries the fallback route. Both fail ⇒ it throws one error that names both. It
|
|
19
|
+
// never tries a third route: the stack names what may hear the meeting, and nothing else may.
|
|
20
|
+
//
|
|
21
|
+
// 🔴 THE DISCLOSURE IS DERIVED. The approval card shows {@link roleDisclosure}, built from the SAME route list the
|
|
22
|
+
// call walks, so the card cannot name one provider while the audio goes to another.
|
|
23
|
+
import { experimental_transcribe as transcribe } from "ai";
|
|
24
|
+
import { getOperatorSecret } from "@open-everywhere/core/agent/adapter-api.js";
|
|
25
|
+
import { GATEWAY_TARGET_HOST, gatewayTranscriptionModel, sharedHostPlaneFetch } from "./gateway.js";
|
|
26
|
+
/** The secret-store name of the DeepInfra key. A fixed name in code, so no config line can point it at another secret. */
|
|
27
|
+
export const DEEPINFRA_SECRET = "DEEPINFRA_API_KEY";
|
|
28
|
+
const DEEPINFRA_HOST = "api.deepinfra.com";
|
|
29
|
+
/**
|
|
30
|
+
* One attempt's limit. A chunk is at most about 75 seconds of audio, and the probed routes answer a 20-second chunk
|
|
31
|
+
* in about one second. 40 seconds per attempt keeps primary plus fallback inside 80 seconds, so a hung provider
|
|
32
|
+
* falls through instead of holding the chunk.
|
|
33
|
+
*/
|
|
34
|
+
const ATTEMPT_TIMEOUT_MS = 40_000;
|
|
35
|
+
/** Refuse a malformed route at boot, not at the first chunk of a live meeting. */
|
|
36
|
+
export function assertTranscriptionRole(role) {
|
|
37
|
+
for (const [slot, r] of [["primary", role.primary], ["fallback", role.fallback]]) {
|
|
38
|
+
if (r === undefined)
|
|
39
|
+
continue;
|
|
40
|
+
if (r.id.trim() === "")
|
|
41
|
+
throw new Error(`transcription ${slot} route: the model id is empty`);
|
|
42
|
+
if (r.via === "self-hosted") {
|
|
43
|
+
if (r.baseUrl === undefined)
|
|
44
|
+
throw new Error(`transcription ${slot} route: a self-hosted route needs baseUrl`);
|
|
45
|
+
const u = new URL(r.baseUrl);
|
|
46
|
+
if (u.protocol !== "http:" && u.protocol !== "https:")
|
|
47
|
+
throw new Error(`transcription ${slot} route: baseUrl must be http or https`);
|
|
48
|
+
if (u.username !== "" || u.password !== "")
|
|
49
|
+
throw new Error(`transcription ${slot} route: baseUrl must not carry credentials`);
|
|
50
|
+
}
|
|
51
|
+
else if (r.baseUrl !== undefined) {
|
|
52
|
+
throw new Error(`transcription ${slot} route: baseUrl is for a self-hosted route only`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** The host a route's audio reaches. */
|
|
57
|
+
function routeHost(r) {
|
|
58
|
+
if (r.via === "deepinfra")
|
|
59
|
+
return DEEPINFRA_HOST;
|
|
60
|
+
if (r.via === "self-hosted")
|
|
61
|
+
return new URL(r.baseUrl ?? "").hostname;
|
|
62
|
+
return "the AI Gateway";
|
|
63
|
+
}
|
|
64
|
+
function routePhrase(r) {
|
|
65
|
+
if (r.via === "gateway")
|
|
66
|
+
return `this deployment's own AI Gateway to \`${r.id}\``;
|
|
67
|
+
if (r.via === "deepinfra")
|
|
68
|
+
return `DeepInfra (${DEEPINFRA_HOST}) to \`${r.id}\``;
|
|
69
|
+
return `this deployment's own speech server at ${routeHost(r)} (\`${r.id}\`)`;
|
|
70
|
+
}
|
|
71
|
+
/** The approval card's sentence: every place the audio can go, in the order it is tried. */
|
|
72
|
+
export function roleDisclosure(role) {
|
|
73
|
+
const head = `Audio goes, in chunks of about a minute, through ${routePhrase(role.primary)}.`;
|
|
74
|
+
return role.fallback === undefined ? head : `${head} If that fails, it goes through ${routePhrase(role.fallback)} instead.`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Resolve a key from the DB-backed secret store, and from nothing else.
|
|
78
|
+
*
|
|
79
|
+
* `getOperatorSecret` falls back to an env var of the same name (its migration on-ramp). The DeepInfra key is not
|
|
80
|
+
* infrastructure, so it has no env home: a value that resolved from the environment is refused, and the refusal
|
|
81
|
+
* names the fix. The same rule as the SIEM export token (core audit/siem-export.ts).
|
|
82
|
+
*/
|
|
83
|
+
export async function storeOnlySecret(name, resolve = getOperatorSecret) {
|
|
84
|
+
const resolved = await resolve(name);
|
|
85
|
+
if (resolved.source !== "db") {
|
|
86
|
+
throw new Error(`secret "${name}" resolves only from the environment; the DeepInfra transcription route reads the secret store and nothing else. Store it with \`oe secret set ${name}\``);
|
|
87
|
+
}
|
|
88
|
+
return resolved.value;
|
|
89
|
+
}
|
|
90
|
+
// ── wire parsing ────────────────────────────────────────────────────────────────────────────────────
|
|
91
|
+
function num(v) {
|
|
92
|
+
if (typeof v === "number" && Number.isFinite(v))
|
|
93
|
+
return v;
|
|
94
|
+
if (typeof v === "string" && v.trim() !== "" && Number.isFinite(Number(v)))
|
|
95
|
+
return Number(v);
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
/** Read `[{text|word, start, end}]` into spans. An entry without a finite start and end is dropped. */
|
|
99
|
+
function parseSpans(raw) {
|
|
100
|
+
if (!Array.isArray(raw))
|
|
101
|
+
return [];
|
|
102
|
+
const out = [];
|
|
103
|
+
for (const e of raw) {
|
|
104
|
+
if (e === null || typeof e !== "object")
|
|
105
|
+
continue;
|
|
106
|
+
const text = typeof e.text === "string" ? e.text : typeof e.word === "string" ? e.word : undefined;
|
|
107
|
+
const start = num(e.start ?? e.startSecond);
|
|
108
|
+
const end = num(e.end ?? e.endSecond);
|
|
109
|
+
if (text === undefined || start === undefined || end === undefined || end < start)
|
|
110
|
+
continue;
|
|
111
|
+
out.push({ text: text.trim(), startSecond: start, endSecond: end });
|
|
112
|
+
}
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
115
|
+
/** True when every span holds one word. Then the segments are word timestamps (the Gateway's grok-stt shape). */
|
|
116
|
+
function spansAreWords(spans) {
|
|
117
|
+
return spans.length > 0 && spans.every((s) => s.text !== "" && !/\s/.test(s.text));
|
|
118
|
+
}
|
|
119
|
+
/** Parse an OpenAI-compatible `verbose_json` body, or DeepInfra's native body (the same field names). */
|
|
120
|
+
export function parseTranscriptionBody(body) {
|
|
121
|
+
if (body === null || typeof body !== "object")
|
|
122
|
+
throw new Error("transcription response is not a JSON object");
|
|
123
|
+
const b = body;
|
|
124
|
+
if (typeof b.text !== "string")
|
|
125
|
+
throw new Error("transcription response has no text");
|
|
126
|
+
const segments = parseSpans(b.segments);
|
|
127
|
+
const words = parseSpans(b.words);
|
|
128
|
+
const status = b.inference_status;
|
|
129
|
+
const cost = num(status?.cost);
|
|
130
|
+
const duration = num(b.duration);
|
|
131
|
+
return {
|
|
132
|
+
text: b.text.trim(),
|
|
133
|
+
segments,
|
|
134
|
+
words: words.length > 0 ? words : spansAreWords(segments) ? segments : [],
|
|
135
|
+
...(duration !== undefined ? { durationSeconds: duration } : {}),
|
|
136
|
+
...(cost !== undefined ? { costUsd: cost } : {}),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/** `fetch` looked up at call time, so instrumentation that wraps it after boot still sees the call. */
|
|
140
|
+
const lateFetch = (input, init) => globalThis.fetch(input, init);
|
|
141
|
+
// ── transports ──────────────────────────────────────────────────────────────────────────────────────
|
|
142
|
+
const defaultGateway = async (modelId, req) => {
|
|
143
|
+
// The SDK reads the container format from the bytes themselves, so the media type is not forwarded. The prompt is
|
|
144
|
+
// not forwarded either: the Gateway takes no common prompt field for transcription models.
|
|
145
|
+
const r = await transcribe({ model: gatewayTranscriptionModel(modelId), audio: req.audio, ...(req.abortSignal ? { abortSignal: req.abortSignal } : {}) });
|
|
146
|
+
const segments = r.segments.map((s) => ({ text: s.text.trim(), startSecond: s.startSecond, endSecond: s.endSecond }));
|
|
147
|
+
const cost = num(r.providerMetadata?.gateway?.cost);
|
|
148
|
+
return {
|
|
149
|
+
text: r.text.trim(),
|
|
150
|
+
segments,
|
|
151
|
+
words: spansAreWords(segments) ? segments : [],
|
|
152
|
+
...(r.durationInSeconds !== undefined ? { durationSeconds: r.durationInSeconds } : {}),
|
|
153
|
+
...(cost !== undefined ? { costUsd: cost } : {}),
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
function fileName(mediaType) {
|
|
157
|
+
const sub = mediaType.split(";")[0].split("/")[1] ?? "bin";
|
|
158
|
+
return `chunk.${sub.replace(/[^a-z0-9]/gi, "") || "bin"}`;
|
|
159
|
+
}
|
|
160
|
+
async function postForm(f, url, form, headers, signal) {
|
|
161
|
+
const res = await f(url, { method: "POST", body: form, headers, ...(signal ? { signal } : {}) });
|
|
162
|
+
if (!res.ok) {
|
|
163
|
+
// The status only: a provider's error body can echo request details.
|
|
164
|
+
throw new Error(`HTTP ${res.status} from ${new URL(url).hostname}`);
|
|
165
|
+
}
|
|
166
|
+
return parseTranscriptionBody(await res.json());
|
|
167
|
+
}
|
|
168
|
+
function deepinfraCall(f, secret) {
|
|
169
|
+
return async (r, req) => {
|
|
170
|
+
const key = await secret(DEEPINFRA_SECRET);
|
|
171
|
+
const form = new FormData();
|
|
172
|
+
form.append("audio", new Blob([req.audio], { type: req.mediaType }), fileName(req.mediaType));
|
|
173
|
+
const path = r.id.split("/").map(encodeURIComponent).join("/");
|
|
174
|
+
return await postForm(f, `https://${DEEPINFRA_HOST}/v1/inference/${path}`, form, { authorization: `Bearer ${key}` }, req.abortSignal);
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function selfHostedCall(f) {
|
|
178
|
+
return async (r, req) => {
|
|
179
|
+
const form = new FormData();
|
|
180
|
+
form.append("file", new Blob([req.audio], { type: req.mediaType }), fileName(req.mediaType));
|
|
181
|
+
form.append("model", r.id);
|
|
182
|
+
form.append("response_format", "verbose_json");
|
|
183
|
+
form.append("timestamp_granularities[]", "word");
|
|
184
|
+
form.append("timestamp_granularities[]", "segment");
|
|
185
|
+
if (req.prompt !== undefined && req.prompt !== "")
|
|
186
|
+
form.append("prompt", req.prompt);
|
|
187
|
+
const base = (r.baseUrl ?? "").replace(/\/+$/, "");
|
|
188
|
+
return await postForm(f, `${base}/audio/transcriptions`, form, {}, req.abortSignal);
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* The hosts a role's routes reach on the host plane: the gateway host FIRST, then every non-gateway route host.
|
|
193
|
+
* They join the process-wide host set in gateway.ts (`sharedHostPlaneFetch`), so the one shared fetch pushes the
|
|
194
|
+
* union and neither the turn model nor a transcription route drops the other's host.
|
|
195
|
+
*/
|
|
196
|
+
export function roleHostPlaneHosts(role) {
|
|
197
|
+
const hosts = [GATEWAY_TARGET_HOST];
|
|
198
|
+
for (const r of [role.primary, role.fallback]) {
|
|
199
|
+
if (r === undefined || r.via === "gateway")
|
|
200
|
+
continue;
|
|
201
|
+
const h = routeHost(r);
|
|
202
|
+
if (!hosts.includes(h))
|
|
203
|
+
hosts.push(h);
|
|
204
|
+
}
|
|
205
|
+
return hosts;
|
|
206
|
+
}
|
|
207
|
+
/** The transport for one route. Exported for the bake-off harness, which calls each route on its own. */
|
|
208
|
+
export function routeTransport(r, deps = {}) {
|
|
209
|
+
if (r.via === "gateway") {
|
|
210
|
+
const g = deps.gateway ?? defaultGateway;
|
|
211
|
+
return (req) => g(r.id, req);
|
|
212
|
+
}
|
|
213
|
+
const f = deps.fetch ?? (deps.hostPlane ?? sharedHostPlaneFetch)(roleHostPlaneHosts({ primary: r })) ?? lateFetch;
|
|
214
|
+
if (r.via === "deepinfra") {
|
|
215
|
+
const call = deepinfraCall(f, deps.secret ?? storeOnlySecret);
|
|
216
|
+
return (req) => call(r, req);
|
|
217
|
+
}
|
|
218
|
+
const call = selfHostedCall(f);
|
|
219
|
+
return (req) => call(r, req);
|
|
220
|
+
}
|
|
221
|
+
function describe(r) {
|
|
222
|
+
return `${r.via}:${r.id}`;
|
|
223
|
+
}
|
|
224
|
+
function errText(err) {
|
|
225
|
+
return err instanceof Error ? err.message : String(err);
|
|
226
|
+
}
|
|
227
|
+
async function attempt(run, req, timeoutMs) {
|
|
228
|
+
// A plain timer, not `AbortSignal.timeout`: that timer is unref'd, so a process with nothing else pending exits
|
|
229
|
+
// before a hung attempt is cut.
|
|
230
|
+
const limit = new AbortController();
|
|
231
|
+
const timer = setTimeout(() => limit.abort(new Error(`no answer within ${timeoutMs} ms`)), timeoutMs);
|
|
232
|
+
const signal = req.abortSignal ? AbortSignal.any([req.abortSignal, limit.signal]) : limit.signal;
|
|
233
|
+
// The race cuts a transport that ignores the signal, too.
|
|
234
|
+
const aborted = new Promise((_, reject) => {
|
|
235
|
+
if (signal.aborted)
|
|
236
|
+
reject(signal.reason);
|
|
237
|
+
signal.addEventListener("abort", () => reject(signal.reason), { once: true });
|
|
238
|
+
});
|
|
239
|
+
try {
|
|
240
|
+
return await Promise.race([run({ ...req, abortSignal: signal }), aborted]);
|
|
241
|
+
}
|
|
242
|
+
finally {
|
|
243
|
+
clearTimeout(timer);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Build the role's transcriber: primary, then fallback on any failure. The routes are validated here, at build time.
|
|
248
|
+
*/
|
|
249
|
+
export function transcribeWithFallback(role, deps = {}) {
|
|
250
|
+
assertTranscriptionRole(role);
|
|
251
|
+
const timeoutMs = deps.attemptTimeoutMs ?? ATTEMPT_TIMEOUT_MS;
|
|
252
|
+
const warn = deps.warn ?? ((m) => console.warn(m));
|
|
253
|
+
// ONE host-plane fetch for the whole role, so the two routes never push host lists that drop each other.
|
|
254
|
+
const shared = { ...deps, fetch: deps.fetch ?? (deps.hostPlane ?? sharedHostPlaneFetch)(roleHostPlaneHosts(role)) ?? lateFetch };
|
|
255
|
+
const primary = routeTransport(role.primary, shared);
|
|
256
|
+
const fallback = role.fallback === undefined ? undefined : routeTransport(role.fallback, shared);
|
|
257
|
+
return async (req) => {
|
|
258
|
+
let first;
|
|
259
|
+
try {
|
|
260
|
+
return { ...(await attempt(primary, req, timeoutMs)), answeredBy: "primary", route: role.primary };
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
if (req.abortSignal?.aborted)
|
|
264
|
+
throw err;
|
|
265
|
+
first = err;
|
|
266
|
+
}
|
|
267
|
+
if (fallback === undefined || role.fallback === undefined) {
|
|
268
|
+
throw new Error(`transcription failed on ${describe(role.primary)}: ${errText(first)}`);
|
|
269
|
+
}
|
|
270
|
+
warn(`[open-everywhere:transcription] ${describe(role.primary)} failed (${errText(first)}); trying the fallback ${describe(role.fallback)}`);
|
|
271
|
+
try {
|
|
272
|
+
return { ...(await attempt(fallback, req, timeoutMs)), answeredBy: "fallback", route: role.fallback };
|
|
273
|
+
}
|
|
274
|
+
catch (second) {
|
|
275
|
+
throw new Error(`transcription failed on both routes — ${describe(role.primary)}: ${errText(first)}; ${describe(role.fallback)}: ${errText(second)}`);
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=transcription-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcription-routes.js","sourceRoot":"","sources":["../../../agent/model/transcription-routes.ts"],"names":[],"mappings":"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"}
|