@effect-uai/core 0.15.0 → 0.16.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/README.md +30 -16
- package/dist/{AiError-eLV9t1lU.d.mts → AiError-DvhLIbmd.d.mts} +15 -4
- package/dist/{AiError-eLV9t1lU.d.mts.map → AiError-DvhLIbmd.d.mts.map} +1 -1
- package/dist/{Loop-B54AB1ME.d.mts → Loop-ChpaO-ya.d.mts} +2 -2
- package/dist/{Loop-B54AB1ME.d.mts.map → Loop-ChpaO-ya.d.mts.map} +1 -1
- package/dist/{Toolkit-DAjJ9Tvl.d.mts → Toolkit-tlL0F2YR.d.mts} +2 -2
- package/dist/{Toolkit-DAjJ9Tvl.d.mts.map → Toolkit-tlL0F2YR.d.mts.map} +1 -1
- package/dist/chunker/Chunker.d.mts +1 -1
- package/dist/domain/AiError.d.mts +2 -2
- package/dist/domain/AiError.mjs +9 -2
- package/dist/domain/AiError.mjs.map +1 -1
- package/dist/domain/Realtime.d.mts +616 -0
- package/dist/domain/Realtime.d.mts.map +1 -0
- package/dist/domain/Realtime.mjs +21 -0
- package/dist/domain/Realtime.mjs.map +1 -0
- package/dist/domain/Transcript.d.mts +17 -3
- package/dist/domain/Transcript.d.mts.map +1 -1
- package/dist/domain/Transcript.mjs +30 -1
- package/dist/domain/Transcript.mjs.map +1 -1
- package/dist/domain/Transcript.test.mjs +110 -0
- package/dist/domain/Transcript.test.mjs.map +1 -0
- package/dist/embedding-model/EmbeddingModel.d.mts +1 -1
- package/dist/image-generator/ImageGenerator.d.mts +1 -1
- package/dist/index.d.mts +8 -5
- package/dist/index.mjs +6 -3
- package/dist/job/Job.d.mts +1 -1
- package/dist/language-model/LanguageModel.d.mts +2 -2
- package/dist/loop/Loop.d.mts +1 -1
- package/dist/music-generator/MusicGenerator.d.mts +1 -1
- package/dist/realtime/RealtimeSession.d.mts +50 -0
- package/dist/realtime/RealtimeSession.d.mts.map +1 -0
- package/dist/realtime/RealtimeSession.mjs +45 -0
- package/dist/realtime/RealtimeSession.mjs.map +1 -0
- package/dist/realtime/RealtimeSession.test.d.mts +1 -0
- package/dist/realtime/RealtimeSession.test.mjs +95 -0
- package/dist/realtime/RealtimeSession.test.mjs.map +1 -0
- package/dist/reranker/Reranker.d.mts +1 -1
- package/dist/research/DeepResearch.d.mts +1 -1
- package/dist/retry/Retry.d.mts +1 -1
- package/dist/speech-synthesizer/SpeechSynthesizer.d.mts +1 -1
- package/dist/streaming/Settle.d.mts +45 -0
- package/dist/streaming/Settle.d.mts.map +1 -0
- package/dist/streaming/Settle.mjs +95 -0
- package/dist/streaming/Settle.mjs.map +1 -0
- package/dist/streaming/Settle.test.d.mts +1 -0
- package/dist/streaming/Settle.test.mjs +252 -0
- package/dist/streaming/Settle.test.mjs.map +1 -0
- package/dist/streaming/WebSocketSession.d.mts +36 -0
- package/dist/streaming/WebSocketSession.d.mts.map +1 -0
- package/dist/streaming/WebSocketSession.mjs +89 -0
- package/dist/streaming/WebSocketSession.mjs.map +1 -0
- package/dist/streaming/WebSocketSession.test.d.mts +1 -0
- package/dist/streaming/WebSocketSession.test.mjs +51 -0
- package/dist/streaming/WebSocketSession.test.mjs.map +1 -0
- package/dist/testing/FakeWebSocket.d.mts +25 -0
- package/dist/testing/FakeWebSocket.d.mts.map +1 -0
- package/dist/testing/FakeWebSocket.mjs +79 -0
- package/dist/testing/FakeWebSocket.mjs.map +1 -0
- package/dist/testing/MockRealtimeSession.d.mts +30 -0
- package/dist/testing/MockRealtimeSession.d.mts.map +1 -0
- package/dist/testing/MockRealtimeSession.mjs +52 -0
- package/dist/testing/MockRealtimeSession.mjs.map +1 -0
- package/dist/tool/Toolkit.d.mts +1 -1
- package/dist/transcriber/Transcriber.d.mts +1 -1
- package/dist/web-read/WebRead.d.mts +1 -1
- package/dist/web-read/WebReadTool.d.mts +1 -1
- package/dist/web-search/WebSearch.d.mts +1 -1
- package/dist/web-search/WebSearchTool.d.mts +1 -1
- package/package.json +24 -4
- package/src/domain/AiError.ts +11 -0
- package/src/domain/Realtime.ts +101 -0
- package/src/domain/Transcript.test.ts +98 -0
- package/src/domain/Transcript.ts +53 -1
- package/src/index.ts +4 -1
- package/src/realtime/RealtimeSession.test.ts +100 -0
- package/src/realtime/RealtimeSession.ts +77 -0
- package/src/streaming/Settle.test.ts +344 -0
- package/src/streaming/Settle.ts +196 -0
- package/src/streaming/WebSocketSession.test.ts +52 -0
- package/src/streaming/WebSocketSession.ts +132 -0
- package/src/testing/FakeWebSocket.ts +120 -0
- package/src/testing/MockRealtimeSession.ts +92 -0
- package/dist/inbox/Inbox.d.mts +0 -16
- package/dist/inbox/Inbox.d.mts.map +0 -1
- package/dist/inbox/Inbox.mjs +0 -28
- package/dist/inbox/Inbox.mjs.map +0 -1
- package/dist/inbox/Inbox.test.mjs +0 -42
- package/dist/inbox/Inbox.test.mjs.map +0 -1
- package/src/inbox/Inbox.test.ts +0 -52
- package/src/inbox/Inbox.ts +0 -33
- /package/dist/{inbox/Inbox.test.d.mts → domain/Transcript.test.d.mts} +0 -0
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { n as __exportAll } from "../rolldown-runtime-EAsCxrDo.mjs";
|
|
2
|
+
import { onQuiet } from "../streaming/Settle.mjs";
|
|
3
|
+
import { Effect, Match, Option, Ref, Stream } from "effect";
|
|
2
4
|
//#region src/domain/Transcript.ts
|
|
3
5
|
var Transcript_exports = /* @__PURE__ */ __exportAll({
|
|
6
|
+
accumulatePartials: () => accumulatePartials,
|
|
4
7
|
isAudioEvent: () => isAudioEvent,
|
|
5
8
|
isError: () => isError,
|
|
6
9
|
isFinal: () => isFinal,
|
|
@@ -16,7 +19,33 @@ const isUtteranceEnded = (e) => e._tag === "utterance-ended";
|
|
|
16
19
|
const isAudioEvent = (e) => e._tag === "audio-event";
|
|
17
20
|
const isMetadata = (e) => e._tag === "metadata";
|
|
18
21
|
const isError = (e) => e._tag === "error";
|
|
22
|
+
const DEFAULT_SILENCE = "700 millis";
|
|
23
|
+
const finalOf = (text) => text.trim().length === 0 ? Option.none() : Option.some({
|
|
24
|
+
_tag: "final",
|
|
25
|
+
text: text.trim()
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* Join fragment `partial`s into the running hypothesis and commit it as a
|
|
29
|
+
* `final` after `silence`. For providers that stream token-sized deltas
|
|
30
|
+
* (OpenAI Realtime) or never segment; piping one that already accumulates
|
|
31
|
+
* repeats its text.
|
|
32
|
+
*
|
|
33
|
+
* Partials are forwarded as they arrive; only the synthetic `final` waits.
|
|
34
|
+
* A real `final` resets the accumulator, and the stream end flushes it.
|
|
35
|
+
*/
|
|
36
|
+
const accumulatePartials = (options) => (self) => Stream.unwrap(Effect.gen(function* () {
|
|
37
|
+
const acc = yield* Ref.make("");
|
|
38
|
+
const flush = Effect.map(Ref.getAndSet(acc, ""), finalOf);
|
|
39
|
+
const rewrite = (event) => Match.value(event).pipe(Match.when({ _tag: "partial" }, (e) => Effect.map(Ref.updateAndGet(acc, (text) => text + e.text), (text) => ({
|
|
40
|
+
...e,
|
|
41
|
+
text: text.trim()
|
|
42
|
+
}))), Match.when({ _tag: "final" }, (e) => Effect.as(Ref.set(acc, ""), e)), Match.orElse((e) => Effect.succeed(e)));
|
|
43
|
+
return self.pipe(Stream.mapEffect(rewrite), onQuiet(options?.silence ?? DEFAULT_SILENCE, flush), Stream.concat(Stream.unwrap(Effect.map(flush, Option.match({
|
|
44
|
+
onNone: () => Stream.empty,
|
|
45
|
+
onSome: Stream.make
|
|
46
|
+
})))));
|
|
47
|
+
}));
|
|
19
48
|
//#endregion
|
|
20
|
-
export { isAudioEvent, isError, isFinal, isMetadata, isPartial, isSpeechStarted, isUtteranceEnded, Transcript_exports as t };
|
|
49
|
+
export { accumulatePartials, isAudioEvent, isError, isFinal, isMetadata, isPartial, isSpeechStarted, isUtteranceEnded, Transcript_exports as t };
|
|
21
50
|
|
|
22
51
|
//# sourceMappingURL=Transcript.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Transcript.mjs","names":[],"sources":["../../src/domain/Transcript.ts"],"sourcesContent":["import type
|
|
1
|
+
{"version":3,"file":"Transcript.mjs","names":["Settle.onQuiet"],"sources":["../../src/domain/Transcript.ts"],"sourcesContent":["import { type Duration, Effect, Match, Option, Ref, Stream } from \"effect\"\nimport * as Settle from \"../streaming/Settle.js\"\n\n/**\n * Per-word timing + metadata. `confidence` and `speakerId` are optional\n * because providers vary widely in what they emit and when (some only on\n * final, some only with diarization enabled, some not at all).\n *\n * `startSeconds` / `endSeconds` stay raw `number` offsets (not `Duration`)\n * — they're positions in the audio, not durations.\n */\nexport type WordTimestamp = {\n readonly text: string\n readonly startSeconds: number\n readonly endSeconds: number\n readonly confidence?: number\n readonly speakerId?: string\n readonly languageCode?: string\n}\n\n/**\n * Sync STT result. `raw` preserves the provider-specific response for\n * consumers that need fields the common shape doesn't expose\n * (alternatives, segments, NBest, audio events, etc.).\n */\nexport type TranscriptResult = {\n readonly text: string\n readonly languageCode?: string\n /** Total audio duration. (Word offsets stay raw seconds on `WordTimestamp`.) */\n readonly duration?: Duration.Duration\n readonly words?: ReadonlyArray<WordTimestamp>\n readonly raw?: unknown\n}\n\n/**\n * Streaming STT event union. Collapses every provider's vocabulary into\n * a small set; provider-specific shapes survive on `metadata.raw`.\n *\n * - `partial`: interim hypothesis. `stability` is Google-only.\n * - `final`: committed transcript for the current utterance / segment.\n * - `speech-started` / `utterance-ended`: VAD-derived boundaries. Not\n * all providers emit them (OpenAI Realtime, Google with\n * `voice_activity_events`, Deepgram with `vad_events`, AssemblyAI).\n * - `audio-event`: non-speech label (`(laughter)`, `(music)`) — ElevenLabs only.\n * - `metadata`: opaque server-side bookkeeping (request_id, model info).\n * - `error`: non-fatal provider error mid-stream. Fatal errors surface\n * on the `Stream`'s error channel as `AiError.AiError`.\n */\nexport type TranscriptEvent =\n | {\n readonly _tag: \"partial\"\n readonly text: string\n readonly words?: ReadonlyArray<WordTimestamp>\n readonly stability?: number\n }\n | {\n readonly _tag: \"final\"\n readonly text: string\n readonly words?: ReadonlyArray<WordTimestamp>\n readonly languageCode?: string\n }\n | { readonly _tag: \"speech-started\"; readonly atSeconds: number }\n | { readonly _tag: \"utterance-ended\"; readonly atSeconds: number }\n | {\n readonly _tag: \"audio-event\"\n readonly label: string\n readonly startSeconds: number\n readonly endSeconds: number\n }\n | { readonly _tag: \"metadata\"; readonly raw: unknown }\n | { readonly _tag: \"error\"; readonly code?: string; readonly message: string }\n\nexport const isPartial = (e: TranscriptEvent): e is Extract<TranscriptEvent, { _tag: \"partial\" }> =>\n e._tag === \"partial\"\nexport const isFinal = (e: TranscriptEvent): e is Extract<TranscriptEvent, { _tag: \"final\" }> =>\n e._tag === \"final\"\nexport const isSpeechStarted = (\n e: TranscriptEvent,\n): e is Extract<TranscriptEvent, { _tag: \"speech-started\" }> => e._tag === \"speech-started\"\nexport const isUtteranceEnded = (\n e: TranscriptEvent,\n): e is Extract<TranscriptEvent, { _tag: \"utterance-ended\" }> => e._tag === \"utterance-ended\"\nexport const isAudioEvent = (\n e: TranscriptEvent,\n): e is Extract<TranscriptEvent, { _tag: \"audio-event\" }> => e._tag === \"audio-event\"\nexport const isMetadata = (\n e: TranscriptEvent,\n): e is Extract<TranscriptEvent, { _tag: \"metadata\" }> => e._tag === \"metadata\"\nexport const isError = (e: TranscriptEvent): e is Extract<TranscriptEvent, { _tag: \"error\" }> =>\n e._tag === \"error\"\n\nexport type AccumulatePartialsOptions = {\n /** Silence after the last `partial` before the text so far is committed. */\n readonly silence?: Duration.Input\n}\n\nconst DEFAULT_SILENCE = \"700 millis\"\n\nconst finalOf = (text: string): Option.Option<TranscriptEvent> =>\n text.trim().length === 0 ? Option.none() : Option.some({ _tag: \"final\", text: text.trim() })\n\n/**\n * Join fragment `partial`s into the running hypothesis and commit it as a\n * `final` after `silence`. For providers that stream token-sized deltas\n * (OpenAI Realtime) or never segment; piping one that already accumulates\n * repeats its text.\n *\n * Partials are forwarded as they arrive; only the synthetic `final` waits.\n * A real `final` resets the accumulator, and the stream end flushes it.\n */\nexport const accumulatePartials =\n (options?: AccumulatePartialsOptions) =>\n <E, R>(self: Stream.Stream<TranscriptEvent, E, R>): Stream.Stream<TranscriptEvent, E, R> =>\n Stream.unwrap(\n Effect.gen(function* () {\n const acc = yield* Ref.make(\"\")\n const flush = Effect.map(Ref.getAndSet(acc, \"\"), finalOf)\n\n const rewrite = (event: TranscriptEvent): Effect.Effect<TranscriptEvent> =>\n Match.value(event).pipe(\n Match.when({ _tag: \"partial\" }, (e) =>\n Effect.map(\n Ref.updateAndGet(acc, (text) => text + e.text),\n (text): TranscriptEvent => ({ ...e, text: text.trim() }),\n ),\n ),\n Match.when({ _tag: \"final\" }, (e) => Effect.as(Ref.set(acc, \"\"), e as TranscriptEvent)),\n Match.orElse((e) => Effect.succeed(e as TranscriptEvent)),\n )\n\n return self.pipe(\n Stream.mapEffect(rewrite),\n Settle.onQuiet(options?.silence ?? DEFAULT_SILENCE, flush),\n Stream.concat(\n Stream.unwrap(\n Effect.map(flush, Option.match({ onNone: () => Stream.empty, onSome: Stream.make })),\n ),\n ),\n )\n }),\n )\n"],"mappings":";;;;;;;;;;;;;;AAwEA,MAAa,aAAa,MACxB,EAAE,SAAS;AACb,MAAa,WAAW,MACtB,EAAE,SAAS;AACb,MAAa,mBACX,MAC8D,EAAE,SAAS;AAC3E,MAAa,oBACX,MAC+D,EAAE,SAAS;AAC5E,MAAa,gBACX,MAC2D,EAAE,SAAS;AACxE,MAAa,cACX,MACwD,EAAE,SAAS;AACrE,MAAa,WAAW,MACtB,EAAE,SAAS;AAOb,MAAM,kBAAkB;AAExB,MAAM,WAAW,SACf,KAAK,KAAK,CAAC,CAAC,WAAW,IAAI,OAAO,KAAK,IAAI,OAAO,KAAK;CAAE,MAAM;CAAS,MAAM,KAAK,KAAK;AAAE,CAAC;;;;;;;;;;AAW7F,MAAa,sBACV,aACM,SACL,OAAO,OACL,OAAO,IAAI,aAAa;CACtB,MAAM,MAAM,OAAO,IAAI,KAAK,EAAE;CAC9B,MAAM,QAAQ,OAAO,IAAI,IAAI,UAAU,KAAK,EAAE,GAAG,OAAO;CAExD,MAAM,WAAW,UACf,MAAM,MAAM,KAAK,CAAC,CAAC,KACjB,MAAM,KAAK,EAAE,MAAM,UAAU,IAAI,MAC/B,OAAO,IACL,IAAI,aAAa,MAAM,SAAS,OAAO,EAAE,IAAI,IAC5C,UAA2B;EAAE,GAAG;EAAG,MAAM,KAAK,KAAK;CAAE,EACxD,CACF,GACA,MAAM,KAAK,EAAE,MAAM,QAAQ,IAAI,MAAM,OAAO,GAAG,IAAI,IAAI,KAAK,EAAE,GAAG,CAAoB,CAAC,GACtF,MAAM,QAAQ,MAAM,OAAO,QAAQ,CAAoB,CAAC,CAC1D;CAEF,OAAO,KAAK,KACV,OAAO,UAAU,OAAO,GACxBA,QAAe,SAAS,WAAW,iBAAiB,KAAK,GACzD,OAAO,OACL,OAAO,OACL,OAAO,IAAI,OAAO,OAAO,MAAM;EAAE,cAAc,OAAO;EAAO,QAAQ,OAAO;CAAK,CAAC,CAAC,CACrF,CACF,CACF;AACF,CAAC,CACH"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { accumulatePartials } from "./Transcript.mjs";
|
|
2
|
+
import { o as describe } from "../utils-CiH_DjFW.mjs";
|
|
3
|
+
import { n as globalExpect } from "../test.DNmyFkvJ-YPzDR0Co.mjs";
|
|
4
|
+
import { t as it } from "../dist-nohcnkD6.mjs";
|
|
5
|
+
import { Effect, Queue, Ref, Stream } from "effect";
|
|
6
|
+
import { TestClock } from "effect/testing";
|
|
7
|
+
//#region src/domain/Transcript.test.ts
|
|
8
|
+
const collecting = (stream) => Effect.gen(function* () {
|
|
9
|
+
const seen = yield* Ref.make([]);
|
|
10
|
+
yield* Effect.forkChild(Stream.runForEach(stream, (e) => Ref.update(seen, (xs) => [...xs, e])));
|
|
11
|
+
return seen;
|
|
12
|
+
});
|
|
13
|
+
/** Deltas arriving faster than any settle window. */
|
|
14
|
+
const speak = (queue, tokens) => Effect.forEach(tokens, (text) => Effect.andThen(Queue.offer(queue, {
|
|
15
|
+
_tag: "partial",
|
|
16
|
+
text
|
|
17
|
+
}), TestClock.adjust("100 millis")), { discard: true });
|
|
18
|
+
const opened = Effect.gen(function* () {
|
|
19
|
+
const queue = yield* Queue.unbounded();
|
|
20
|
+
return {
|
|
21
|
+
queue,
|
|
22
|
+
seen: yield* collecting(Stream.fromQueue(queue).pipe(accumulatePartials({ silence: "1 second" })))
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
describe("accumulatePartials", () => {
|
|
26
|
+
it.effect("joins deltas into the running hypothesis, forwarding each as it arrives", () => Effect.gen(function* () {
|
|
27
|
+
const { queue, seen } = yield* opened;
|
|
28
|
+
yield* speak(queue, [
|
|
29
|
+
" Hi",
|
|
30
|
+
",",
|
|
31
|
+
" how"
|
|
32
|
+
]);
|
|
33
|
+
globalExpect(yield* Ref.get(seen)).toEqual([
|
|
34
|
+
{
|
|
35
|
+
_tag: "partial",
|
|
36
|
+
text: "Hi"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
_tag: "partial",
|
|
40
|
+
text: "Hi,"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
_tag: "partial",
|
|
44
|
+
text: "Hi, how"
|
|
45
|
+
}
|
|
46
|
+
]);
|
|
47
|
+
}));
|
|
48
|
+
it.effect("commits on silence and starts the next utterance from empty", () => Effect.gen(function* () {
|
|
49
|
+
const { queue, seen } = yield* opened;
|
|
50
|
+
yield* speak(queue, [" Hi", " there"]);
|
|
51
|
+
yield* TestClock.adjust("3 seconds");
|
|
52
|
+
yield* speak(queue, [" Bye"]);
|
|
53
|
+
yield* TestClock.adjust("3 seconds");
|
|
54
|
+
globalExpect(yield* Ref.get(seen)).toEqual([
|
|
55
|
+
{
|
|
56
|
+
_tag: "partial",
|
|
57
|
+
text: "Hi"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
_tag: "partial",
|
|
61
|
+
text: "Hi there"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
_tag: "final",
|
|
65
|
+
text: "Hi there"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
_tag: "partial",
|
|
69
|
+
text: "Bye"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
_tag: "final",
|
|
73
|
+
text: "Bye"
|
|
74
|
+
}
|
|
75
|
+
]);
|
|
76
|
+
}));
|
|
77
|
+
it.effect("a provider's own final resets the accumulator, so silence adds no duplicate", () => Effect.gen(function* () {
|
|
78
|
+
const { queue, seen } = yield* opened;
|
|
79
|
+
yield* speak(queue, [" Hi"]);
|
|
80
|
+
yield* Queue.offer(queue, {
|
|
81
|
+
_tag: "final",
|
|
82
|
+
text: "Hi."
|
|
83
|
+
});
|
|
84
|
+
yield* TestClock.adjust("3 seconds");
|
|
85
|
+
globalExpect(yield* Ref.get(seen)).toEqual([{
|
|
86
|
+
_tag: "partial",
|
|
87
|
+
text: "Hi"
|
|
88
|
+
}, {
|
|
89
|
+
_tag: "final",
|
|
90
|
+
text: "Hi."
|
|
91
|
+
}]);
|
|
92
|
+
}));
|
|
93
|
+
it.effect("commits the pending text when the stream ends mid-utterance", () => Effect.gen(function* () {
|
|
94
|
+
const { queue, seen } = yield* opened;
|
|
95
|
+
yield* speak(queue, [" Half a sen"]);
|
|
96
|
+
yield* Queue.end(queue);
|
|
97
|
+
yield* TestClock.adjust("10 millis");
|
|
98
|
+
globalExpect(yield* Ref.get(seen)).toEqual([{
|
|
99
|
+
_tag: "partial",
|
|
100
|
+
text: "Half a sen"
|
|
101
|
+
}, {
|
|
102
|
+
_tag: "final",
|
|
103
|
+
text: "Half a sen"
|
|
104
|
+
}]);
|
|
105
|
+
}));
|
|
106
|
+
});
|
|
107
|
+
//#endregion
|
|
108
|
+
export {};
|
|
109
|
+
|
|
110
|
+
//# sourceMappingURL=Transcript.test.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Transcript.test.mjs","names":[],"sources":["../../src/domain/Transcript.test.ts"],"sourcesContent":["import { describe, it } from \"@effect/vitest\"\nimport { Cause, Effect, Queue, Ref, Stream } from \"effect\"\nimport { TestClock } from \"effect/testing\"\nimport { expect } from \"vitest\"\nimport { accumulatePartials, type TranscriptEvent } from \"./Transcript.js\"\n\nconst collecting = (stream: Stream.Stream<TranscriptEvent, never>) =>\n Effect.gen(function* () {\n const seen = yield* Ref.make<ReadonlyArray<TranscriptEvent>>([])\n yield* Effect.forkChild(Stream.runForEach(stream, (e) => Ref.update(seen, (xs) => [...xs, e])))\n return seen\n })\n\n/** Deltas arriving faster than any settle window. */\nconst speak = (\n queue: Queue.Queue<TranscriptEvent, Cause.Done>,\n tokens: ReadonlyArray<string>,\n): Effect.Effect<void> =>\n Effect.forEach(\n tokens,\n (text) =>\n Effect.andThen(Queue.offer(queue, { _tag: \"partial\", text }), TestClock.adjust(\"100 millis\")),\n { discard: true },\n )\n\nconst opened = Effect.gen(function* () {\n const queue = yield* Queue.unbounded<TranscriptEvent, Cause.Done>()\n const seen = yield* collecting(\n Stream.fromQueue(queue).pipe(accumulatePartials({ silence: \"1 second\" })),\n )\n return { queue, seen }\n})\n\ndescribe(\"accumulatePartials\", () => {\n it.effect(\"joins deltas into the running hypothesis, forwarding each as it arrives\", () =>\n Effect.gen(function* () {\n const { queue, seen } = yield* opened\n\n yield* speak(queue, [\" Hi\", \",\", \" how\"])\n\n // Three in, three out, each the whole sentence so far, none delayed.\n expect(yield* Ref.get(seen)).toEqual([\n { _tag: \"partial\", text: \"Hi\" },\n { _tag: \"partial\", text: \"Hi,\" },\n { _tag: \"partial\", text: \"Hi, how\" },\n ])\n }),\n )\n\n it.effect(\"commits on silence and starts the next utterance from empty\", () =>\n Effect.gen(function* () {\n const { queue, seen } = yield* opened\n\n yield* speak(queue, [\" Hi\", \" there\"])\n yield* TestClock.adjust(\"3 seconds\")\n yield* speak(queue, [\" Bye\"])\n yield* TestClock.adjust(\"3 seconds\")\n\n expect(yield* Ref.get(seen)).toEqual([\n { _tag: \"partial\", text: \"Hi\" },\n { _tag: \"partial\", text: \"Hi there\" },\n { _tag: \"final\", text: \"Hi there\" },\n { _tag: \"partial\", text: \"Bye\" },\n { _tag: \"final\", text: \"Bye\" },\n ])\n }),\n )\n\n it.effect(\"a provider's own final resets the accumulator, so silence adds no duplicate\", () =>\n Effect.gen(function* () {\n const { queue, seen } = yield* opened\n\n yield* speak(queue, [\" Hi\"])\n yield* Queue.offer(queue, { _tag: \"final\", text: \"Hi.\" })\n yield* TestClock.adjust(\"3 seconds\")\n\n expect(yield* Ref.get(seen)).toEqual([\n { _tag: \"partial\", text: \"Hi\" },\n { _tag: \"final\", text: \"Hi.\" },\n ])\n }),\n )\n\n it.effect(\"commits the pending text when the stream ends mid-utterance\", () =>\n Effect.gen(function* () {\n const { queue, seen } = yield* opened\n\n yield* speak(queue, [\" Half a sen\"])\n yield* Queue.end(queue)\n yield* TestClock.adjust(\"10 millis\")\n\n expect(yield* Ref.get(seen)).toEqual([\n { _tag: \"partial\", text: \"Half a sen\" },\n { _tag: \"final\", text: \"Half a sen\" },\n ])\n }),\n )\n})\n"],"mappings":";;;;;;;AAMA,MAAM,cAAc,WAClB,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,IAAI,KAAqC,CAAC,CAAC;CAC/D,OAAO,OAAO,UAAU,OAAO,WAAW,SAAS,MAAM,IAAI,OAAO,OAAO,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;CAC9F,OAAO;AACT,CAAC;;AAGH,MAAM,SACJ,OACA,WAEA,OAAO,QACL,SACC,SACC,OAAO,QAAQ,MAAM,MAAM,OAAO;CAAE,MAAM;CAAW;AAAK,CAAC,GAAG,UAAU,OAAO,YAAY,CAAC,GAC9F,EAAE,SAAS,KAAK,CAClB;AAEF,MAAM,SAAS,OAAO,IAAI,aAAa;CACrC,MAAM,QAAQ,OAAO,MAAM,UAAuC;CAIlE,OAAO;EAAE;EAAO,MAAA,OAHI,WAClB,OAAO,UAAU,KAAK,CAAC,CAAC,KAAK,mBAAmB,EAAE,SAAS,WAAW,CAAC,CAAC,CAC1E;CACqB;AACvB,CAAC;AAED,SAAS,4BAA4B;CACnC,GAAG,OAAO,iFACR,OAAO,IAAI,aAAa;EACtB,MAAM,EAAE,OAAO,SAAS,OAAO;EAE/B,OAAO,MAAM,OAAO;GAAC;GAAO;GAAK;EAAM,CAAC;EAGxC,aAAO,OAAO,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ;GACnC;IAAE,MAAM;IAAW,MAAM;GAAK;GAC9B;IAAE,MAAM;IAAW,MAAM;GAAM;GAC/B;IAAE,MAAM;IAAW,MAAM;GAAU;EACrC,CAAC;CACH,CAAC,CACH;CAEA,GAAG,OAAO,qEACR,OAAO,IAAI,aAAa;EACtB,MAAM,EAAE,OAAO,SAAS,OAAO;EAE/B,OAAO,MAAM,OAAO,CAAC,OAAO,QAAQ,CAAC;EACrC,OAAO,UAAU,OAAO,WAAW;EACnC,OAAO,MAAM,OAAO,CAAC,MAAM,CAAC;EAC5B,OAAO,UAAU,OAAO,WAAW;EAEnC,aAAO,OAAO,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ;GACnC;IAAE,MAAM;IAAW,MAAM;GAAK;GAC9B;IAAE,MAAM;IAAW,MAAM;GAAW;GACpC;IAAE,MAAM;IAAS,MAAM;GAAW;GAClC;IAAE,MAAM;IAAW,MAAM;GAAM;GAC/B;IAAE,MAAM;IAAS,MAAM;GAAM;EAC/B,CAAC;CACH,CAAC,CACH;CAEA,GAAG,OAAO,qFACR,OAAO,IAAI,aAAa;EACtB,MAAM,EAAE,OAAO,SAAS,OAAO;EAE/B,OAAO,MAAM,OAAO,CAAC,KAAK,CAAC;EAC3B,OAAO,MAAM,MAAM,OAAO;GAAE,MAAM;GAAS,MAAM;EAAM,CAAC;EACxD,OAAO,UAAU,OAAO,WAAW;EAEnC,aAAO,OAAO,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ,CACnC;GAAE,MAAM;GAAW,MAAM;EAAK,GAC9B;GAAE,MAAM;GAAS,MAAM;EAAM,CAC/B,CAAC;CACH,CAAC,CACH;CAEA,GAAG,OAAO,qEACR,OAAO,IAAI,aAAa;EACtB,MAAM,EAAE,OAAO,SAAS,OAAO;EAE/B,OAAO,MAAM,OAAO,CAAC,aAAa,CAAC;EACnC,OAAO,MAAM,IAAI,KAAK;EACtB,OAAO,UAAU,OAAO,WAAW;EAEnC,aAAO,OAAO,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ,CACnC;GAAE,MAAM;GAAW,MAAM;EAAa,GACtC;GAAE,MAAM;GAAS,MAAM;EAAa,CACtC,CAAC;CACH,CAAC,CACH;AACF,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as AiError } from "../AiError-
|
|
1
|
+
import { t as AiError } from "../AiError-DvhLIbmd.mjs";
|
|
2
2
|
import { EmbedInput, EmbeddingFor, ResponseEncoding, Usage } from "./Embedding.mjs";
|
|
3
3
|
import { Context, Effect } from "effect";
|
|
4
4
|
declare namespace EmbeddingModel_d_exports {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as AspectRatio } from "../Media-BbX7BAaO.mjs";
|
|
2
2
|
import { a as ImageResolution, l as ProviderData, o as ImageSource, t as GeneratedImage } from "../Image-Cv6iBLTy.mjs";
|
|
3
|
-
import { t as AiError } from "../AiError-
|
|
3
|
+
import { t as AiError } from "../AiError-DvhLIbmd.mjs";
|
|
4
4
|
import { Context, Data, Effect, Stream } from "effect";
|
|
5
5
|
declare namespace ImageGenerator_d_exports {
|
|
6
6
|
export { AspectRatio, CommonImageEditRequest, CommonImageGenerateRequest, CommonStreamImageEditRequest, CommonStreamImageRequest, GeneratedImage, ImageGenerator, ImageGeneratorService, ImageResolution, ImageResponse, ImageStreamEvent, ImageStreaming, ImageUsage, ProviderData, edit, generate, isComplete, isPartialImage, streamEdit, streamGeneration };
|
package/dist/index.d.mts
CHANGED
|
@@ -6,11 +6,12 @@ import { u as Items_d_exports } from "./Items-C7MyrYPX.mjs";
|
|
|
6
6
|
import { _ as Tool_d_exports } from "./Tool-BF78QWtn.mjs";
|
|
7
7
|
import { t as BrowserTool_d_exports } from "./browser/BrowserTool.mjs";
|
|
8
8
|
import { t as Capabilities_d_exports } from "./capabilities/Capabilities.mjs";
|
|
9
|
-
import { n as AiError_d_exports } from "./AiError-
|
|
9
|
+
import { n as AiError_d_exports } from "./AiError-DvhLIbmd.mjs";
|
|
10
10
|
import { t as Chunker_d_exports } from "./chunker/Chunker.mjs";
|
|
11
11
|
import { o as Audio_d_exports } from "./Audio-_nGR4V0X.mjs";
|
|
12
12
|
import { t as Citation_d_exports } from "./domain/Citation.mjs";
|
|
13
13
|
import { t as Music_d_exports } from "./domain/Music.mjs";
|
|
14
|
+
import { t as Realtime_d_exports } from "./domain/Realtime.mjs";
|
|
14
15
|
import { t as Job_d_exports } from "./job/Job.mjs";
|
|
15
16
|
import { a as StructuredFormat_d_exports } from "./StructuredFormat-BlZhyOsi.mjs";
|
|
16
17
|
import { t as Turn_d_exports } from "./domain/Turn.mjs";
|
|
@@ -19,12 +20,12 @@ import { t as Transcript_d_exports } from "./domain/Transcript.mjs";
|
|
|
19
20
|
import { t as Embedding_d_exports } from "./embedding-model/Embedding.mjs";
|
|
20
21
|
import { t as EmbeddingModel_d_exports } from "./embedding-model/EmbeddingModel.mjs";
|
|
21
22
|
import { t as ImageGenerator_d_exports } from "./image-generator/ImageGenerator.mjs";
|
|
22
|
-
import { t as Inbox_d_exports } from "./inbox/Inbox.mjs";
|
|
23
23
|
import { t as DeepResearch_d_exports } from "./research/DeepResearch.mjs";
|
|
24
|
-
import { t as
|
|
24
|
+
import { t as RealtimeSession_d_exports } from "./realtime/RealtimeSession.mjs";
|
|
25
|
+
import { t as Loop_d_exports } from "./Loop-ChpaO-ya.mjs";
|
|
25
26
|
import { n as ToolResult_d_exports } from "./ToolResult-BsYQRjmW.mjs";
|
|
26
27
|
import { n as ToolEvent_d_exports } from "./ToolEvent-Di4a723B.mjs";
|
|
27
|
-
import { l as Toolkit_d_exports } from "./Toolkit-
|
|
28
|
+
import { l as Toolkit_d_exports } from "./Toolkit-tlL0F2YR.mjs";
|
|
28
29
|
import { t as LanguageModel_d_exports } from "./language-model/LanguageModel.mjs";
|
|
29
30
|
import { r as MessengerError_d_exports } from "./MessengerError-CeK6VAcu.mjs";
|
|
30
31
|
import { t as Messenger_d_exports } from "./messenger/Messenger.mjs";
|
|
@@ -44,6 +45,8 @@ import { t as WebSearch_d_exports } from "./web-search/WebSearch.mjs";
|
|
|
44
45
|
import { t as WebSearchTool_d_exports } from "./web-search/WebSearchTool.mjs";
|
|
45
46
|
import { t as Vector_d_exports } from "./math/Vector.mjs";
|
|
46
47
|
import { t as Tokenizer_d_exports } from "./tokenizer/Tokenizer.mjs";
|
|
48
|
+
import { t as Settle_d_exports } from "./streaming/Settle.mjs";
|
|
49
|
+
import { t as WebSocketSession_d_exports } from "./streaming/WebSocketSession.mjs";
|
|
47
50
|
import { t as Retry_d_exports } from "./retry/Retry.mjs";
|
|
48
51
|
import { t as Approval_d_exports } from "./tool/Approval.mjs";
|
|
49
52
|
import { t as HistoryCheck_d_exports } from "./tool/HistoryCheck.mjs";
|
|
@@ -53,4 +56,4 @@ import { t as Multipart_d_exports } from "./streaming/Multipart.mjs";
|
|
|
53
56
|
import { t as SSE_d_exports } from "./streaming/SSE.mjs";
|
|
54
57
|
import { t as Metrics_d_exports } from "./observability/Metrics.mjs";
|
|
55
58
|
import { t as Telemetry_d_exports } from "./observability/Telemetry.mjs";
|
|
56
|
-
export { AiError_d_exports as AiError, Approval_d_exports as Approval, Audio_d_exports as Audio, Browser_d_exports as Browser, BrowserError_d_exports as BrowserError, BrowserTool_d_exports as BrowserTool, Capabilities_d_exports as Capabilities, Chunker_d_exports as Chunker, Citation_d_exports as Citation, DeepResearch_d_exports as DeepResearch, Embedding_d_exports as Embedding, EmbeddingModel_d_exports as EmbeddingModel, HistoryCheck_d_exports as HistoryCheck, Image_d_exports as Image, ImageGenerator_d_exports as ImageGenerator,
|
|
59
|
+
export { AiError_d_exports as AiError, Approval_d_exports as Approval, Audio_d_exports as Audio, Browser_d_exports as Browser, BrowserError_d_exports as BrowserError, BrowserTool_d_exports as BrowserTool, Capabilities_d_exports as Capabilities, Chunker_d_exports as Chunker, Citation_d_exports as Citation, DeepResearch_d_exports as DeepResearch, Embedding_d_exports as Embedding, EmbeddingModel_d_exports as EmbeddingModel, HistoryCheck_d_exports as HistoryCheck, Image_d_exports as Image, ImageGenerator_d_exports as ImageGenerator, Items_d_exports as Items, JSONL_d_exports as JSONL, Job_d_exports as Job, LanguageModel_d_exports as LanguageModel, Lines_d_exports as Lines, Loop_d_exports as Loop, Media_d_exports as Media, Memory_d_exports as Memory, Messenger_d_exports as Messenger, MessengerAdapter_d_exports as MessengerAdapter, MessengerError_d_exports as MessengerError, Metrics_d_exports as Metrics, Multipart_d_exports as Multipart, Music_d_exports as Music, MusicGenerator_d_exports as MusicGenerator, Realtime_d_exports as Realtime, RealtimeSession_d_exports as RealtimeSession, Reranker_d_exports as Reranker, Research_d_exports as Research, Retry_d_exports as Retry, SSE_d_exports as SSE, Sandbox_d_exports as Sandbox, SandboxError_d_exports as SandboxError, SandboxImage_d_exports as SandboxImage, SandboxNetwork_d_exports as SandboxNetwork, Settle_d_exports as Settle, SpeechSynthesizer_d_exports as SpeechSynthesizer, StructuredFormat_d_exports as StructuredFormat, Telemetry_d_exports as Telemetry, Tokenizer_d_exports as Tokenizer, Tool_d_exports as Tool, ToolEvent_d_exports as ToolEvent, ToolResult_d_exports as ToolResult, Toolkit_d_exports as Toolkit, Transcriber_d_exports as Transcriber, Transcript_d_exports as Transcript, Turn_d_exports as Turn, Vector_d_exports as Vector, WebRead_d_exports as WebRead, WebReadTool_d_exports as WebReadTool, WebSearch_d_exports as WebSearch, WebSearchTool_d_exports as WebSearchTool, WebSocketSession_d_exports as WebSocketSession };
|
package/dist/index.mjs
CHANGED
|
@@ -20,6 +20,9 @@ import { t as Job_exports } from "./job/Job.mjs";
|
|
|
20
20
|
import { t as DeepResearch_exports } from "./research/DeepResearch.mjs";
|
|
21
21
|
import { t as Music_exports } from "./domain/Music.mjs";
|
|
22
22
|
import { t as Research_exports } from "./domain/Research.mjs";
|
|
23
|
+
import { t as Realtime_exports } from "./domain/Realtime.mjs";
|
|
24
|
+
import { t as RealtimeSession_exports } from "./realtime/RealtimeSession.mjs";
|
|
25
|
+
import { t as Settle_exports } from "./streaming/Settle.mjs";
|
|
23
26
|
import { t as Transcript_exports } from "./domain/Transcript.mjs";
|
|
24
27
|
import { t as Embedding_exports } from "./embedding-model/Embedding.mjs";
|
|
25
28
|
import { t as EmbeddingModel_exports } from "./embedding-model/EmbeddingModel.mjs";
|
|
@@ -43,14 +46,14 @@ import { t as WebSearch_exports } from "./web-search/WebSearch.mjs";
|
|
|
43
46
|
import { t as WebSearchTool_exports } from "./web-search/WebSearchTool.mjs";
|
|
44
47
|
import { t as Vector_exports } from "./math/Vector.mjs";
|
|
45
48
|
import { t as Tokenizer_exports } from "./tokenizer/Tokenizer.mjs";
|
|
46
|
-
import { t as
|
|
49
|
+
import { t as JSONL_exports } from "./streaming/JSONL.mjs";
|
|
50
|
+
import { t as WebSocketSession_exports } from "./streaming/WebSocketSession.mjs";
|
|
47
51
|
import { t as Retry_exports } from "./retry/Retry.mjs";
|
|
48
52
|
import { t as Approval_exports } from "./tool/Approval.mjs";
|
|
49
53
|
import { t as HistoryCheck_exports } from "./tool/HistoryCheck.mjs";
|
|
50
|
-
import { t as JSONL_exports } from "./streaming/JSONL.mjs";
|
|
51
54
|
import { t as Lines_exports } from "./streaming/Lines.mjs";
|
|
52
55
|
import { t as Multipart_exports } from "./streaming/Multipart.mjs";
|
|
53
56
|
import { t as SSE_exports } from "./streaming/SSE.mjs";
|
|
54
57
|
import { t as Metrics_exports } from "./observability/Metrics.mjs";
|
|
55
58
|
import { t as Telemetry_exports } from "./observability/Telemetry.mjs";
|
|
56
|
-
export { AiError_exports as AiError, Approval_exports as Approval, Audio_exports as Audio, Browser_exports as Browser, BrowserError_exports as BrowserError, BrowserTool_exports as BrowserTool, Capabilities_exports as Capabilities, Chunker_exports as Chunker, Citation_exports as Citation, DeepResearch_exports as DeepResearch, Embedding_exports as Embedding, EmbeddingModel_exports as EmbeddingModel, HistoryCheck_exports as HistoryCheck, Image_exports as Image, ImageGenerator_exports as ImageGenerator,
|
|
59
|
+
export { AiError_exports as AiError, Approval_exports as Approval, Audio_exports as Audio, Browser_exports as Browser, BrowserError_exports as BrowserError, BrowserTool_exports as BrowserTool, Capabilities_exports as Capabilities, Chunker_exports as Chunker, Citation_exports as Citation, DeepResearch_exports as DeepResearch, Embedding_exports as Embedding, EmbeddingModel_exports as EmbeddingModel, HistoryCheck_exports as HistoryCheck, Image_exports as Image, ImageGenerator_exports as ImageGenerator, Items_exports as Items, JSONL_exports as JSONL, Job_exports as Job, LanguageModel_exports as LanguageModel, Lines_exports as Lines, Loop_exports as Loop, Media_exports as Media, Memory_exports as Memory, Messenger_exports as Messenger, MessengerAdapter_exports as MessengerAdapter, MessengerError_exports as MessengerError, Metrics_exports as Metrics, Multipart_exports as Multipart, Music_exports as Music, MusicGenerator_exports as MusicGenerator, Realtime_exports as Realtime, RealtimeSession_exports as RealtimeSession, Reranker_exports as Reranker, Research_exports as Research, Retry_exports as Retry, SSE_exports as SSE, Sandbox_exports as Sandbox, SandboxError_exports as SandboxError, SandboxImage_exports as SandboxImage, SandboxNetwork_exports as SandboxNetwork, Settle_exports as Settle, SpeechSynthesizer_exports as SpeechSynthesizer, StructuredFormat_exports as StructuredFormat, Telemetry_exports as Telemetry, Tokenizer_exports as Tokenizer, Tool_exports as Tool, ToolEvent_exports as ToolEvent, ToolResult_exports as ToolResult, Toolkit_exports as Toolkit, Transcriber_exports as Transcriber, Transcript_exports as Transcript, Turn_exports as Turn, Vector_exports as Vector, WebRead_exports as WebRead, WebReadTool_exports as WebReadTool, WebSearch_exports as WebSearch, WebSearchTool_exports as WebSearchTool, WebSocketSession_exports as WebSocketSession };
|
package/dist/job/Job.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as AiError } from "../AiError-
|
|
1
|
+
import { t as AiError } from "../AiError-DvhLIbmd.mjs";
|
|
2
2
|
import { Duration, Effect } from "effect";
|
|
3
3
|
declare namespace Job_d_exports {
|
|
4
4
|
export { JobConfig, JobOps, JobRef, JobState, collect, isSettled, jobRef, run };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { o as HistoryItem } from "../Items-C7MyrYPX.mjs";
|
|
2
|
-
import { t as AiError } from "../AiError-
|
|
2
|
+
import { t as AiError } from "../AiError-DvhLIbmd.mjs";
|
|
3
3
|
import { i as StructuredFormat } from "../StructuredFormat-BlZhyOsi.mjs";
|
|
4
4
|
import { Turn, TurnEvent } from "../domain/Turn.mjs";
|
|
5
|
-
import { o as Toolkit } from "../Toolkit-
|
|
5
|
+
import { o as Toolkit } from "../Toolkit-tlL0F2YR.mjs";
|
|
6
6
|
import { Context, Effect, Stream } from "effect";
|
|
7
7
|
declare namespace LanguageModel_d_exports {
|
|
8
8
|
export { CommonRequest, LanguageModel, LanguageModelService, streamTurn, turn, turnFromStream };
|
package/dist/loop/Loop.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as StopWith, c as loopOver, d as onTurnComplete, f as stop, i as Stop, l as loopWithState, n as Next, o as Value, p as value, r as Step, s as loop, u as next } from "../Loop-
|
|
1
|
+
import { a as StopWith, c as loopOver, d as onTurnComplete, f as stop, i as Stop, l as loopWithState, n as Next, o as Value, p as value, r as Step, s as loop, u as next } from "../Loop-ChpaO-ya.mjs";
|
|
2
2
|
export { Next, Step, Stop, StopWith, Value, loop, loopOver, loopWithState, next, onTurnComplete, stop, value };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as Watermark } from "../Media-BbX7BAaO.mjs";
|
|
2
|
-
import { t as AiError } from "../AiError-
|
|
2
|
+
import { t as AiError } from "../AiError-DvhLIbmd.mjs";
|
|
3
3
|
import { n as AudioChunk } from "../Audio-_nGR4V0X.mjs";
|
|
4
4
|
import { CommonGenerateMusicRequest, CommonStreamGenerateMusicRequest, GenerateResult, MusicResult, MusicSection, MusicSessionControl, MusicSessionInput, MusicStreamEvent, WeightedPrompt } from "../domain/Music.mjs";
|
|
5
5
|
import { Context, Effect, Stream } from "effect";
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { o as ImageSource } from "../Image-Cv6iBLTy.mjs";
|
|
2
|
+
import { t as AiError } from "../AiError-DvhLIbmd.mjs";
|
|
3
|
+
import { CommonSessionRequest, RealtimeEvent, RealtimeInput } from "../domain/Realtime.mjs";
|
|
4
|
+
import { Context, Effect, Scope, Stream } from "effect";
|
|
5
|
+
declare namespace RealtimeSession_d_exports {
|
|
6
|
+
export { RealtimeSession, RealtimeSessionHandle, RealtimeSessionService, RealtimeVideoInput, audioDeltas, open, sendVideoFrame, toolCalls };
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The live connection. `events` ends when the socket closes cleanly; a close
|
|
10
|
+
* during a response ends it with `AiError.IncompleteTurn` instead, and never
|
|
11
|
+
* synthesizes a `ResponseDone`. `send` after close fails `Unavailable`.
|
|
12
|
+
*/
|
|
13
|
+
type RealtimeSessionHandle = {
|
|
14
|
+
readonly send: (input: RealtimeInput) => Effect.Effect<void, AiError>;
|
|
15
|
+
readonly events: Stream.Stream<RealtimeEvent, AiError>;
|
|
16
|
+
};
|
|
17
|
+
type RealtimeSessionService = {
|
|
18
|
+
/**
|
|
19
|
+
* Connect and complete the provider handshake before succeeding. Closing the
|
|
20
|
+
* `Scope` closes the socket.
|
|
21
|
+
*/
|
|
22
|
+
readonly open: (request: CommonSessionRequest) => Effect.Effect<RealtimeSessionHandle, AiError, Scope.Scope>;
|
|
23
|
+
};
|
|
24
|
+
declare const RealtimeSession_base: Context.ServiceClass<RealtimeSession, "@betalyra/effect-uai/RealtimeSession", RealtimeSessionService>;
|
|
25
|
+
declare class RealtimeSession extends RealtimeSession_base {}
|
|
26
|
+
declare const RealtimeVideoInput_base: Context.ServiceClass<RealtimeVideoInput, "@betalyra/effect-uai/capability/RealtimeVideoInput", void>;
|
|
27
|
+
/**
|
|
28
|
+
* Capability marker for sessions that accept video frames. Phantom: providers
|
|
29
|
+
* register with `Layer.succeed(RealtimeVideoInput, undefined)`. Only Gemini
|
|
30
|
+
* ships it, so `sendVideoFrame` against an OpenAI-only Layer is a type error.
|
|
31
|
+
*/
|
|
32
|
+
declare class RealtimeVideoInput extends RealtimeVideoInput_base {}
|
|
33
|
+
/** Open a session for the lifetime of the surrounding `Scope`. */
|
|
34
|
+
declare const open: (request: CommonSessionRequest) => Effect.Effect<RealtimeSessionHandle, AiError, RealtimeSession | Scope.Scope>;
|
|
35
|
+
/**
|
|
36
|
+
* Push one video frame. Requires `RealtimeVideoInput`, so a provider without
|
|
37
|
+
* video fails at `Effect.provide` rather than at runtime.
|
|
38
|
+
*/
|
|
39
|
+
declare const sendVideoFrame: (handle: RealtimeSessionHandle, frame: ImageSource) => Effect.Effect<void, AiError, RealtimeVideoInput>;
|
|
40
|
+
/** Just the audio, for wiring straight to playback. */
|
|
41
|
+
declare const audioDeltas: <E, R>(events: Stream.Stream<RealtimeEvent, E, R>) => Stream.Stream<Extract<RealtimeEvent, {
|
|
42
|
+
readonly _tag: "AudioDelta";
|
|
43
|
+
}>, E, R>;
|
|
44
|
+
/** Just the tool calls. Answer each with a `ToolResult`; the adapter resumes. */
|
|
45
|
+
declare const toolCalls: <E, R>(events: Stream.Stream<RealtimeEvent, E, R>) => Stream.Stream<Extract<RealtimeEvent, {
|
|
46
|
+
readonly _tag: "ToolCall";
|
|
47
|
+
}>, E, R>;
|
|
48
|
+
//#endregion
|
|
49
|
+
export { RealtimeSession, RealtimeSessionHandle, RealtimeSessionService, RealtimeVideoInput, audioDeltas, open, sendVideoFrame, RealtimeSession_d_exports as t, toolCalls };
|
|
50
|
+
//# sourceMappingURL=RealtimeSession.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RealtimeSession.d.mts","names":[],"sources":["../../src/realtime/RealtimeSession.ts"],"mappings":";;;;;;;;;;;;KAmBY;WACD,OAAO,OAAO,kBAAkB,OAAO,aAAa;WACpD,QAAQ,OAAO,OAAO,eAAe;;KAGpC;;;;;WAKD,OACP,SAAS,yBACN,OAAO,OAAO,uBAAuB,SAAiB,MAAM;;;cAGtD,wBAAwB;;;;;;;cASxB,2BAA2B;;cAK3B,OAAI,SACN,yBACR,OAAO,OAAO,uBAAuB,SAAiB,kBAAkB,MAAM;;;;;cAOpE,iBAAc,QACjB,uBAAqB,OACtB,gBACN,OAAO,aAAa,SAAiB;;cAO3B,cAAe,GAAG,GAAC,QACtB,OAAO,OAAO,eAAe,GAAG,OACvC,OAAO,OAAO,QAAQ;WAA0B;IAAuB,GAAG;;cAIhE,YAAa,GAAG,GAAC,QACpB,OAAO,OAAO,eAAe,GAAG,OACvC,OAAO,OAAO,QAAQ;WAA0B;IAAqB,GAAG"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { n as __exportAll } from "../rolldown-runtime-EAsCxrDo.mjs";
|
|
2
|
+
import { RealtimeEvent, RealtimeInput } from "../domain/Realtime.mjs";
|
|
3
|
+
import { Context, Effect, Stream } from "effect";
|
|
4
|
+
//#region src/realtime/RealtimeSession.ts
|
|
5
|
+
/**
|
|
6
|
+
* A duplex speech-to-speech session. The server drives turn-taking, so this is
|
|
7
|
+
* its own primitive rather than a variant of `Loop`.
|
|
8
|
+
*
|
|
9
|
+
* The session is deliberately low level: tool execution, playback, barge-in
|
|
10
|
+
* bookkeeping and reconnection are the caller's, built from `send` and
|
|
11
|
+
* `events`. There is no agent wrapper, no hidden queue and no automatic
|
|
12
|
+
* reconnect here.
|
|
13
|
+
*/
|
|
14
|
+
var RealtimeSession_exports = /* @__PURE__ */ __exportAll({
|
|
15
|
+
RealtimeSession: () => RealtimeSession,
|
|
16
|
+
RealtimeVideoInput: () => RealtimeVideoInput,
|
|
17
|
+
audioDeltas: () => audioDeltas,
|
|
18
|
+
open: () => open,
|
|
19
|
+
sendVideoFrame: () => sendVideoFrame,
|
|
20
|
+
toolCalls: () => toolCalls
|
|
21
|
+
});
|
|
22
|
+
var RealtimeSession = class extends Context.Service()("@betalyra/effect-uai/RealtimeSession") {};
|
|
23
|
+
/**
|
|
24
|
+
* Capability marker for sessions that accept video frames. Phantom: providers
|
|
25
|
+
* register with `Layer.succeed(RealtimeVideoInput, undefined)`. Only Gemini
|
|
26
|
+
* ships it, so `sendVideoFrame` against an OpenAI-only Layer is a type error.
|
|
27
|
+
*/
|
|
28
|
+
var RealtimeVideoInput = class extends Context.Service()("@betalyra/effect-uai/capability/RealtimeVideoInput") {};
|
|
29
|
+
/** Open a session for the lifetime of the surrounding `Scope`. */
|
|
30
|
+
const open = (request) => Effect.flatMap(RealtimeSession, (s) => s.open(request));
|
|
31
|
+
/**
|
|
32
|
+
* Push one video frame. Requires `RealtimeVideoInput`, so a provider without
|
|
33
|
+
* video fails at `Effect.provide` rather than at runtime.
|
|
34
|
+
*/
|
|
35
|
+
const sendVideoFrame = (handle, frame) => Effect.flatMap(RealtimeVideoInput, () => handle.send(RealtimeInput.VideoFrame({ frame })));
|
|
36
|
+
const isAudioDelta = RealtimeEvent.$is("AudioDelta");
|
|
37
|
+
const isToolCall = RealtimeEvent.$is("ToolCall");
|
|
38
|
+
/** Just the audio, for wiring straight to playback. */
|
|
39
|
+
const audioDeltas = (events) => Stream.filter(events, isAudioDelta);
|
|
40
|
+
/** Just the tool calls. Answer each with a `ToolResult`; the adapter resumes. */
|
|
41
|
+
const toolCalls = (events) => Stream.filter(events, isToolCall);
|
|
42
|
+
//#endregion
|
|
43
|
+
export { RealtimeSession, RealtimeVideoInput, audioDeltas, open, sendVideoFrame, RealtimeSession_exports as t, toolCalls };
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=RealtimeSession.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RealtimeSession.mjs","names":[],"sources":["../../src/realtime/RealtimeSession.ts"],"sourcesContent":["/**\n * A duplex speech-to-speech session. The server drives turn-taking, so this is\n * its own primitive rather than a variant of `Loop`.\n *\n * The session is deliberately low level: tool execution, playback, barge-in\n * bookkeeping and reconnection are the caller's, built from `send` and\n * `events`. There is no agent wrapper, no hidden queue and no automatic\n * reconnect here.\n */\nimport { Context, Effect, type Scope, Stream } from \"effect\"\nimport type * as AiError from \"../domain/AiError.js\"\nimport type { ImageSource } from \"../domain/Image.js\"\nimport { type CommonSessionRequest, RealtimeInput, RealtimeEvent } from \"../domain/Realtime.js\"\n\n/**\n * The live connection. `events` ends when the socket closes cleanly; a close\n * during a response ends it with `AiError.IncompleteTurn` instead, and never\n * synthesizes a `ResponseDone`. `send` after close fails `Unavailable`.\n */\nexport type RealtimeSessionHandle = {\n readonly send: (input: RealtimeInput) => Effect.Effect<void, AiError.AiError>\n readonly events: Stream.Stream<RealtimeEvent, AiError.AiError>\n}\n\nexport type RealtimeSessionService = {\n /**\n * Connect and complete the provider handshake before succeeding. Closing the\n * `Scope` closes the socket.\n */\n readonly open: (\n request: CommonSessionRequest,\n ) => Effect.Effect<RealtimeSessionHandle, AiError.AiError, Scope.Scope>\n}\n\nexport class RealtimeSession extends Context.Service<RealtimeSession, RealtimeSessionService>()(\n \"@betalyra/effect-uai/RealtimeSession\",\n) {}\n\n/**\n * Capability marker for sessions that accept video frames. Phantom: providers\n * register with `Layer.succeed(RealtimeVideoInput, undefined)`. Only Gemini\n * ships it, so `sendVideoFrame` against an OpenAI-only Layer is a type error.\n */\nexport class RealtimeVideoInput extends Context.Service<RealtimeVideoInput, void>()(\n \"@betalyra/effect-uai/capability/RealtimeVideoInput\",\n) {}\n\n/** Open a session for the lifetime of the surrounding `Scope`. */\nexport const open = (\n request: CommonSessionRequest,\n): Effect.Effect<RealtimeSessionHandle, AiError.AiError, RealtimeSession | Scope.Scope> =>\n Effect.flatMap(RealtimeSession, (s) => s.open(request))\n\n/**\n * Push one video frame. Requires `RealtimeVideoInput`, so a provider without\n * video fails at `Effect.provide` rather than at runtime.\n */\nexport const sendVideoFrame = (\n handle: RealtimeSessionHandle,\n frame: ImageSource,\n): Effect.Effect<void, AiError.AiError, RealtimeVideoInput> =>\n Effect.flatMap(RealtimeVideoInput, () => handle.send(RealtimeInput.VideoFrame({ frame })))\n\nconst isAudioDelta = RealtimeEvent.$is(\"AudioDelta\")\nconst isToolCall = RealtimeEvent.$is(\"ToolCall\")\n\n/** Just the audio, for wiring straight to playback. */\nexport const audioDeltas = <E, R>(\n events: Stream.Stream<RealtimeEvent, E, R>,\n): Stream.Stream<Extract<RealtimeEvent, { readonly _tag: \"AudioDelta\" }>, E, R> =>\n Stream.filter(events, isAudioDelta)\n\n/** Just the tool calls. Answer each with a `ToolResult`; the adapter resumes. */\nexport const toolCalls = <E, R>(\n events: Stream.Stream<RealtimeEvent, E, R>,\n): Stream.Stream<Extract<RealtimeEvent, { readonly _tag: \"ToolCall\" }>, E, R> =>\n Stream.filter(events, isToolCall)\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAkCA,IAAa,kBAAb,cAAqC,QAAQ,QAAiD,CAAC,CAC7F,sCACF,CAAC,CAAC,CAAC;;;;;;AAOH,IAAa,qBAAb,cAAwC,QAAQ,QAAkC,CAAC,CACjF,oDACF,CAAC,CAAC,CAAC;;AAGH,MAAa,QACX,YAEA,OAAO,QAAQ,kBAAkB,MAAM,EAAE,KAAK,OAAO,CAAC;;;;;AAMxD,MAAa,kBACX,QACA,UAEA,OAAO,QAAQ,0BAA0B,OAAO,KAAK,cAAc,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;AAE3F,MAAM,eAAe,cAAc,IAAI,YAAY;AACnD,MAAM,aAAa,cAAc,IAAI,UAAU;;AAG/C,MAAa,eACX,WAEA,OAAO,OAAO,QAAQ,YAAY;;AAGpC,MAAa,aACX,WAEA,OAAO,OAAO,QAAQ,UAAU"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { imageBase64 } from "../domain/Image.mjs";
|
|
2
|
+
import { RealtimeEvent, RealtimeInput } from "../domain/Realtime.mjs";
|
|
3
|
+
import { open, sendVideoFrame, toolCalls } from "./RealtimeSession.mjs";
|
|
4
|
+
import { o as describe } from "../utils-CiH_DjFW.mjs";
|
|
5
|
+
import { n as globalExpect } from "../test.DNmyFkvJ-YPzDR0Co.mjs";
|
|
6
|
+
import { t as import_dist } from "../dist-BaenoU1A.mjs";
|
|
7
|
+
import { t as it } from "../dist-nohcnkD6.mjs";
|
|
8
|
+
import { layer, layerAudioOnly } from "../testing/MockRealtimeSession.mjs";
|
|
9
|
+
import { Effect, Stream } from "effect";
|
|
10
|
+
//#region src/realtime/RealtimeSession.test.ts
|
|
11
|
+
const pcm = {
|
|
12
|
+
container: "raw",
|
|
13
|
+
encoding: "pcm_s16le",
|
|
14
|
+
sampleRate: 24e3,
|
|
15
|
+
channels: 1
|
|
16
|
+
};
|
|
17
|
+
const request = {
|
|
18
|
+
model: "gpt-realtime-2.1",
|
|
19
|
+
inputFormat: pcm,
|
|
20
|
+
outputFormat: pcm
|
|
21
|
+
};
|
|
22
|
+
const call = {
|
|
23
|
+
type: "function_call",
|
|
24
|
+
call_id: "call_1",
|
|
25
|
+
name: "get_time",
|
|
26
|
+
arguments: "{}"
|
|
27
|
+
};
|
|
28
|
+
describe("RealtimeSession against a scripted session", () => {
|
|
29
|
+
it.effect("answers each input and ends `events` when the scope closes", () => Effect.gen(function* () {
|
|
30
|
+
const mock = layer({
|
|
31
|
+
initial: [RealtimeEvent.ResponseStarted({ responseId: "r1" })],
|
|
32
|
+
onInput: (input) => RealtimeInput.$is("Audio")(input) ? [RealtimeEvent.AudioDelta({
|
|
33
|
+
responseId: "r1",
|
|
34
|
+
bytes: new Uint8Array([7])
|
|
35
|
+
})] : [RealtimeEvent.ResponseDone({
|
|
36
|
+
responseId: "r1",
|
|
37
|
+
reason: "interrupted"
|
|
38
|
+
})]
|
|
39
|
+
});
|
|
40
|
+
const handle = yield* Effect.scoped(Effect.gen(function* () {
|
|
41
|
+
const handle = yield* open(request);
|
|
42
|
+
yield* handle.send(RealtimeInput.Audio({ bytes: new Uint8Array([1, 2]) }));
|
|
43
|
+
yield* handle.send(RealtimeInput.Interrupt());
|
|
44
|
+
return handle;
|
|
45
|
+
})).pipe(Effect.provide(mock.layer));
|
|
46
|
+
const events = yield* Stream.runCollect(handle.events);
|
|
47
|
+
globalExpect(events).toEqual([
|
|
48
|
+
RealtimeEvent.ResponseStarted({ responseId: "r1" }),
|
|
49
|
+
RealtimeEvent.AudioDelta({
|
|
50
|
+
responseId: "r1",
|
|
51
|
+
bytes: new Uint8Array([7])
|
|
52
|
+
}),
|
|
53
|
+
RealtimeEvent.ResponseDone({
|
|
54
|
+
responseId: "r1",
|
|
55
|
+
reason: "interrupted"
|
|
56
|
+
})
|
|
57
|
+
]);
|
|
58
|
+
const recorder = yield* mock.recorder;
|
|
59
|
+
globalExpect(recorder.openCalls.map((r) => r.model)).toEqual(["gpt-realtime-2.1"]);
|
|
60
|
+
globalExpect(recorder.sent.map((i) => i._tag)).toEqual(["Audio", "Interrupt"]);
|
|
61
|
+
}));
|
|
62
|
+
it.effect("narrows `toolCalls` to the calls the model made", () => Effect.gen(function* () {
|
|
63
|
+
const mock = layer({ initial: [
|
|
64
|
+
RealtimeEvent.ResponseStarted({ responseId: "r1" }),
|
|
65
|
+
RealtimeEvent.ToolCall({
|
|
66
|
+
responseId: "r1",
|
|
67
|
+
call
|
|
68
|
+
}),
|
|
69
|
+
RealtimeEvent.OutputTranscriptDelta({
|
|
70
|
+
responseId: "r1",
|
|
71
|
+
text: "one moment"
|
|
72
|
+
})
|
|
73
|
+
] });
|
|
74
|
+
const handle = yield* Effect.scoped(open(request)).pipe(Effect.provide(mock.layer));
|
|
75
|
+
const calls = yield* Stream.runCollect(toolCalls(handle.events));
|
|
76
|
+
globalExpect(calls.map((e) => e.call.call_id)).toEqual(["call_1"]);
|
|
77
|
+
}));
|
|
78
|
+
});
|
|
79
|
+
describe("RealtimeVideoInput marker", () => {
|
|
80
|
+
const frame = imageBase64("aW1n", "image/jpeg");
|
|
81
|
+
it("leaves the marker unsatisfied against an audio-only Layer", () => {
|
|
82
|
+
const mock = layerAudioOnly({});
|
|
83
|
+
const program = Effect.scoped(Effect.flatMap(open(request), (handle) => sendVideoFrame(handle, frame))).pipe(Effect.provide(mock.layer));
|
|
84
|
+
(0, import_dist.expectTypeOf)(program).toEqualTypeOf();
|
|
85
|
+
});
|
|
86
|
+
it("clears R to never against a Layer that ships the marker", () => {
|
|
87
|
+
const mock = layer({});
|
|
88
|
+
const program = Effect.scoped(Effect.flatMap(open(request), (handle) => sendVideoFrame(handle, frame))).pipe(Effect.provide(mock.layer));
|
|
89
|
+
(0, import_dist.expectTypeOf)(program).toEqualTypeOf();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
//#endregion
|
|
93
|
+
export {};
|
|
94
|
+
|
|
95
|
+
//# sourceMappingURL=RealtimeSession.test.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RealtimeSession.test.mjs","names":["MockRealtimeSession.layer","MockRealtimeSession.layerAudioOnly"],"sources":["../../src/realtime/RealtimeSession.test.ts"],"sourcesContent":["import { describe, it } from \"@effect/vitest\"\nimport { Effect, Stream } from \"effect\"\nimport { expect, expectTypeOf } from \"vitest\"\nimport type * as AiError from \"../domain/AiError.js\"\nimport { imageBase64 } from \"../domain/Image.js\"\nimport { type CommonSessionRequest, RealtimeEvent, RealtimeInput } from \"../domain/Realtime.js\"\nimport * as MockRealtimeSession from \"../testing/MockRealtimeSession.js\"\nimport { RealtimeVideoInput, open, sendVideoFrame, toolCalls } from \"./RealtimeSession.js\"\n\nconst pcm = { container: \"raw\", encoding: \"pcm_s16le\", sampleRate: 24000, channels: 1 } as const\n\nconst request: CommonSessionRequest = {\n model: \"gpt-realtime-2.1\",\n inputFormat: pcm,\n outputFormat: pcm,\n}\n\nconst call = {\n type: \"function_call\",\n call_id: \"call_1\",\n name: \"get_time\",\n arguments: \"{}\",\n} as const\n\ndescribe(\"RealtimeSession against a scripted session\", () => {\n it.effect(\"answers each input and ends `events` when the scope closes\", () =>\n Effect.gen(function* () {\n const mock = MockRealtimeSession.layer({\n initial: [RealtimeEvent.ResponseStarted({ responseId: \"r1\" })],\n onInput: (input) =>\n RealtimeInput.$is(\"Audio\")(input)\n ? [RealtimeEvent.AudioDelta({ responseId: \"r1\", bytes: new Uint8Array([7]) })]\n : [RealtimeEvent.ResponseDone({ responseId: \"r1\", reason: \"interrupted\" })],\n })\n\n const handle = yield* Effect.scoped(\n Effect.gen(function* () {\n const handle = yield* open(request)\n yield* handle.send(RealtimeInput.Audio({ bytes: new Uint8Array([1, 2]) }))\n yield* handle.send(RealtimeInput.Interrupt())\n return handle\n }),\n ).pipe(Effect.provide(mock.layer))\n\n // The scope is closed, so the stream drains what is queued and ends\n // rather than hanging.\n const events = yield* Stream.runCollect(handle.events)\n expect(events).toEqual([\n RealtimeEvent.ResponseStarted({ responseId: \"r1\" }),\n RealtimeEvent.AudioDelta({ responseId: \"r1\", bytes: new Uint8Array([7]) }),\n RealtimeEvent.ResponseDone({ responseId: \"r1\", reason: \"interrupted\" }),\n ])\n\n const recorder = yield* mock.recorder\n expect(recorder.openCalls.map((r) => r.model)).toEqual([\"gpt-realtime-2.1\"])\n expect(recorder.sent.map((i) => i._tag)).toEqual([\"Audio\", \"Interrupt\"])\n }),\n )\n\n it.effect(\"narrows `toolCalls` to the calls the model made\", () =>\n Effect.gen(function* () {\n const mock = MockRealtimeSession.layer({\n initial: [\n RealtimeEvent.ResponseStarted({ responseId: \"r1\" }),\n RealtimeEvent.ToolCall({ responseId: \"r1\", call }),\n RealtimeEvent.OutputTranscriptDelta({ responseId: \"r1\", text: \"one moment\" }),\n ],\n })\n\n const handle = yield* Effect.scoped(open(request)).pipe(Effect.provide(mock.layer))\n const calls = yield* Stream.runCollect(toolCalls(handle.events))\n\n expect(calls.map((e) => e.call.call_id)).toEqual([\"call_1\"])\n }),\n )\n})\n\ndescribe(\"RealtimeVideoInput marker\", () => {\n const frame = imageBase64(\"aW1n\", \"image/jpeg\")\n\n it(\"leaves the marker unsatisfied against an audio-only Layer\", () => {\n const mock = MockRealtimeSession.layerAudioOnly({})\n const program = Effect.scoped(\n Effect.flatMap(open(request), (handle) => sendVideoFrame(handle, frame)),\n ).pipe(Effect.provide(mock.layer))\n\n // `RealtimeSession` is provided, `RealtimeVideoInput` is not, so running\n // this would be a type error.\n expectTypeOf(program).toEqualTypeOf<Effect.Effect<void, AiError.AiError, RealtimeVideoInput>>()\n })\n\n it(\"clears R to never against a Layer that ships the marker\", () => {\n const mock = MockRealtimeSession.layer({})\n const program = Effect.scoped(\n Effect.flatMap(open(request), (handle) => sendVideoFrame(handle, frame)),\n ).pipe(Effect.provide(mock.layer))\n\n expectTypeOf(program).toEqualTypeOf<Effect.Effect<void, AiError.AiError, never>>()\n })\n})\n"],"mappings":";;;;;;;;;;AASA,MAAM,MAAM;CAAE,WAAW;CAAO,UAAU;CAAa,YAAY;CAAO,UAAU;AAAE;AAEtF,MAAM,UAAgC;CACpC,OAAO;CACP,aAAa;CACb,cAAc;AAChB;AAEA,MAAM,OAAO;CACX,MAAM;CACN,SAAS;CACT,MAAM;CACN,WAAW;AACb;AAEA,SAAS,oDAAoD;CAC3D,GAAG,OAAO,oEACR,OAAO,IAAI,aAAa;EACtB,MAAM,OAAOA,MAA0B;GACrC,SAAS,CAAC,cAAc,gBAAgB,EAAE,YAAY,KAAK,CAAC,CAAC;GAC7D,UAAU,UACR,cAAc,IAAI,OAAO,CAAC,CAAC,KAAK,IAC5B,CAAC,cAAc,WAAW;IAAE,YAAY;IAAM,OAAO,IAAI,WAAW,CAAC,CAAC,CAAC;GAAE,CAAC,CAAC,IAC3E,CAAC,cAAc,aAAa;IAAE,YAAY;IAAM,QAAQ;GAAc,CAAC,CAAC;EAChF,CAAC;EAED,MAAM,SAAS,OAAO,OAAO,OAC3B,OAAO,IAAI,aAAa;GACtB,MAAM,SAAS,OAAO,KAAK,OAAO;GAClC,OAAO,OAAO,KAAK,cAAc,MAAM,EAAE,OAAO,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;GACzE,OAAO,OAAO,KAAK,cAAc,UAAU,CAAC;GAC5C,OAAO;EACT,CAAC,CACH,CAAC,CAAC,KAAK,OAAO,QAAQ,KAAK,KAAK,CAAC;EAIjC,MAAM,SAAS,OAAO,OAAO,WAAW,OAAO,MAAM;EACrD,aAAO,MAAM,CAAC,CAAC,QAAQ;GACrB,cAAc,gBAAgB,EAAE,YAAY,KAAK,CAAC;GAClD,cAAc,WAAW;IAAE,YAAY;IAAM,OAAO,IAAI,WAAW,CAAC,CAAC,CAAC;GAAE,CAAC;GACzE,cAAc,aAAa;IAAE,YAAY;IAAM,QAAQ;GAAc,CAAC;EACxE,CAAC;EAED,MAAM,WAAW,OAAO,KAAK;EAC7B,aAAO,SAAS,UAAU,KAAK,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC;EAC3E,aAAO,SAAS,KAAK,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,WAAW,CAAC;CACzE,CAAC,CACH;CAEA,GAAG,OAAO,yDACR,OAAO,IAAI,aAAa;EACtB,MAAM,OAAOA,MAA0B,EACrC,SAAS;GACP,cAAc,gBAAgB,EAAE,YAAY,KAAK,CAAC;GAClD,cAAc,SAAS;IAAE,YAAY;IAAM;GAAK,CAAC;GACjD,cAAc,sBAAsB;IAAE,YAAY;IAAM,MAAM;GAAa,CAAC;EAC9E,EACF,CAAC;EAED,MAAM,SAAS,OAAO,OAAO,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,KAAK,KAAK,CAAC;EAClF,MAAM,QAAQ,OAAO,OAAO,WAAW,UAAU,OAAO,MAAM,CAAC;EAE/D,aAAO,MAAM,KAAK,MAAM,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;CAC7D,CAAC,CACH;AACF,CAAC;AAED,SAAS,mCAAmC;CAC1C,MAAM,QAAQ,YAAY,QAAQ,YAAY;CAE9C,GAAG,mEAAmE;EACpE,MAAM,OAAOC,eAAmC,CAAC,CAAC;EAClD,MAAM,UAAU,OAAO,OACrB,OAAO,QAAQ,KAAK,OAAO,IAAI,WAAW,eAAe,QAAQ,KAAK,CAAC,CACzE,CAAC,CAAC,KAAK,OAAO,QAAQ,KAAK,KAAK,CAAC;EAIjC,CAAA,GAAA,YAAA,aAAA,CAAa,OAAO,CAAC,CAAC,cAAwE;CAChG,CAAC;CAED,GAAG,iEAAiE;EAClE,MAAM,OAAOD,MAA0B,CAAC,CAAC;EACzC,MAAM,UAAU,OAAO,OACrB,OAAO,QAAQ,KAAK,OAAO,IAAI,WAAW,eAAe,QAAQ,KAAK,CAAC,CACzE,CAAC,CAAC,KAAK,OAAO,QAAQ,KAAK,KAAK,CAAC;EAEjC,CAAA,GAAA,YAAA,aAAA,CAAa,OAAO,CAAC,CAAC,cAA2D;CACnF,CAAC;AACH,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as AiError } from "../AiError-
|
|
1
|
+
import { t as AiError } from "../AiError-DvhLIbmd.mjs";
|
|
2
2
|
import { Context, Effect } from "effect";
|
|
3
3
|
declare namespace Reranker_d_exports {
|
|
4
4
|
export { CommonRerankRequest, RerankResponse, RerankResult, RerankUsage, Reranker, RerankerService, rerank };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as AiError } from "../AiError-
|
|
1
|
+
import { t as AiError } from "../AiError-DvhLIbmd.mjs";
|
|
2
2
|
import { JobConfig } from "../job/Job.mjs";
|
|
3
3
|
import { Turn, TurnEvent } from "../domain/Turn.mjs";
|
|
4
4
|
import { ResearchJobRef, ResearchRequest, ResearchState } from "../domain/Research.mjs";
|
package/dist/retry/Retry.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as RateLimited,
|
|
1
|
+
import { d as RateLimited, h as Unavailable, m as Timeout, t as AiError, u as InvalidRequest } from "../AiError-DvhLIbmd.mjs";
|
|
2
2
|
import { Effect, Schedule, Stream } from "effect";
|
|
3
3
|
declare namespace Retry_d_exports {
|
|
4
4
|
export { Retryable, effect, isRetryable, stream };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as AiError } from "../AiError-
|
|
1
|
+
import { t as AiError } from "../AiError-DvhLIbmd.mjs";
|
|
2
2
|
import { n as AudioChunk, r as AudioFormat, t as AudioBlob } from "../Audio-_nGR4V0X.mjs";
|
|
3
3
|
import { Context, Effect, Stream } from "effect";
|
|
4
4
|
declare namespace SpeechSynthesizer_d_exports {
|