@kuralle-syrinx/core 4.4.0 → 4.5.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/dist/audio/alaw.d.ts +3 -0
- package/dist/audio/alaw.d.ts.map +1 -0
- package/dist/audio/alaw.js +53 -0
- package/dist/audio/alaw.js.map +1 -0
- package/dist/audio/g722.d.ts +39 -0
- package/dist/audio/g722.d.ts.map +1 -0
- package/dist/audio/g722.js +286 -0
- package/dist/audio/g722.js.map +1 -0
- package/dist/audio/index.d.ts +7 -0
- package/dist/audio/index.d.ts.map +1 -0
- package/dist/audio/index.js +8 -0
- package/dist/audio/index.js.map +1 -0
- package/dist/audio/loudness.d.ts +13 -0
- package/dist/audio/loudness.d.ts.map +1 -0
- package/dist/audio/loudness.js +65 -0
- package/dist/audio/loudness.js.map +1 -0
- package/dist/audio/mulaw.d.ts +3 -0
- package/dist/audio/mulaw.d.ts.map +1 -0
- package/dist/audio/mulaw.js +39 -0
- package/dist/audio/mulaw.js.map +1 -0
- package/dist/audio/pcm.d.ts +5 -0
- package/dist/audio/pcm.d.ts.map +1 -0
- package/dist/audio/pcm.js +40 -0
- package/dist/audio/pcm.js.map +1 -0
- package/dist/audio/resample.d.ts +12 -0
- package/dist/audio/resample.d.ts.map +1 -0
- package/dist/audio/resample.js +157 -0
- package/dist/audio/resample.js.map +1 -0
- package/dist/audio-envelope.d.ts +23 -0
- package/dist/audio-envelope.d.ts.map +1 -0
- package/dist/audio-envelope.js +114 -0
- package/dist/audio-envelope.js.map +1 -0
- package/dist/confidence-to-wait.d.ts +12 -0
- package/dist/confidence-to-wait.d.ts.map +1 -0
- package/dist/confidence-to-wait.js +18 -0
- package/dist/confidence-to-wait.js.map +1 -0
- package/dist/conversation-event.d.ts +19 -0
- package/dist/conversation-event.d.ts.map +1 -0
- package/dist/conversation-event.js +44 -0
- package/dist/conversation-event.js.map +1 -0
- package/dist/error-handler.d.ts +35 -0
- package/dist/error-handler.d.ts.map +1 -0
- package/dist/error-handler.js +136 -0
- package/dist/error-handler.js.map +1 -0
- package/dist/idle-timeout.d.ts +69 -0
- package/dist/idle-timeout.d.ts.map +1 -0
- package/dist/idle-timeout.js +149 -0
- package/dist/idle-timeout.js.map +1 -0
- package/dist/incremental-unit.d.ts +17 -0
- package/dist/incremental-unit.d.ts.map +1 -0
- package/dist/incremental-unit.js +5 -0
- package/dist/incremental-unit.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/dist/init-chain.d.ts +35 -0
- package/dist/init-chain.d.ts.map +1 -0
- package/dist/init-chain.js +102 -0
- package/dist/init-chain.js.map +1 -0
- package/dist/init-stage-order.d.ts +5 -0
- package/dist/init-stage-order.d.ts.map +1 -0
- package/dist/init-stage-order.js +74 -0
- package/dist/init-stage-order.js.map +1 -0
- package/dist/interaction-coordinator.d.ts +45 -0
- package/dist/interaction-coordinator.d.ts.map +1 -0
- package/dist/interaction-coordinator.js +197 -0
- package/dist/interaction-coordinator.js.map +1 -0
- package/dist/interaction-policy.d.ts +103 -0
- package/dist/interaction-policy.d.ts.map +1 -0
- package/dist/interaction-policy.js +6 -0
- package/dist/interaction-policy.js.map +1 -0
- package/dist/iu-ledger.d.ts +39 -0
- package/dist/iu-ledger.d.ts.map +1 -0
- package/dist/iu-ledger.js +90 -0
- package/dist/iu-ledger.js.map +1 -0
- package/dist/latency-filler-fixtures.d.ts +7 -0
- package/dist/latency-filler-fixtures.d.ts.map +1 -0
- package/dist/latency-filler-fixtures.js +10 -0
- package/dist/latency-filler-fixtures.js.map +1 -0
- package/dist/latency-filler.d.ts +29 -0
- package/dist/latency-filler.d.ts.map +1 -0
- package/dist/latency-filler.js +102 -0
- package/dist/latency-filler.js.map +1 -0
- package/dist/mode-switcher.d.ts +24 -0
- package/dist/mode-switcher.d.ts.map +1 -0
- package/dist/mode-switcher.js +83 -0
- package/dist/mode-switcher.js.map +1 -0
- package/dist/observability-observer.d.ts +36 -0
- package/dist/observability-observer.d.ts.map +1 -0
- package/dist/observability-observer.js +141 -0
- package/dist/observability-observer.js.map +1 -0
- package/dist/observability.d.ts +68 -0
- package/dist/observability.d.ts.map +1 -0
- package/dist/observability.js +70 -0
- package/dist/observability.js.map +1 -0
- package/dist/packet-factories.d.ts +58 -0
- package/dist/packet-factories.d.ts.map +1 -0
- package/dist/packet-factories.js +181 -0
- package/dist/packet-factories.js.map +1 -0
- package/dist/packets.d.ts +532 -0
- package/dist/packets.d.ts.map +1 -0
- package/dist/packets.js +51 -0
- package/dist/packets.js.map +1 -0
- package/dist/pipeline-bus.d.ts +92 -0
- package/dist/pipeline-bus.d.ts.map +1 -0
- package/dist/pipeline-bus.js +294 -0
- package/dist/pipeline-bus.js.map +1 -0
- package/dist/plugin-contract.d.ts +73 -0
- package/dist/plugin-contract.d.ts.map +1 -0
- package/dist/plugin-contract.js +30 -0
- package/dist/plugin-contract.js.map +1 -0
- package/dist/policies/defer.d.ts +11 -0
- package/dist/policies/defer.d.ts.map +1 -0
- package/dist/policies/defer.js +13 -0
- package/dist/policies/defer.js.map +1 -0
- package/dist/policies/rule-based.d.ts +35 -0
- package/dist/policies/rule-based.d.ts.map +1 -0
- package/dist/policies/rule-based.js +130 -0
- package/dist/policies/rule-based.js.map +1 -0
- package/dist/pricing.d.ts +34 -0
- package/dist/pricing.d.ts.map +1 -0
- package/dist/pricing.js +108 -0
- package/dist/pricing.js.map +1 -0
- package/dist/primary-speaker-fixtures.d.ts +12 -0
- package/dist/primary-speaker-fixtures.d.ts.map +1 -0
- package/dist/primary-speaker-fixtures.js +37 -0
- package/dist/primary-speaker-fixtures.js.map +1 -0
- package/dist/primary-speaker-gate.d.ts +42 -0
- package/dist/primary-speaker-gate.d.ts.map +1 -0
- package/dist/primary-speaker-gate.js +178 -0
- package/dist/primary-speaker-gate.js.map +1 -0
- package/dist/provider-fallback.d.ts +28 -0
- package/dist/provider-fallback.d.ts.map +1 -0
- package/dist/provider-fallback.js +72 -0
- package/dist/provider-fallback.js.map +1 -0
- package/dist/reasoner-hedge.d.ts +21 -0
- package/dist/reasoner-hedge.d.ts.map +1 -0
- package/dist/reasoner-hedge.js +170 -0
- package/dist/reasoner-hedge.js.map +1 -0
- package/dist/reasoner-route.d.ts +24 -0
- package/dist/reasoner-route.d.ts.map +1 -0
- package/dist/reasoner-route.js +87 -0
- package/dist/reasoner-route.js.map +1 -0
- package/dist/reasoner-session-store.d.ts +18 -0
- package/dist/reasoner-session-store.d.ts.map +1 -0
- package/dist/reasoner-session-store.js +21 -0
- package/dist/reasoner-session-store.js.map +1 -0
- package/dist/reasoner.d.ts +97 -0
- package/dist/reasoner.d.ts.map +1 -0
- package/dist/reasoner.js +9 -0
- package/dist/reasoner.js.map +1 -0
- package/dist/retry.d.ts +31 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +83 -0
- package/dist/retry.js.map +1 -0
- package/dist/scheduler.d.ts +11 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +20 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/spend-cap.d.ts +27 -0
- package/dist/spend-cap.d.ts.map +1 -0
- package/dist/spend-cap.js +38 -0
- package/dist/spend-cap.js.map +1 -0
- package/dist/tts-playout-clock.d.ts +43 -0
- package/dist/tts-playout-clock.d.ts.map +1 -0
- package/dist/tts-playout-clock.js +125 -0
- package/dist/tts-playout-clock.js.map +1 -0
- package/dist/turn-arbiter.d.ts +41 -0
- package/dist/turn-arbiter.d.ts.map +1 -0
- package/dist/turn-arbiter.js +259 -0
- package/dist/turn-arbiter.js.map +1 -0
- package/dist/voice-agent-session-util.d.ts +60 -0
- package/dist/voice-agent-session-util.d.ts.map +1 -0
- package/dist/voice-agent-session-util.js +204 -0
- package/dist/voice-agent-session-util.js.map +1 -0
- package/dist/voice-agent-session.d.ts +435 -0
- package/dist/voice-agent-session.d.ts.map +1 -0
- package/dist/voice-agent-session.js +1597 -0
- package/dist/voice-agent-session.js.map +1 -0
- package/dist/voice-text.d.ts +46 -0
- package/dist/voice-text.d.ts.map +1 -0
- package/dist/voice-text.js +209 -0
- package/dist/voice-text.js.map +1 -0
- package/package.json +19 -6
- package/src/audio/alaw.test.ts +87 -0
- package/src/audio/audio.test.ts +285 -0
- package/src/audio/g722.test.ts +149 -0
- package/src/audio/loudness.test.ts +58 -0
- package/src/audio-envelope.test.ts +167 -0
- package/src/confidence-to-wait.test.ts +21 -0
- package/src/error-handler.test.ts +56 -0
- package/src/hedge-throwing-backend.test.ts +46 -0
- package/src/interaction-coordinator.test.ts +529 -0
- package/src/iu-ledger.test.ts +276 -0
- package/src/latency-filler.test.ts +62 -0
- package/src/observability-observer.test.ts +248 -0
- package/src/observability.test.ts +94 -0
- package/src/packet-factories.test.ts +126 -0
- package/src/pipeline-bus.g10.test.ts +145 -0
- package/src/pipeline-bus.test.ts +211 -0
- package/src/policies/defer.test.ts +86 -0
- package/src/policies/rule-based.test.ts +334 -0
- package/src/pricing.test.ts +226 -0
- package/src/primary-speaker-gate.test.ts +150 -0
- package/src/provider-fallback.test.ts +87 -0
- package/src/reasoner-hedge.test.ts +361 -0
- package/src/reasoner-route.test.ts +248 -0
- package/src/reasoner.test.ts +69 -0
- package/src/retry.test.ts +83 -0
- package/src/route-throwing-spec.test.ts +44 -0
- package/src/spend-cap.test.ts +114 -0
- package/src/tts-playout-clock.test.ts +125 -0
- package/src/turn-arbiter.characterization.test.ts +477 -0
- package/src/turn-arbiter.test.ts +762 -0
- package/src/voice-agent-session.test.ts +4165 -0
- package/src/voice-text.test.ts +156 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import { Route } from "./pipeline-bus.js";
|
|
3
|
+
import * as make from "./packet-factories.js";
|
|
4
|
+
import { TimerScheduler } from "./scheduler.js";
|
|
5
|
+
export class ProviderFallback {
|
|
6
|
+
providers;
|
|
7
|
+
opts;
|
|
8
|
+
unavailable = new Set();
|
|
9
|
+
recoveryTimers = new Set();
|
|
10
|
+
scheduler;
|
|
11
|
+
constructor(providers, opts) {
|
|
12
|
+
this.providers = providers;
|
|
13
|
+
this.opts = opts;
|
|
14
|
+
this.scheduler = opts.scheduler ?? new TimerScheduler();
|
|
15
|
+
}
|
|
16
|
+
async send(req) {
|
|
17
|
+
let lastError = null;
|
|
18
|
+
for (const provider of this.providers) {
|
|
19
|
+
if (this.unavailable.has(provider.id))
|
|
20
|
+
continue;
|
|
21
|
+
try {
|
|
22
|
+
return await provider.send(req, AbortSignal.timeout(this.opts.attemptTimeoutMs));
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
lastError = err;
|
|
26
|
+
this.markUnavailable(provider);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
throw lastError instanceof Error ? lastError : new Error("all fallback providers unavailable");
|
|
30
|
+
}
|
|
31
|
+
close() {
|
|
32
|
+
for (const providerId of this.recoveryTimers)
|
|
33
|
+
this.scheduler.cancel(recoveryKey(providerId));
|
|
34
|
+
this.recoveryTimers.clear();
|
|
35
|
+
this.unavailable.clear();
|
|
36
|
+
}
|
|
37
|
+
markUnavailable(provider) {
|
|
38
|
+
if (!this.unavailable.has(provider.id)) {
|
|
39
|
+
this.unavailable.add(provider.id);
|
|
40
|
+
this.metric(`${provider.id}.availability_changed`, "unavailable");
|
|
41
|
+
}
|
|
42
|
+
this.scheduleRecoveryProbe(provider);
|
|
43
|
+
}
|
|
44
|
+
scheduleRecoveryProbe(provider) {
|
|
45
|
+
if (this.recoveryTimers.has(provider.id))
|
|
46
|
+
return;
|
|
47
|
+
const runProbe = async () => {
|
|
48
|
+
this.recoveryTimers.delete(provider.id);
|
|
49
|
+
try {
|
|
50
|
+
if (await provider.healthProbe(AbortSignal.timeout(this.opts.attemptTimeoutMs))) {
|
|
51
|
+
this.unavailable.delete(provider.id);
|
|
52
|
+
this.metric(`${provider.id}.availability_changed`, "available");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Probe failure keeps the provider unavailable and schedules the next probe.
|
|
58
|
+
}
|
|
59
|
+
this.recoveryTimers.add(provider.id);
|
|
60
|
+
this.scheduler.schedule(recoveryKey(provider.id), this.opts.recoveryProbeIntervalMs, () => void runProbe());
|
|
61
|
+
};
|
|
62
|
+
this.recoveryTimers.add(provider.id);
|
|
63
|
+
this.scheduler.schedule(recoveryKey(provider.id), this.opts.recoveryProbeIntervalMs, () => void runProbe());
|
|
64
|
+
}
|
|
65
|
+
metric(name, value) {
|
|
66
|
+
this.opts.bus.push(Route.Background, make.metric(this.opts.contextId, name, value));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function recoveryKey(providerId) {
|
|
70
|
+
return `voice.provider_fallback.recovery:${providerId}`;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=provider-fallback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-fallback.js","sourceRoot":"","sources":["../src/provider-fallback.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type PipelineBus } from "./pipeline-bus.js";
|
|
2
|
+
import type { Reasoner, ReasonerTurn, ReasoningPart } from "./reasoner.js";
|
|
3
|
+
import { type Scheduler } from "./scheduler.js";
|
|
4
|
+
export interface HedgedReasonerOptions {
|
|
5
|
+
readonly primary: Reasoner;
|
|
6
|
+
readonly backup: Reasoner;
|
|
7
|
+
readonly hedgeAfterMs: number;
|
|
8
|
+
readonly bus?: PipelineBus;
|
|
9
|
+
readonly contextId?: string;
|
|
10
|
+
readonly scheduler?: Scheduler;
|
|
11
|
+
}
|
|
12
|
+
export declare class HedgedReasoner implements Reasoner {
|
|
13
|
+
private readonly opts;
|
|
14
|
+
private readonly scheduler;
|
|
15
|
+
constructor(opts: HedgedReasonerOptions);
|
|
16
|
+
stream(turn: ReasonerTurn): AsyncIterable<ReasoningPart>;
|
|
17
|
+
private doStream;
|
|
18
|
+
private raceToCommit;
|
|
19
|
+
private metric;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=reasoner-hedge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reasoner-hedge.d.ts","sourceRoot":"","sources":["../src/reasoner-hedge.ts"],"names":[],"mappings":"AAEA,OAAO,EAAS,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;CAChC;AAyBD,qBAAa,cAAe,YAAW,QAAQ;IAGjC,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;gBAET,IAAI,EAAE,qBAAqB;IAIxD,MAAM,CAAC,IAAI,EAAE,YAAY,GAAG,aAAa,CAAC,aAAa,CAAC;YAIzC,QAAQ;YAeT,YAAY;IAyI1B,OAAO,CAAC,MAAM;CAGf"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import { Route } from "./pipeline-bus.js";
|
|
3
|
+
import * as make from "./packet-factories.js";
|
|
4
|
+
import { TimerScheduler } from "./scheduler.js";
|
|
5
|
+
const asRacer = (who, next) => next
|
|
6
|
+
.then((result) => ({ who, result }))
|
|
7
|
+
.catch((err) => ({
|
|
8
|
+
who,
|
|
9
|
+
result: {
|
|
10
|
+
done: false,
|
|
11
|
+
value: {
|
|
12
|
+
type: "error",
|
|
13
|
+
cause: err instanceof Error ? err : new Error(String(err)),
|
|
14
|
+
recoverable: true,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
}));
|
|
18
|
+
export class HedgedReasoner {
|
|
19
|
+
opts;
|
|
20
|
+
scheduler;
|
|
21
|
+
constructor(opts) {
|
|
22
|
+
this.opts = opts;
|
|
23
|
+
this.scheduler = opts.scheduler ?? new TimerScheduler();
|
|
24
|
+
}
|
|
25
|
+
stream(turn) {
|
|
26
|
+
return this.doStream(turn);
|
|
27
|
+
}
|
|
28
|
+
async *doStream(turn) {
|
|
29
|
+
const commit = await this.raceToCommit(turn);
|
|
30
|
+
if (!commit.ok) {
|
|
31
|
+
yield commit.error;
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
yield commit.first;
|
|
35
|
+
let tail = await commit.iter.next();
|
|
36
|
+
while (!tail.done) {
|
|
37
|
+
yield tail.value;
|
|
38
|
+
tail = await commit.iter.next();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async raceToCommit(turn) {
|
|
42
|
+
const pc = new AbortController();
|
|
43
|
+
const bc = new AbortController();
|
|
44
|
+
if (turn.signal.aborted) {
|
|
45
|
+
pc.abort();
|
|
46
|
+
bc.abort();
|
|
47
|
+
return { ok: false, error: abortedError() };
|
|
48
|
+
}
|
|
49
|
+
turn.signal.addEventListener("abort", () => {
|
|
50
|
+
pc.abort();
|
|
51
|
+
bc.abort();
|
|
52
|
+
}, { once: true });
|
|
53
|
+
let committed = false;
|
|
54
|
+
let primaryExhausted = false;
|
|
55
|
+
let backupExhausted = false;
|
|
56
|
+
let lastError = null;
|
|
57
|
+
const primaryIter = this.opts.primary.stream({ ...turn, signal: pc.signal })[Symbol.asyncIterator]();
|
|
58
|
+
let primaryNext = primaryIter.next();
|
|
59
|
+
let backupIter = null;
|
|
60
|
+
let backupNext = null;
|
|
61
|
+
let repollRace = null;
|
|
62
|
+
const ensureBackup = () => {
|
|
63
|
+
if (backupIter)
|
|
64
|
+
return;
|
|
65
|
+
backupIter = this.opts.backup.stream({ ...turn, signal: bc.signal })[Symbol.asyncIterator]();
|
|
66
|
+
backupNext = backupIter.next();
|
|
67
|
+
this.metric("hedge.fired", "1");
|
|
68
|
+
repollRace?.();
|
|
69
|
+
};
|
|
70
|
+
this.scheduler.schedule("hedge", this.opts.hedgeAfterMs, () => {
|
|
71
|
+
if (!committed)
|
|
72
|
+
ensureBackup();
|
|
73
|
+
});
|
|
74
|
+
while (!committed) {
|
|
75
|
+
const raced = await new Promise((resolve) => {
|
|
76
|
+
const racers = [];
|
|
77
|
+
if (!primaryExhausted) {
|
|
78
|
+
racers.push(asRacer("primary", primaryNext));
|
|
79
|
+
}
|
|
80
|
+
if (backupNext && !backupExhausted) {
|
|
81
|
+
racers.push(asRacer("backup", backupNext));
|
|
82
|
+
}
|
|
83
|
+
if (racers.length === 0) {
|
|
84
|
+
repollRace = null;
|
|
85
|
+
resolve("repoll");
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
repollRace = () => resolve("repoll");
|
|
89
|
+
void Promise.race(racers).then((winner) => {
|
|
90
|
+
repollRace = null;
|
|
91
|
+
resolve(winner);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
if (raced === "repoll") {
|
|
95
|
+
if (primaryExhausted && (backupExhausted || !backupNext)) {
|
|
96
|
+
return { ok: false, error: lastError ?? abortedError() };
|
|
97
|
+
}
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const { who, result } = raced;
|
|
101
|
+
if (result.done) {
|
|
102
|
+
if (who === "primary") {
|
|
103
|
+
primaryExhausted = true;
|
|
104
|
+
if (!backupIter) {
|
|
105
|
+
this.scheduler.cancel("hedge");
|
|
106
|
+
ensureBackup();
|
|
107
|
+
}
|
|
108
|
+
else if (backupExhausted) {
|
|
109
|
+
return { ok: false, error: lastError ?? abortedError() };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
backupExhausted = true;
|
|
114
|
+
if (primaryExhausted) {
|
|
115
|
+
return { ok: false, error: lastError ?? abortedError() };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const part = result.value;
|
|
121
|
+
if (part.type === "error") {
|
|
122
|
+
lastError = part;
|
|
123
|
+
if (who === "primary") {
|
|
124
|
+
primaryExhausted = true;
|
|
125
|
+
if (!backupIter) {
|
|
126
|
+
this.scheduler.cancel("hedge");
|
|
127
|
+
ensureBackup();
|
|
128
|
+
}
|
|
129
|
+
if (backupExhausted) {
|
|
130
|
+
return { ok: false, error: part };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
backupExhausted = true;
|
|
135
|
+
if (primaryExhausted) {
|
|
136
|
+
return { ok: false, error: part };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
committed = true;
|
|
142
|
+
this.scheduler.cancel("hedge");
|
|
143
|
+
if (who === "primary") {
|
|
144
|
+
bc.abort();
|
|
145
|
+
releaseIterator(backupIter);
|
|
146
|
+
this.metric("hedge.committed_to", "primary");
|
|
147
|
+
return { ok: true, winner: "primary", first: part, iter: primaryIter };
|
|
148
|
+
}
|
|
149
|
+
pc.abort();
|
|
150
|
+
releaseIterator(primaryIter);
|
|
151
|
+
this.metric("hedge.committed_to", "backup");
|
|
152
|
+
return { ok: true, winner: "backup", first: part, iter: backupIter };
|
|
153
|
+
}
|
|
154
|
+
return { ok: false, error: lastError ?? abortedError() };
|
|
155
|
+
}
|
|
156
|
+
metric(name, value) {
|
|
157
|
+
this.opts.bus?.push(Route.Background, make.metric(this.opts.contextId ?? "", name, value));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function releaseIterator(iter) {
|
|
161
|
+
if (!iter)
|
|
162
|
+
return;
|
|
163
|
+
const release = iter.return;
|
|
164
|
+
if (release)
|
|
165
|
+
void release.call(iter, undefined);
|
|
166
|
+
}
|
|
167
|
+
function abortedError() {
|
|
168
|
+
return { type: "error", cause: new Error("aborted"), recoverable: true };
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=reasoner-hedge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reasoner-hedge.js","sourceRoot":"","sources":["../src/reasoner-hedge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type PipelineBus } from "./pipeline-bus.js";
|
|
2
|
+
import type { Reasoner, ReasonerTurn, ReasoningPart } from "./reasoner.js";
|
|
3
|
+
export interface ReasonerRoute {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly reasoner: Reasoner;
|
|
6
|
+
}
|
|
7
|
+
export interface RoutingReasonerOptions {
|
|
8
|
+
readonly routes: readonly ReasonerRoute[];
|
|
9
|
+
readonly classify: (turn: ReasonerTurn) => string | Promise<string>;
|
|
10
|
+
readonly speculateRouteId?: string;
|
|
11
|
+
readonly bus?: PipelineBus;
|
|
12
|
+
readonly contextId?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare class RoutingReasoner implements Reasoner {
|
|
15
|
+
private readonly opts;
|
|
16
|
+
constructor(opts: RoutingReasonerOptions);
|
|
17
|
+
stream(turn: ReasonerTurn): AsyncIterable<ReasoningPart>;
|
|
18
|
+
private doStream;
|
|
19
|
+
private streamWithSpeculation;
|
|
20
|
+
private forwardRoute;
|
|
21
|
+
private resolveRoute;
|
|
22
|
+
private metric;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=reasoner-route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reasoner-route.d.ts","sourceRoot":"","sources":["../src/reasoner-route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAS,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE3E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;CAC7B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,qBAAa,eAAgB,YAAW,QAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,sBAAsB;IAEzD,MAAM,CAAC,IAAI,EAAE,YAAY,GAAG,aAAa,CAAC,aAAa,CAAC;YAIzC,QAAQ;YAeR,qBAAqB;YAiCrB,YAAY;IAqB3B,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,MAAM;CAGf"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import { Route } from "./pipeline-bus.js";
|
|
3
|
+
import * as make from "./packet-factories.js";
|
|
4
|
+
export class RoutingReasoner {
|
|
5
|
+
opts;
|
|
6
|
+
constructor(opts) {
|
|
7
|
+
this.opts = opts;
|
|
8
|
+
}
|
|
9
|
+
stream(turn) {
|
|
10
|
+
return this.doStream(turn);
|
|
11
|
+
}
|
|
12
|
+
async *doStream(turn) {
|
|
13
|
+
if (turn.signal.aborted)
|
|
14
|
+
return;
|
|
15
|
+
if (this.opts.speculateRouteId !== undefined) {
|
|
16
|
+
yield* this.streamWithSpeculation(turn);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const routeId = await this.opts.classify(turn);
|
|
20
|
+
const route = this.resolveRoute(routeId);
|
|
21
|
+
this.metric("route.selected", routeId);
|
|
22
|
+
const iter = route.reasoner.stream({ ...turn, signal: turn.signal })[Symbol.asyncIterator]();
|
|
23
|
+
yield* this.forwardRoute(iter, undefined, turn.signal);
|
|
24
|
+
}
|
|
25
|
+
async *streamWithSpeculation(turn) {
|
|
26
|
+
const specId = this.opts.speculateRouteId;
|
|
27
|
+
const specRoute = this.resolveRoute(specId);
|
|
28
|
+
const child = new AbortController();
|
|
29
|
+
if (turn.signal.aborted) {
|
|
30
|
+
child.abort();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
turn.signal.addEventListener("abort", () => child.abort(), { once: true });
|
|
34
|
+
const specIter = specRoute.reasoner.stream({ ...turn, signal: child.signal })[Symbol.asyncIterator]();
|
|
35
|
+
const specNext = specIter.next();
|
|
36
|
+
const classifiedId = await this.opts.classify(turn);
|
|
37
|
+
if (classifiedId === specId) {
|
|
38
|
+
this.metric("route.selected", classifiedId);
|
|
39
|
+
yield* this.forwardRoute(specIter, specNext, turn.signal);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
child.abort();
|
|
43
|
+
releaseIterator(specIter);
|
|
44
|
+
void specNext.catch(() => undefined);
|
|
45
|
+
this.metric("route.mispredict", "1");
|
|
46
|
+
const route = this.resolveRoute(classifiedId);
|
|
47
|
+
this.metric("route.selected", classifiedId);
|
|
48
|
+
const iter = route.reasoner.stream({ ...turn, signal: turn.signal })[Symbol.asyncIterator]();
|
|
49
|
+
yield* this.forwardRoute(iter, undefined, turn.signal);
|
|
50
|
+
}
|
|
51
|
+
async *forwardRoute(iter, first, signal) {
|
|
52
|
+
try {
|
|
53
|
+
let next = first ? await first : await iter.next();
|
|
54
|
+
while (!next.done) {
|
|
55
|
+
if (signal.aborted)
|
|
56
|
+
return;
|
|
57
|
+
yield next.value;
|
|
58
|
+
next = await iter.next();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
yield {
|
|
63
|
+
type: "error",
|
|
64
|
+
cause: err instanceof Error ? err : new Error(String(err)),
|
|
65
|
+
recoverable: true,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
resolveRoute(id) {
|
|
70
|
+
const route = this.opts.routes.find((r) => r.id === id);
|
|
71
|
+
if (!route) {
|
|
72
|
+
throw new Error(`RoutingReasoner: unknown route id "${id}"`);
|
|
73
|
+
}
|
|
74
|
+
return route;
|
|
75
|
+
}
|
|
76
|
+
metric(name, value) {
|
|
77
|
+
this.opts.bus?.push(Route.Background, make.metric(this.opts.contextId ?? "", name, value));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function releaseIterator(iter) {
|
|
81
|
+
if (!iter)
|
|
82
|
+
return;
|
|
83
|
+
const release = iter.return;
|
|
84
|
+
if (release)
|
|
85
|
+
void release.call(iter, undefined);
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=reasoner-route.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reasoner-route.js","sourceRoot":"","sources":["../src/reasoner-route.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ReasonerMessage } from "./reasoner.js";
|
|
2
|
+
/**
|
|
3
|
+
* Durable per-session reasoner conversation history. `save` persists the full
|
|
4
|
+
* (already bounded) history snapshot — snapshot semantics, not append, because
|
|
5
|
+
* barge-in truncation rewrites earlier messages to the heard prefix (G25).
|
|
6
|
+
*/
|
|
7
|
+
export interface ReasonerSessionStore {
|
|
8
|
+
load(sessionId: string): Promise<readonly ReasonerMessage[]> | readonly ReasonerMessage[];
|
|
9
|
+
save(sessionId: string, messages: readonly ReasonerMessage[]): Promise<void> | void;
|
|
10
|
+
clear(sessionId: string): Promise<void> | void;
|
|
11
|
+
}
|
|
12
|
+
export declare class InMemoryReasonerSessionStore implements ReasonerSessionStore {
|
|
13
|
+
private readonly sessions;
|
|
14
|
+
load(sessionId: string): readonly ReasonerMessage[];
|
|
15
|
+
save(sessionId: string, messages: readonly ReasonerMessage[]): void;
|
|
16
|
+
clear(sessionId: string): void;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=reasoner-session-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reasoner-session-store.d.ts","sourceRoot":"","sources":["../src/reasoner-session-store.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC,GAAG,SAAS,eAAe,EAAE,CAAC;IAC1F,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,eAAe,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACpF,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAChD;AAED,qBAAa,4BAA6B,YAAW,oBAAoB;IACvE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiD;IAE1E,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,eAAe,EAAE;IAInD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,eAAe,EAAE,GAAG,IAAI;IAInE,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAG/B"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
//
|
|
3
|
+
// Syrinx Kernel v2 — durable reasoner session state (G4, RFC bimodel-delegate-seam)
|
|
4
|
+
//
|
|
5
|
+
// The bridge owns conversation history (reasoner.ts §4.5); this seam makes that
|
|
6
|
+
// history durable so a reasoner resumes with the same context after a host
|
|
7
|
+
// eviction/reconnect instead of restarting amnesiac. Concrete backends: the
|
|
8
|
+
// in-memory impl below (Node/tests), a DO-SQLite impl in @kuralle-syrinx/cf-agents.
|
|
9
|
+
export class InMemoryReasonerSessionStore {
|
|
10
|
+
sessions = new Map();
|
|
11
|
+
load(sessionId) {
|
|
12
|
+
return this.sessions.get(sessionId) ?? [];
|
|
13
|
+
}
|
|
14
|
+
save(sessionId, messages) {
|
|
15
|
+
this.sessions.set(sessionId, [...messages]);
|
|
16
|
+
}
|
|
17
|
+
clear(sessionId) {
|
|
18
|
+
this.sessions.delete(sessionId);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=reasoner-session-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reasoner-session-store.js","sourceRoot":"","sources":["../src/reasoner-session-store.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,EAAE;AACF,oFAAoF;AACpF,EAAE;AACF,gFAAgF;AAChF,2EAA2E;AAC3E,4EAA4E;AAC5E,oFAAoF;AAepF,MAAM,OAAO,4BAA4B;IACtB,QAAQ,GAAG,IAAI,GAAG,EAAsC,CAAC;IAE1E,IAAI,CAAC,SAAiB;QACpB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IAC5C,CAAC;IAED,IAAI,CAAC,SAAiB,EAAE,QAAoC;QAC1D,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,SAAiB;QACrB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;CACF"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/** A reasoning backend reduced to one normalized pull-stream per turn. */
|
|
2
|
+
export interface Reasoner {
|
|
3
|
+
/** Add transient steering context consumed by the next turn, when supported. */
|
|
4
|
+
injectContext?(text: string): void;
|
|
5
|
+
/**
|
|
6
|
+
* Drive one reasoning turn. The returned async-iterable IS the response.
|
|
7
|
+
* Cancellation (barge-in) is via `turn.signal` (abort) — the adapter forwards
|
|
8
|
+
* it into the backend stream and into tool execution.
|
|
9
|
+
*
|
|
10
|
+
* LATENCY INVARIANT (non-negotiable, see §7a): the adapter MUST yield every
|
|
11
|
+
* part the instant the backend produces it — NO buffering, NO awaiting the
|
|
12
|
+
* stream to completion, NO batching. The first `text-delta` must reach the
|
|
13
|
+
* caller as soon as the backend's first token lands. The seam adds at most one
|
|
14
|
+
* microtask + a synchronous object remap per part; it must add no I/O hop.
|
|
15
|
+
*/
|
|
16
|
+
stream(turn: ReasonerTurn): AsyncIterable<ReasoningPart>;
|
|
17
|
+
}
|
|
18
|
+
export interface ReasonerTurn {
|
|
19
|
+
/** Finalized user transcript for this turn (from `eos.turn_complete`). */
|
|
20
|
+
readonly userText: string;
|
|
21
|
+
/** Full prior conversation context. The BRIDGE owns history (see §4.5). */
|
|
22
|
+
readonly messages: readonly ReasonerMessage[];
|
|
23
|
+
/**
|
|
24
|
+
* The front-model delegate tool-call arguments that triggered this turn, verbatim — so a
|
|
25
|
+
* realtime front can pass structured context (e.g. `reply_language`) to the reasoner beyond
|
|
26
|
+
* the extracted `userText`. Absent for cascade STT turns.
|
|
27
|
+
*/
|
|
28
|
+
readonly toolArgs?: Record<string, unknown>;
|
|
29
|
+
/** Barge-in / supersede cancellation. */
|
|
30
|
+
readonly signal: AbortSignal;
|
|
31
|
+
/** Present only when resuming a previously-suspended run (step 3). */
|
|
32
|
+
readonly resume?: {
|
|
33
|
+
readonly runId: string;
|
|
34
|
+
readonly data: unknown;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export interface ReasonerMessage {
|
|
38
|
+
readonly role: "system" | "user" | "assistant" | "tool";
|
|
39
|
+
readonly content: string;
|
|
40
|
+
readonly toolCallId?: string;
|
|
41
|
+
}
|
|
42
|
+
/** Normalized output — the union of what AI SDK + Mastra can produce, minus noise. */
|
|
43
|
+
export type ReasoningPart = {
|
|
44
|
+
readonly type: "text-delta";
|
|
45
|
+
readonly text: string;
|
|
46
|
+
} | {
|
|
47
|
+
readonly type: "tool-call";
|
|
48
|
+
readonly toolId: string;
|
|
49
|
+
readonly toolName: string;
|
|
50
|
+
readonly args: Record<string, unknown>;
|
|
51
|
+
} | {
|
|
52
|
+
readonly type: "tool-result";
|
|
53
|
+
readonly toolId: string;
|
|
54
|
+
readonly toolName: string;
|
|
55
|
+
readonly result: string;
|
|
56
|
+
} | {
|
|
57
|
+
readonly type: "control";
|
|
58
|
+
readonly name: string;
|
|
59
|
+
readonly payload: unknown;
|
|
60
|
+
} | {
|
|
61
|
+
readonly type: "blocked";
|
|
62
|
+
readonly userFacingMessage: string;
|
|
63
|
+
readonly payload?: unknown;
|
|
64
|
+
} | {
|
|
65
|
+
readonly type: "suspended";
|
|
66
|
+
readonly runId: string;
|
|
67
|
+
readonly toolId?: string;
|
|
68
|
+
readonly prompt?: string;
|
|
69
|
+
readonly payload: unknown;
|
|
70
|
+
} | {
|
|
71
|
+
readonly type: "error";
|
|
72
|
+
readonly cause: Error;
|
|
73
|
+
readonly recoverable: boolean;
|
|
74
|
+
} | {
|
|
75
|
+
readonly type: "finish";
|
|
76
|
+
readonly reason: "stop" | "tool" | "length";
|
|
77
|
+
readonly text: string;
|
|
78
|
+
/**
|
|
79
|
+
* Billable token usage for this turn, when the backend reports it. Optional —
|
|
80
|
+
* a reasoner that cannot report usage omits it, and the metering path treats a
|
|
81
|
+
* missing field as "unknown", never zero. Consumed into `usage.recorded`.
|
|
82
|
+
*/
|
|
83
|
+
readonly usage?: ReasonerUsage;
|
|
84
|
+
};
|
|
85
|
+
/** Token usage a reasoner may attach to its terminal `finish` part. */
|
|
86
|
+
export interface ReasonerUsage {
|
|
87
|
+
/** Provider slug (e.g. "openai"), for low-cardinality cost attribution. */
|
|
88
|
+
readonly provider?: string;
|
|
89
|
+
/** Model id (e.g. "gpt-4.1-mini"). Without this, spend cannot be attributed to a model. */
|
|
90
|
+
readonly model?: string;
|
|
91
|
+
readonly inputTokens?: number;
|
|
92
|
+
readonly outputTokens?: number;
|
|
93
|
+
readonly totalTokens?: number;
|
|
94
|
+
readonly cachedInputTokens?: number;
|
|
95
|
+
readonly reasoningTokens?: number;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=reasoner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reasoner.d.ts","sourceRoot":"","sources":["../src/reasoner.ts"],"names":[],"mappings":"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"}
|
package/dist/reasoner.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
//
|
|
3
|
+
// Syrinx Kernel v2 — Reasoner seam
|
|
4
|
+
//
|
|
5
|
+
// A reasoning backend reduced to one normalized pull-stream per turn. Frameworks
|
|
6
|
+
// (AI SDK ToolLoopAgent, Mastra Agent, raw streamText) become a Reasoner via
|
|
7
|
+
// adapters; the bridge drives the seam, not the framework. See RFC §4.2.
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=reasoner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reasoner.js","sourceRoot":"","sources":["../src/reasoner.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,EAAE;AACF,mCAAmC;AACnC,EAAE;AACF,iFAAiF;AACjF,6EAA6E;AAC7E,yEAAyE"}
|
package/dist/retry.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface RetryConfig {
|
|
2
|
+
readonly maxAttempts: number;
|
|
3
|
+
readonly baseDelayMs: number;
|
|
4
|
+
readonly maxDelayMs: number;
|
|
5
|
+
}
|
|
6
|
+
export declare const DEFAULT_RETRY_CONFIG: RetryConfig;
|
|
7
|
+
/**
|
|
8
|
+
* Retry profile for long-lived voice-provider WebSockets (STT/TTS).
|
|
9
|
+
*
|
|
10
|
+
* Keeps the SAME fast first reconnect as the default (~125-250 ms) so a transient
|
|
11
|
+
* blip during a live call recovers without dead air, but raises the backoff cap to
|
|
12
|
+
* 10 s and allows more attempts so a persistent provider failure (rate limit /
|
|
13
|
+
* outage) is retried patiently instead of giving up after ~2 s. This intentionally
|
|
14
|
+
* does NOT use a multi-second *floor* (a 4 s first-retry would mean seconds of dead
|
|
15
|
+
* air on a live call); "every 10 ms matters" applies to the first reconnect, patient
|
|
16
|
+
* backoff applies only after repeated failures.
|
|
17
|
+
*/
|
|
18
|
+
export declare const VOICE_PROVIDER_RETRY_CONFIG: RetryConfig;
|
|
19
|
+
export declare const VOICE_PROVIDER_OUTAGE_RETRY_CONFIG: RetryConfig;
|
|
20
|
+
export declare function readRetryConfig(config: Record<string, unknown>): RetryConfig;
|
|
21
|
+
/** Read retry config for a voice-provider WebSocket; defaults to the patient-backoff profile. */
|
|
22
|
+
export declare function readProviderRetryConfig(config: Record<string, unknown>): RetryConfig;
|
|
23
|
+
export declare function retryDelayMs(attemptIndex: number, config: RetryConfig): number;
|
|
24
|
+
/**
|
|
25
|
+
* Equal-jitter backoff: half the deterministic exponential delay plus a random half.
|
|
26
|
+
* Spreads out retries so many sessions hitting the same provider rate/concurrency limit
|
|
27
|
+
* at once don't reconnect in lockstep (thundering herd). `rng` is injectable for tests.
|
|
28
|
+
*/
|
|
29
|
+
export declare function retryDelayWithJitterMs(attemptIndex: number, config: RetryConfig, rng?: () => number): number;
|
|
30
|
+
export declare function waitForRetryDelay(attemptIndex: number, config: RetryConfig, signal?: AbortSignal): Promise<void>;
|
|
31
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,eAAO,MAAM,oBAAoB,EAAE,WAIlC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,2BAA2B,EAAE,WAIzC,CAAC;AAEF,eAAO,MAAM,kCAAkC,EAAE,WAIhD,CAAC;AAEF,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,CAE5E;AAED,iGAAiG;AACjG,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,CAMpF;AAUD,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,MAAM,CAG9E;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,WAAW,EACnB,GAAG,GAAE,MAAM,MAAoB,GAC9B,MAAM,CAIR;AAED,wBAAsB,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAetH"}
|