@effect-uai/core 0.2.0 → 0.4.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 +1 -1
- package/dist/{AiError-CqmYjXyx.d.mts → AiError-csR8Bhxx.d.mts} +26 -4
- package/dist/{AiError-CqmYjXyx.d.mts.map → AiError-csR8Bhxx.d.mts.map} +1 -1
- package/dist/Audio-BfCTGnH3.d.mts +61 -0
- package/dist/Audio-BfCTGnH3.d.mts.map +1 -0
- package/dist/Image-DxyXqzAM.d.mts +61 -0
- package/dist/Image-DxyXqzAM.d.mts.map +1 -0
- package/dist/{Items-D1C2686t.d.mts → Items-Hg5AsYxl.d.mts} +132 -80
- package/dist/Items-Hg5AsYxl.d.mts.map +1 -0
- package/dist/Media-D_CpcM1Z.d.mts +57 -0
- package/dist/Media-D_CpcM1Z.d.mts.map +1 -0
- package/dist/{StructuredFormat-B5ueioNr.d.mts → StructuredFormat-Cl41C56K.d.mts} +5 -5
- package/dist/StructuredFormat-Cl41C56K.d.mts.map +1 -0
- package/dist/{Tool-5wxOCuOh.d.mts → Tool-B8B5qVEy.d.mts} +13 -13
- package/dist/Tool-B8B5qVEy.d.mts.map +1 -0
- package/dist/{Turn-Bi83du4I.d.mts → Turn-7geUcKsf.d.mts} +5 -11
- package/dist/Turn-7geUcKsf.d.mts.map +1 -0
- package/dist/{chunk-CfYAbeIz.mjs → chunk-uyGKjUfl.mjs} +2 -1
- package/dist/dist-DV5ISja1.mjs +13782 -0
- package/dist/dist-DV5ISja1.mjs.map +1 -0
- package/dist/domain/AiError.d.mts +2 -2
- package/dist/domain/AiError.mjs +19 -3
- package/dist/domain/AiError.mjs.map +1 -1
- package/dist/domain/Audio.d.mts +2 -0
- package/dist/domain/Audio.mjs +14 -0
- package/dist/domain/Audio.mjs.map +1 -0
- package/dist/domain/Image.d.mts +2 -0
- package/dist/domain/Image.mjs +58 -0
- package/dist/domain/Image.mjs.map +1 -0
- package/dist/domain/Items.d.mts +2 -2
- package/dist/domain/Items.mjs +19 -42
- package/dist/domain/Items.mjs.map +1 -1
- package/dist/domain/Media.d.mts +2 -0
- package/dist/domain/Media.mjs +14 -0
- package/dist/domain/Media.mjs.map +1 -0
- package/dist/domain/Music.d.mts +116 -0
- package/dist/domain/Music.d.mts.map +1 -0
- package/dist/domain/Music.mjs +29 -0
- package/dist/domain/Music.mjs.map +1 -0
- package/dist/domain/Transcript.d.mts +95 -0
- package/dist/domain/Transcript.d.mts.map +1 -0
- package/dist/domain/Transcript.mjs +22 -0
- package/dist/domain/Transcript.mjs.map +1 -0
- package/dist/domain/Turn.d.mts +1 -1
- package/dist/domain/Turn.mjs +1 -1
- package/dist/embedding-model/Embedding.d.mts +107 -0
- package/dist/embedding-model/Embedding.d.mts.map +1 -0
- package/dist/embedding-model/Embedding.mjs +18 -0
- package/dist/embedding-model/Embedding.mjs.map +1 -0
- package/dist/embedding-model/EmbeddingModel.d.mts +97 -0
- package/dist/embedding-model/EmbeddingModel.d.mts.map +1 -0
- package/dist/embedding-model/EmbeddingModel.mjs +17 -0
- package/dist/embedding-model/EmbeddingModel.mjs.map +1 -0
- package/dist/index.d.mts +21 -7
- package/dist/index.mjs +16 -2
- package/dist/language-model/LanguageModel.d.mts +12 -20
- package/dist/language-model/LanguageModel.d.mts.map +1 -1
- package/dist/language-model/LanguageModel.mjs +3 -20
- package/dist/language-model/LanguageModel.mjs.map +1 -1
- package/dist/loop/Loop.d.mts +31 -7
- package/dist/loop/Loop.d.mts.map +1 -1
- package/dist/loop/Loop.mjs +39 -6
- package/dist/loop/Loop.mjs.map +1 -1
- package/dist/loop/Loop.test.d.mts +1 -0
- package/dist/loop/Loop.test.mjs +411 -0
- package/dist/loop/Loop.test.mjs.map +1 -0
- package/dist/magic-string.es-BgIV5Mu3.mjs +1013 -0
- package/dist/magic-string.es-BgIV5Mu3.mjs.map +1 -0
- package/dist/math/Vector.d.mts +47 -0
- package/dist/math/Vector.d.mts.map +1 -0
- package/dist/math/Vector.mjs +117 -0
- package/dist/math/Vector.mjs.map +1 -0
- package/dist/music-generator/MusicGenerator.d.mts +77 -0
- package/dist/music-generator/MusicGenerator.d.mts.map +1 -0
- package/dist/music-generator/MusicGenerator.mjs +51 -0
- package/dist/music-generator/MusicGenerator.mjs.map +1 -0
- package/dist/music-generator/MusicGenerator.test.d.mts +1 -0
- package/dist/music-generator/MusicGenerator.test.mjs +154 -0
- package/dist/music-generator/MusicGenerator.test.mjs.map +1 -0
- package/dist/observability/Metrics.d.mts +2 -2
- package/dist/observability/Metrics.d.mts.map +1 -1
- package/dist/observability/Metrics.mjs +1 -1
- package/dist/observability/Metrics.mjs.map +1 -1
- package/dist/speech-synthesizer/SpeechSynthesizer.d.mts +96 -0
- package/dist/speech-synthesizer/SpeechSynthesizer.d.mts.map +1 -0
- package/dist/speech-synthesizer/SpeechSynthesizer.mjs +48 -0
- package/dist/speech-synthesizer/SpeechSynthesizer.mjs.map +1 -0
- package/dist/speech-synthesizer/SpeechSynthesizer.test.d.mts +1 -0
- package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs +112 -0
- package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs.map +1 -0
- package/dist/streaming/JSONL.d.mts +10 -3
- package/dist/streaming/JSONL.d.mts.map +1 -1
- package/dist/streaming/JSONL.mjs +13 -2
- package/dist/streaming/JSONL.mjs.map +1 -1
- package/dist/streaming/JSONL.test.d.mts +1 -0
- package/dist/streaming/JSONL.test.mjs +70 -0
- package/dist/streaming/JSONL.test.mjs.map +1 -0
- package/dist/streaming/Lines.mjs +1 -1
- package/dist/streaming/SSE.d.mts +2 -2
- package/dist/streaming/SSE.d.mts.map +1 -1
- package/dist/streaming/SSE.mjs +1 -1
- package/dist/streaming/SSE.mjs.map +1 -1
- package/dist/streaming/SSE.test.d.mts +1 -0
- package/dist/streaming/SSE.test.mjs +72 -0
- package/dist/streaming/SSE.test.mjs.map +1 -0
- package/dist/structured-format/StructuredFormat.d.mts +1 -1
- package/dist/structured-format/StructuredFormat.mjs +1 -1
- package/dist/structured-format/StructuredFormat.mjs.map +1 -1
- package/dist/testing/MockMusicGenerator.d.mts +39 -0
- package/dist/testing/MockMusicGenerator.d.mts.map +1 -0
- package/dist/testing/MockMusicGenerator.mjs +96 -0
- package/dist/testing/MockMusicGenerator.mjs.map +1 -0
- package/dist/testing/MockProvider.d.mts +6 -6
- package/dist/testing/MockProvider.d.mts.map +1 -1
- package/dist/testing/MockProvider.mjs.map +1 -1
- package/dist/testing/MockSpeechSynthesizer.d.mts +37 -0
- package/dist/testing/MockSpeechSynthesizer.d.mts.map +1 -0
- package/dist/testing/MockSpeechSynthesizer.mjs +95 -0
- package/dist/testing/MockSpeechSynthesizer.mjs.map +1 -0
- package/dist/testing/MockTranscriber.d.mts +37 -0
- package/dist/testing/MockTranscriber.d.mts.map +1 -0
- package/dist/testing/MockTranscriber.mjs +77 -0
- package/dist/testing/MockTranscriber.mjs.map +1 -0
- package/dist/tool/HistoryCheck.d.mts +6 -3
- package/dist/tool/HistoryCheck.d.mts.map +1 -1
- package/dist/tool/HistoryCheck.mjs +7 -1
- package/dist/tool/HistoryCheck.mjs.map +1 -1
- package/dist/tool/Outcome.d.mts +138 -2
- package/dist/tool/Outcome.d.mts.map +1 -0
- package/dist/tool/Outcome.mjs +32 -10
- package/dist/tool/Outcome.mjs.map +1 -1
- package/dist/tool/Resolvers.d.mts +11 -8
- package/dist/tool/Resolvers.d.mts.map +1 -1
- package/dist/tool/Resolvers.mjs +10 -1
- package/dist/tool/Resolvers.mjs.map +1 -1
- package/dist/tool/Resolvers.test.d.mts +1 -0
- package/dist/tool/Resolvers.test.mjs +317 -0
- package/dist/tool/Resolvers.test.mjs.map +1 -0
- package/dist/tool/Tool.d.mts +1 -1
- package/dist/tool/Tool.mjs +1 -1
- package/dist/tool/Tool.mjs.map +1 -1
- package/dist/tool/ToolEvent.d.mts +151 -2
- package/dist/tool/ToolEvent.d.mts.map +1 -0
- package/dist/tool/ToolEvent.mjs +30 -4
- package/dist/tool/ToolEvent.mjs.map +1 -1
- package/dist/tool/Toolkit.d.mts +19 -10
- package/dist/tool/Toolkit.d.mts.map +1 -1
- package/dist/tool/Toolkit.mjs +5 -5
- package/dist/tool/Toolkit.mjs.map +1 -1
- package/dist/tool/Toolkit.test.d.mts +1 -0
- package/dist/tool/Toolkit.test.mjs +113 -0
- package/dist/tool/Toolkit.test.mjs.map +1 -0
- package/dist/transcriber/Transcriber.d.mts +101 -0
- package/dist/transcriber/Transcriber.d.mts.map +1 -0
- package/dist/transcriber/Transcriber.mjs +49 -0
- package/dist/transcriber/Transcriber.mjs.map +1 -0
- package/dist/transcriber/Transcriber.test.d.mts +1 -0
- package/dist/transcriber/Transcriber.test.mjs +130 -0
- package/dist/transcriber/Transcriber.test.mjs.map +1 -0
- package/package.json +65 -13
- package/src/domain/AiError.ts +21 -0
- package/src/domain/Audio.ts +88 -0
- package/src/domain/Image.ts +75 -0
- package/src/domain/Items.ts +18 -47
- package/src/domain/Media.ts +61 -0
- package/src/domain/Music.ts +121 -0
- package/src/domain/Transcript.ts +83 -0
- package/src/embedding-model/Embedding.ts +117 -0
- package/src/embedding-model/EmbeddingModel.ts +107 -0
- package/src/index.ts +15 -1
- package/src/language-model/LanguageModel.ts +2 -22
- package/src/loop/Loop.test.ts +114 -2
- package/src/loop/Loop.ts +69 -5
- package/src/math/Vector.ts +138 -0
- package/src/music-generator/MusicGenerator.test.ts +170 -0
- package/src/music-generator/MusicGenerator.ts +123 -0
- package/src/observability/Metrics.ts +1 -1
- package/src/speech-synthesizer/SpeechSynthesizer.test.ts +141 -0
- package/src/speech-synthesizer/SpeechSynthesizer.ts +131 -0
- package/src/streaming/JSONL.ts +12 -0
- package/src/streaming/SSE.ts +1 -1
- package/src/structured-format/StructuredFormat.ts +2 -2
- package/src/testing/MockMusicGenerator.ts +170 -0
- package/src/testing/MockProvider.ts +2 -2
- package/src/testing/MockSpeechSynthesizer.ts +165 -0
- package/src/testing/MockTranscriber.ts +139 -0
- package/src/tool/HistoryCheck.ts +2 -5
- package/src/tool/Outcome.ts +36 -36
- package/src/tool/Resolvers.test.ts +11 -35
- package/src/tool/Resolvers.ts +5 -14
- package/src/tool/Tool.ts +9 -9
- package/src/tool/ToolEvent.ts +28 -24
- package/src/tool/Toolkit.test.ts +97 -2
- package/src/tool/Toolkit.ts +57 -33
- package/src/transcriber/Transcriber.test.ts +125 -0
- package/src/transcriber/Transcriber.ts +127 -0
- package/dist/Items-D1C2686t.d.mts.map +0 -1
- package/dist/Outcome-GiaNvt7i.d.mts +0 -32
- package/dist/Outcome-GiaNvt7i.d.mts.map +0 -1
- package/dist/StructuredFormat-B5ueioNr.d.mts.map +0 -1
- package/dist/Tool-5wxOCuOh.d.mts.map +0 -1
- package/dist/ToolEvent-wTMgb2GO.d.mts +0 -29
- package/dist/ToolEvent-wTMgb2GO.d.mts.map +0 -1
- package/dist/Turn-Bi83du4I.d.mts.map +0 -1
- package/dist/match/Match.d.mts +0 -16
- package/dist/match/Match.d.mts.map +0 -1
- package/dist/match/Match.mjs +0 -15
- package/dist/match/Match.mjs.map +0 -1
- package/src/match/Match.ts +0 -9
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { InvalidRequest } from "../domain/AiError.mjs";
|
|
2
|
+
import { SpeechSynthesizer, TtsIncrementalText } from "../speech-synthesizer/SpeechSynthesizer.mjs";
|
|
3
|
+
import { Effect, Layer, Ref, Stream } from "effect";
|
|
4
|
+
//#region src/testing/MockSpeechSynthesizer.ts
|
|
5
|
+
const makeService = (script, record) => Effect.gen(function* () {
|
|
6
|
+
const bCursor = yield* Ref.make(0);
|
|
7
|
+
const ssCursor = yield* Ref.make(0);
|
|
8
|
+
const ssfCursor = yield* Ref.make(0);
|
|
9
|
+
return {
|
|
10
|
+
synthesize: (request) => Effect.gen(function* () {
|
|
11
|
+
yield* record.synthesize(request);
|
|
12
|
+
const i = yield* Ref.getAndUpdate(bCursor, (n) => n + 1);
|
|
13
|
+
const scripted = script.blobs ?? [];
|
|
14
|
+
if (i >= scripted.length) return yield* Effect.fail(new InvalidRequest({
|
|
15
|
+
provider: "mock",
|
|
16
|
+
raw: `MockSpeechSynthesizer exhausted: ${scripted.length} blobs scripted, but call ${i + 1} was made`
|
|
17
|
+
}));
|
|
18
|
+
return scripted[i];
|
|
19
|
+
}),
|
|
20
|
+
streamSynthesis: (request) => Stream.unwrap(Effect.gen(function* () {
|
|
21
|
+
yield* record.streamSynthesis(request);
|
|
22
|
+
const i = yield* Ref.getAndUpdate(ssCursor, (n) => n + 1);
|
|
23
|
+
const scripted = script.streamSynthesisChunks ?? [];
|
|
24
|
+
if (i >= scripted.length) return Stream.fail(new InvalidRequest({
|
|
25
|
+
provider: "mock",
|
|
26
|
+
raw: `MockSpeechSynthesizer exhausted: ${scripted.length} streamSynthesis lists scripted, but call ${i + 1} was made`
|
|
27
|
+
}));
|
|
28
|
+
return Stream.fromIterable(scripted[i]);
|
|
29
|
+
})),
|
|
30
|
+
streamSynthesisFrom: (textIn, request) => Stream.unwrap(Effect.gen(function* () {
|
|
31
|
+
yield* record.streamSynthesisFrom(request);
|
|
32
|
+
const i = yield* Ref.getAndUpdate(ssfCursor, (n) => n + 1);
|
|
33
|
+
const scripted = script.streamSynthesisFromChunks ?? [];
|
|
34
|
+
if (i >= scripted.length) return Stream.fail(new InvalidRequest({
|
|
35
|
+
provider: "mock",
|
|
36
|
+
raw: `MockSpeechSynthesizer exhausted: ${scripted.length} streamSynthesisFrom lists scripted, but call ${i + 1} was made`
|
|
37
|
+
}));
|
|
38
|
+
return Stream.drain(textIn).pipe(Stream.concat(Stream.fromIterable(scripted[i])));
|
|
39
|
+
}))
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* Layer providing the `SpeechSynthesizer` service AND the
|
|
44
|
+
* `TtsIncrementalText` capability marker. Use for the common case
|
|
45
|
+
* where code under test exercises `streamSynthesisFrom`.
|
|
46
|
+
*/
|
|
47
|
+
const layer = (script) => {
|
|
48
|
+
const bCalls = Ref.makeUnsafe([]);
|
|
49
|
+
const ssCalls = Ref.makeUnsafe([]);
|
|
50
|
+
const ssfCalls = Ref.makeUnsafe([]);
|
|
51
|
+
const synthesizerLayer = Layer.effect(SpeechSynthesizer, makeService(script, {
|
|
52
|
+
synthesize: (req) => Ref.update(bCalls, (xs) => [...xs, req]),
|
|
53
|
+
streamSynthesis: (req) => Ref.update(ssCalls, (xs) => [...xs, req]),
|
|
54
|
+
streamSynthesisFrom: (req) => Ref.update(ssfCalls, (xs) => [...xs, req])
|
|
55
|
+
}));
|
|
56
|
+
return {
|
|
57
|
+
layer: Layer.merge(synthesizerLayer, Layer.succeed(TtsIncrementalText, void 0)),
|
|
58
|
+
recorder: Effect.gen(function* () {
|
|
59
|
+
return {
|
|
60
|
+
synthesizeCalls: yield* Ref.get(bCalls),
|
|
61
|
+
streamSynthesisCalls: yield* Ref.get(ssCalls),
|
|
62
|
+
streamSynthesisFromCalls: yield* Ref.get(ssfCalls)
|
|
63
|
+
};
|
|
64
|
+
})
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Variant that omits the `TtsIncrementalText` marker — simulates a
|
|
69
|
+
* provider without incremental-text-in support (e.g. OpenAI, AWS
|
|
70
|
+
* Polly non-Generative). Calls to `streamSynthesisFrom` in code under
|
|
71
|
+
* test should be a compile-time error.
|
|
72
|
+
*/
|
|
73
|
+
const layerWithoutIncremental = (script) => {
|
|
74
|
+
const bCalls = Ref.makeUnsafe([]);
|
|
75
|
+
const ssCalls = Ref.makeUnsafe([]);
|
|
76
|
+
const ssfCalls = Ref.makeUnsafe([]);
|
|
77
|
+
return {
|
|
78
|
+
layer: Layer.effect(SpeechSynthesizer, makeService(script, {
|
|
79
|
+
synthesize: (req) => Ref.update(bCalls, (xs) => [...xs, req]),
|
|
80
|
+
streamSynthesis: (req) => Ref.update(ssCalls, (xs) => [...xs, req]),
|
|
81
|
+
streamSynthesisFrom: (req) => Ref.update(ssfCalls, (xs) => [...xs, req])
|
|
82
|
+
})),
|
|
83
|
+
recorder: Effect.gen(function* () {
|
|
84
|
+
return {
|
|
85
|
+
synthesizeCalls: yield* Ref.get(bCalls),
|
|
86
|
+
streamSynthesisCalls: yield* Ref.get(ssCalls),
|
|
87
|
+
streamSynthesisFromCalls: yield* Ref.get(ssfCalls)
|
|
88
|
+
};
|
|
89
|
+
})
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
//#endregion
|
|
93
|
+
export { layer, layerWithoutIncremental };
|
|
94
|
+
|
|
95
|
+
//# sourceMappingURL=MockSpeechSynthesizer.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MockSpeechSynthesizer.mjs","names":["AiError.InvalidRequest"],"sources":["../../src/testing/MockSpeechSynthesizer.ts"],"sourcesContent":["import { Effect, Layer, Ref, Stream } from \"effect\"\nimport type { AudioBlob, AudioChunk } from \"../domain/Audio.js\"\nimport * as AiError from \"../domain/AiError.js\"\nimport {\n SpeechSynthesizer,\n TtsIncrementalText,\n type CommonStreamSynthesizeRequest,\n type CommonSynthesizeRequest,\n type SpeechSynthesizerService,\n} from \"../speech-synthesizer/SpeechSynthesizer.js\"\n\nexport type MockSynthesizerRecorder = {\n readonly synthesizeCalls: ReadonlyArray<CommonSynthesizeRequest>\n readonly streamSynthesisCalls: ReadonlyArray<CommonSynthesizeRequest>\n readonly streamSynthesisFromCalls: ReadonlyArray<CommonStreamSynthesizeRequest>\n}\n\nexport type MockSynthesizerScript = {\n /** One blob per `synthesize` call, consumed in order. */\n readonly blobs?: ReadonlyArray<AudioBlob>\n /** One chunk-list per `streamSynthesis` call, consumed in order. */\n readonly streamSynthesisChunks?: ReadonlyArray<ReadonlyArray<AudioChunk>>\n /** One chunk-list per `streamSynthesisFrom` call, consumed in order. */\n readonly streamSynthesisFromChunks?: ReadonlyArray<ReadonlyArray<AudioChunk>>\n}\n\nconst makeService = (\n script: MockSynthesizerScript,\n record: {\n readonly synthesize: (req: CommonSynthesizeRequest) => Effect.Effect<void>\n readonly streamSynthesis: (req: CommonSynthesizeRequest) => Effect.Effect<void>\n readonly streamSynthesisFrom: (req: CommonStreamSynthesizeRequest) => Effect.Effect<void>\n },\n) =>\n Effect.gen(function* () {\n const bCursor = yield* Ref.make(0)\n const ssCursor = yield* Ref.make(0)\n const ssfCursor = yield* Ref.make(0)\n const service: SpeechSynthesizerService = {\n synthesize: (request) =>\n Effect.gen(function* () {\n yield* record.synthesize(request)\n const i = yield* Ref.getAndUpdate(bCursor, (n) => n + 1)\n const scripted = script.blobs ?? []\n if (i >= scripted.length) {\n return yield* Effect.fail(\n new AiError.InvalidRequest({\n provider: \"mock\",\n raw: `MockSpeechSynthesizer exhausted: ${scripted.length} blobs scripted, but call ${i + 1} was made`,\n }),\n )\n }\n return scripted[i]!\n }),\n streamSynthesis: (request) =>\n Stream.unwrap(\n Effect.gen(function* () {\n yield* record.streamSynthesis(request)\n const i = yield* Ref.getAndUpdate(ssCursor, (n) => n + 1)\n const scripted = script.streamSynthesisChunks ?? []\n if (i >= scripted.length) {\n return Stream.fail(\n new AiError.InvalidRequest({\n provider: \"mock\",\n raw: `MockSpeechSynthesizer exhausted: ${scripted.length} streamSynthesis lists scripted, but call ${i + 1} was made`,\n }),\n )\n }\n return Stream.fromIterable(scripted[i]!)\n }),\n ),\n streamSynthesisFrom: <E, R>(\n textIn: Stream.Stream<string, E, R>,\n request: CommonStreamSynthesizeRequest,\n ): Stream.Stream<AudioChunk, AiError.AiError | E, R> =>\n Stream.unwrap(\n Effect.gen(function* () {\n yield* record.streamSynthesisFrom(request)\n const i = yield* Ref.getAndUpdate(ssfCursor, (n) => n + 1)\n const scripted = script.streamSynthesisFromChunks ?? []\n if (i >= scripted.length) {\n const exhausted: Stream.Stream<AudioChunk, AiError.AiError | E, R> = Stream.fail(\n new AiError.InvalidRequest({\n provider: \"mock\",\n raw: `MockSpeechSynthesizer exhausted: ${scripted.length} streamSynthesisFrom lists scripted, but call ${i + 1} was made`,\n }),\n )\n return exhausted\n }\n // Drain the input text fully before emitting scripted audio chunks,\n // so consumers can assert on what text was pushed.\n return Stream.drain(textIn).pipe(Stream.concat(Stream.fromIterable(scripted[i]!)))\n }),\n ),\n }\n return service\n })\n\n/**\n * Layer providing the `SpeechSynthesizer` service AND the\n * `TtsIncrementalText` capability marker. Use for the common case\n * where code under test exercises `streamSynthesisFrom`.\n */\nexport const layer = (\n script: MockSynthesizerScript,\n): {\n readonly layer: Layer.Layer<SpeechSynthesizer | TtsIncrementalText>\n readonly recorder: Effect.Effect<MockSynthesizerRecorder>\n} => {\n const bCalls = Ref.makeUnsafe<ReadonlyArray<CommonSynthesizeRequest>>([])\n const ssCalls = Ref.makeUnsafe<ReadonlyArray<CommonSynthesizeRequest>>([])\n const ssfCalls = Ref.makeUnsafe<ReadonlyArray<CommonStreamSynthesizeRequest>>([])\n const synthesizerLayer = Layer.effect(\n SpeechSynthesizer,\n makeService(script, {\n synthesize: (req) => Ref.update(bCalls, (xs) => [...xs, req]),\n streamSynthesis: (req) => Ref.update(ssCalls, (xs) => [...xs, req]),\n streamSynthesisFrom: (req) => Ref.update(ssfCalls, (xs) => [...xs, req]),\n }),\n )\n const live = Layer.merge(synthesizerLayer, Layer.succeed(TtsIncrementalText, undefined))\n return {\n layer: live,\n recorder: Effect.gen(function* () {\n const synthesizeCalls = yield* Ref.get(bCalls)\n const streamSynthesisCalls = yield* Ref.get(ssCalls)\n const streamSynthesisFromCalls = yield* Ref.get(ssfCalls)\n return { synthesizeCalls, streamSynthesisCalls, streamSynthesisFromCalls }\n }),\n }\n}\n\n/**\n * Variant that omits the `TtsIncrementalText` marker — simulates a\n * provider without incremental-text-in support (e.g. OpenAI, AWS\n * Polly non-Generative). Calls to `streamSynthesisFrom` in code under\n * test should be a compile-time error.\n */\nexport const layerWithoutIncremental = (\n script: MockSynthesizerScript,\n): {\n readonly layer: Layer.Layer<SpeechSynthesizer>\n readonly recorder: Effect.Effect<MockSynthesizerRecorder>\n} => {\n const bCalls = Ref.makeUnsafe<ReadonlyArray<CommonSynthesizeRequest>>([])\n const ssCalls = Ref.makeUnsafe<ReadonlyArray<CommonSynthesizeRequest>>([])\n const ssfCalls = Ref.makeUnsafe<ReadonlyArray<CommonStreamSynthesizeRequest>>([])\n const live = Layer.effect(\n SpeechSynthesizer,\n makeService(script, {\n synthesize: (req) => Ref.update(bCalls, (xs) => [...xs, req]),\n streamSynthesis: (req) => Ref.update(ssCalls, (xs) => [...xs, req]),\n streamSynthesisFrom: (req) => Ref.update(ssfCalls, (xs) => [...xs, req]),\n }),\n )\n return {\n layer: live,\n recorder: Effect.gen(function* () {\n const synthesizeCalls = yield* Ref.get(bCalls)\n const streamSynthesisCalls = yield* Ref.get(ssCalls)\n const streamSynthesisFromCalls = yield* Ref.get(ssfCalls)\n return { synthesizeCalls, streamSynthesisCalls, streamSynthesisFromCalls }\n }),\n }\n}\n"],"mappings":";;;;AA0BA,MAAM,eACJ,QACA,WAMA,OAAO,IAAI,aAAa;CACtB,MAAM,UAAU,OAAO,IAAI,KAAK,EAAE;CAClC,MAAM,WAAW,OAAO,IAAI,KAAK,EAAE;CACnC,MAAM,YAAY,OAAO,IAAI,KAAK,EAAE;AA0DpC,QAAO;EAxDL,aAAa,YACX,OAAO,IAAI,aAAa;AACtB,UAAO,OAAO,WAAW,QAAQ;GACjC,MAAM,IAAI,OAAO,IAAI,aAAa,UAAU,MAAM,IAAI,EAAE;GACxD,MAAM,WAAW,OAAO,SAAS,EAAE;AACnC,OAAI,KAAK,SAAS,OAChB,QAAO,OAAO,OAAO,KACnB,IAAIA,eAAuB;IACzB,UAAU;IACV,KAAK,oCAAoC,SAAS,OAAO,4BAA4B,IAAI,EAAE;IAC5F,CAAC,CACH;AAEH,UAAO,SAAS;IAChB;EACJ,kBAAkB,YAChB,OAAO,OACL,OAAO,IAAI,aAAa;AACtB,UAAO,OAAO,gBAAgB,QAAQ;GACtC,MAAM,IAAI,OAAO,IAAI,aAAa,WAAW,MAAM,IAAI,EAAE;GACzD,MAAM,WAAW,OAAO,yBAAyB,EAAE;AACnD,OAAI,KAAK,SAAS,OAChB,QAAO,OAAO,KACZ,IAAIA,eAAuB;IACzB,UAAU;IACV,KAAK,oCAAoC,SAAS,OAAO,4CAA4C,IAAI,EAAE;IAC5G,CAAC,CACH;AAEH,UAAO,OAAO,aAAa,SAAS,GAAI;IACxC,CACH;EACH,sBACE,QACA,YAEA,OAAO,OACL,OAAO,IAAI,aAAa;AACtB,UAAO,OAAO,oBAAoB,QAAQ;GAC1C,MAAM,IAAI,OAAO,IAAI,aAAa,YAAY,MAAM,IAAI,EAAE;GAC1D,MAAM,WAAW,OAAO,6BAA6B,EAAE;AACvD,OAAI,KAAK,SAAS,OAOhB,QANqE,OAAO,KAC1E,IAAIA,eAAuB;IACzB,UAAU;IACV,KAAK,oCAAoC,SAAS,OAAO,gDAAgD,IAAI,EAAE;IAChH,CAAC,CAEY;AAIlB,UAAO,OAAO,MAAM,OAAO,CAAC,KAAK,OAAO,OAAO,OAAO,aAAa,SAAS,GAAI,CAAC,CAAC;IAClF,CACH;EAES;EACd;;;;;;AAOJ,MAAa,SACX,WAIG;CACH,MAAM,SAAS,IAAI,WAAmD,EAAE,CAAC;CACzE,MAAM,UAAU,IAAI,WAAmD,EAAE,CAAC;CAC1E,MAAM,WAAW,IAAI,WAAyD,EAAE,CAAC;CACjF,MAAM,mBAAmB,MAAM,OAC7B,mBACA,YAAY,QAAQ;EAClB,aAAa,QAAQ,IAAI,OAAO,SAAS,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC;EAC7D,kBAAkB,QAAQ,IAAI,OAAO,UAAU,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC;EACnE,sBAAsB,QAAQ,IAAI,OAAO,WAAW,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC;EACzE,CAAC,CACH;AAED,QAAO;EACL,OAFW,MAAM,MAAM,kBAAkB,MAAM,QAAQ,oBAAoB,KAAA,EAAU,CAE1E;EACX,UAAU,OAAO,IAAI,aAAa;AAIhC,UAAO;IAAE,iBAAA,OAHsB,IAAI,IAAI,OAAO;IAGpB,sBAAA,OAFU,IAAI,IAAI,QAAQ;IAEJ,0BAAA,OADR,IAAI,IAAI,SAAS;IACiB;IAC1E;EACH;;;;;;;;AASH,MAAa,2BACX,WAIG;CACH,MAAM,SAAS,IAAI,WAAmD,EAAE,CAAC;CACzE,MAAM,UAAU,IAAI,WAAmD,EAAE,CAAC;CAC1E,MAAM,WAAW,IAAI,WAAyD,EAAE,CAAC;AASjF,QAAO;EACL,OATW,MAAM,OACjB,mBACA,YAAY,QAAQ;GAClB,aAAa,QAAQ,IAAI,OAAO,SAAS,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC;GAC7D,kBAAkB,QAAQ,IAAI,OAAO,UAAU,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC;GACnE,sBAAsB,QAAQ,IAAI,OAAO,WAAW,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC;GACzE,CAAC,CAGS;EACX,UAAU,OAAO,IAAI,aAAa;AAIhC,UAAO;IAAE,iBAAA,OAHsB,IAAI,IAAI,OAAO;IAGpB,sBAAA,OAFU,IAAI,IAAI,QAAQ;IAEJ,0BAAA,OADR,IAAI,IAAI,SAAS;IACiB;IAC1E;EACH"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { TranscriptEvent, TranscriptResult } from "../domain/Transcript.mjs";
|
|
2
|
+
import { CommonStreamTranscribeRequest, CommonTranscribeRequest, SttStreaming, Transcriber } from "../transcriber/Transcriber.mjs";
|
|
3
|
+
import { Effect, Layer } from "effect";
|
|
4
|
+
|
|
5
|
+
//#region src/testing/MockTranscriber.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Recorder of every call made to the mock.
|
|
8
|
+
*/
|
|
9
|
+
type MockTranscriberRecorder = {
|
|
10
|
+
readonly transcribeCalls: ReadonlyArray<CommonTranscribeRequest>;
|
|
11
|
+
readonly streamCalls: ReadonlyArray<CommonStreamTranscribeRequest>;
|
|
12
|
+
};
|
|
13
|
+
type MockTranscriberScript = {
|
|
14
|
+
/** One result per `transcribe` call, consumed in order. */readonly transcripts?: ReadonlyArray<TranscriptResult>; /** One event-list per `streamTranscriptionFrom` call, consumed in order. */
|
|
15
|
+
readonly streams?: ReadonlyArray<ReadonlyArray<TranscriptEvent>>;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Returns a Layer that provides both the `Transcriber` service and the
|
|
19
|
+
* `SttStreaming` capability marker. Use when the code under test calls
|
|
20
|
+
* `streamTranscriptionFrom`.
|
|
21
|
+
*/
|
|
22
|
+
declare const layer: (script: MockTranscriberScript) => {
|
|
23
|
+
readonly layer: Layer.Layer<Transcriber | SttStreaming>;
|
|
24
|
+
readonly recorder: Effect.Effect<MockTranscriberRecorder>;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Variant that omits the `SttStreaming` marker — use to test that
|
|
28
|
+
* consumers calling `streamTranscriptionFrom` fail to compile against
|
|
29
|
+
* a non-streaming provider.
|
|
30
|
+
*/
|
|
31
|
+
declare const layerSyncOnly: (script: MockTranscriberScript) => {
|
|
32
|
+
readonly layer: Layer.Layer<Transcriber>;
|
|
33
|
+
readonly recorder: Effect.Effect<MockTranscriberRecorder>;
|
|
34
|
+
};
|
|
35
|
+
//#endregion
|
|
36
|
+
export { MockTranscriberRecorder, MockTranscriberScript, layer, layerSyncOnly };
|
|
37
|
+
//# sourceMappingURL=MockTranscriber.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MockTranscriber.d.mts","names":[],"sources":["../../src/testing/MockTranscriber.ts"],"mappings":";;;;;;;AAcA;KAAY,uBAAA;EAAA,SACD,eAAA,EAAiB,aAAA,CAAc,uBAAA;EAAA,SAC/B,WAAA,EAAa,aAAA,CAAc,6BAAA;AAAA;AAAA,KAG1B,qBAAA;EAHY,oEAKb,WAAA,GAAc,aAAA,CAAc,gBAAA,GALF;EAAA,SAO1B,OAAA,GAAU,aAAA,CAAc,aAAA,CAAc,eAAA;AAAA;;;;;;cA6DpC,KAAA,GACX,MAAA,EAAQ,qBAAA;EAAA,SAEC,KAAA,EAAO,KAAA,CAAM,KAAA,CAAM,WAAA,GAAc,YAAA;EAAA,SACjC,QAAA,EAAU,MAAA,CAAO,MAAA,CAAO,uBAAA;AAAA;;;;;;cA2BtB,aAAA,GACX,MAAA,EAAQ,qBAAA;EAAA,SAEC,KAAA,EAAO,KAAA,CAAM,KAAA,CAAM,WAAA;EAAA,SACnB,QAAA,EAAU,MAAA,CAAO,MAAA,CAAO,uBAAA;AAAA"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { InvalidRequest } from "../domain/AiError.mjs";
|
|
2
|
+
import { SttStreaming, Transcriber } from "../transcriber/Transcriber.mjs";
|
|
3
|
+
import { Effect, Layer, Ref, Stream } from "effect";
|
|
4
|
+
//#region src/testing/MockTranscriber.ts
|
|
5
|
+
const makeService = (script, record) => Effect.gen(function* () {
|
|
6
|
+
const tCursor = yield* Ref.make(0);
|
|
7
|
+
const sCursor = yield* Ref.make(0);
|
|
8
|
+
return {
|
|
9
|
+
transcribe: (request) => Effect.gen(function* () {
|
|
10
|
+
yield* record.transcribe(request);
|
|
11
|
+
const i = yield* Ref.getAndUpdate(tCursor, (n) => n + 1);
|
|
12
|
+
const scripted = script.transcripts ?? [];
|
|
13
|
+
if (i >= scripted.length) return yield* Effect.fail(new InvalidRequest({
|
|
14
|
+
provider: "mock",
|
|
15
|
+
raw: `MockTranscriber exhausted: ${scripted.length} transcripts scripted, but call ${i + 1} was made`
|
|
16
|
+
}));
|
|
17
|
+
return scripted[i];
|
|
18
|
+
}),
|
|
19
|
+
streamTranscriptionFrom: (audioIn, request) => Stream.unwrap(Effect.gen(function* () {
|
|
20
|
+
yield* record.stream(request);
|
|
21
|
+
const i = yield* Ref.getAndUpdate(sCursor, (n) => n + 1);
|
|
22
|
+
const scripted = script.streams ?? [];
|
|
23
|
+
if (i >= scripted.length) return Stream.fail(new InvalidRequest({
|
|
24
|
+
provider: "mock",
|
|
25
|
+
raw: `MockTranscriber exhausted: ${scripted.length} streams scripted, but call ${i + 1} was made`
|
|
26
|
+
}));
|
|
27
|
+
return Stream.drain(audioIn).pipe(Stream.concat(Stream.fromIterable(scripted[i])));
|
|
28
|
+
}))
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
/**
|
|
32
|
+
* Returns a Layer that provides both the `Transcriber` service and the
|
|
33
|
+
* `SttStreaming` capability marker. Use when the code under test calls
|
|
34
|
+
* `streamTranscriptionFrom`.
|
|
35
|
+
*/
|
|
36
|
+
const layer = (script) => {
|
|
37
|
+
const tCalls = Ref.makeUnsafe([]);
|
|
38
|
+
const sCalls = Ref.makeUnsafe([]);
|
|
39
|
+
const transcriberLayer = Layer.effect(Transcriber, makeService(script, {
|
|
40
|
+
transcribe: (req) => Ref.update(tCalls, (xs) => [...xs, req]),
|
|
41
|
+
stream: (req) => Ref.update(sCalls, (xs) => [...xs, req])
|
|
42
|
+
}));
|
|
43
|
+
return {
|
|
44
|
+
layer: Layer.merge(transcriberLayer, Layer.succeed(SttStreaming, void 0)),
|
|
45
|
+
recorder: Effect.gen(function* () {
|
|
46
|
+
return {
|
|
47
|
+
transcribeCalls: yield* Ref.get(tCalls),
|
|
48
|
+
streamCalls: yield* Ref.get(sCalls)
|
|
49
|
+
};
|
|
50
|
+
})
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Variant that omits the `SttStreaming` marker — use to test that
|
|
55
|
+
* consumers calling `streamTranscriptionFrom` fail to compile against
|
|
56
|
+
* a non-streaming provider.
|
|
57
|
+
*/
|
|
58
|
+
const layerSyncOnly = (script) => {
|
|
59
|
+
const tCalls = Ref.makeUnsafe([]);
|
|
60
|
+
const sCalls = Ref.makeUnsafe([]);
|
|
61
|
+
return {
|
|
62
|
+
layer: Layer.effect(Transcriber, makeService(script, {
|
|
63
|
+
transcribe: (req) => Ref.update(tCalls, (xs) => [...xs, req]),
|
|
64
|
+
stream: (req) => Ref.update(sCalls, (xs) => [...xs, req])
|
|
65
|
+
})),
|
|
66
|
+
recorder: Effect.gen(function* () {
|
|
67
|
+
return {
|
|
68
|
+
transcribeCalls: yield* Ref.get(tCalls),
|
|
69
|
+
streamCalls: yield* Ref.get(sCalls)
|
|
70
|
+
};
|
|
71
|
+
})
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
//#endregion
|
|
75
|
+
export { layer, layerSyncOnly };
|
|
76
|
+
|
|
77
|
+
//# sourceMappingURL=MockTranscriber.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MockTranscriber.mjs","names":["AiError.InvalidRequest"],"sources":["../../src/testing/MockTranscriber.ts"],"sourcesContent":["import { Effect, Layer, Ref, Stream } from \"effect\"\nimport * as AiError from \"../domain/AiError.js\"\nimport type { TranscriptEvent, TranscriptResult } from \"../domain/Transcript.js\"\nimport {\n SttStreaming,\n Transcriber,\n type CommonStreamTranscribeRequest,\n type CommonTranscribeRequest,\n type TranscriberService,\n} from \"../transcriber/Transcriber.js\"\n\n/**\n * Recorder of every call made to the mock.\n */\nexport type MockTranscriberRecorder = {\n readonly transcribeCalls: ReadonlyArray<CommonTranscribeRequest>\n readonly streamCalls: ReadonlyArray<CommonStreamTranscribeRequest>\n}\n\nexport type MockTranscriberScript = {\n /** One result per `transcribe` call, consumed in order. */\n readonly transcripts?: ReadonlyArray<TranscriptResult>\n /** One event-list per `streamTranscriptionFrom` call, consumed in order. */\n readonly streams?: ReadonlyArray<ReadonlyArray<TranscriptEvent>>\n}\n\nconst makeService = (\n script: MockTranscriberScript,\n record: {\n readonly transcribe: (req: CommonTranscribeRequest) => Effect.Effect<void>\n readonly stream: (req: CommonStreamTranscribeRequest) => Effect.Effect<void>\n },\n) =>\n Effect.gen(function* () {\n const tCursor = yield* Ref.make(0)\n const sCursor = yield* Ref.make(0)\n const service: TranscriberService = {\n transcribe: (request) =>\n Effect.gen(function* () {\n yield* record.transcribe(request)\n const i = yield* Ref.getAndUpdate(tCursor, (n) => n + 1)\n const scripted = script.transcripts ?? []\n if (i >= scripted.length) {\n return yield* Effect.fail(\n new AiError.InvalidRequest({\n provider: \"mock\",\n raw: `MockTranscriber exhausted: ${scripted.length} transcripts scripted, but call ${i + 1} was made`,\n }),\n )\n }\n return scripted[i]!\n }),\n streamTranscriptionFrom: <E, R>(\n audioIn: Stream.Stream<Uint8Array, E, R>,\n request: CommonStreamTranscribeRequest,\n ): Stream.Stream<TranscriptEvent, AiError.AiError | E, R> =>\n Stream.unwrap(\n Effect.gen(function* () {\n yield* record.stream(request)\n const i = yield* Ref.getAndUpdate(sCursor, (n) => n + 1)\n const scripted = script.streams ?? []\n if (i >= scripted.length) {\n const exhausted: Stream.Stream<TranscriptEvent, AiError.AiError | E, R> = Stream.fail(\n new AiError.InvalidRequest({\n provider: \"mock\",\n raw: `MockTranscriber exhausted: ${scripted.length} streams scripted, but call ${i + 1} was made`,\n }),\n )\n return exhausted\n }\n // Drain the input audio fully before emitting the scripted events,\n // so consumers can assert on what bytes were pushed.\n return Stream.drain(audioIn).pipe(Stream.concat(Stream.fromIterable(scripted[i]!)))\n }),\n ),\n }\n return service\n })\n\n/**\n * Returns a Layer that provides both the `Transcriber` service and the\n * `SttStreaming` capability marker. Use when the code under test calls\n * `streamTranscriptionFrom`.\n */\nexport const layer = (\n script: MockTranscriberScript,\n): {\n readonly layer: Layer.Layer<Transcriber | SttStreaming>\n readonly recorder: Effect.Effect<MockTranscriberRecorder>\n} => {\n const tCalls = Ref.makeUnsafe<ReadonlyArray<CommonTranscribeRequest>>([])\n const sCalls = Ref.makeUnsafe<ReadonlyArray<CommonStreamTranscribeRequest>>([])\n const transcriberLayer = Layer.effect(\n Transcriber,\n makeService(script, {\n transcribe: (req) => Ref.update(tCalls, (xs) => [...xs, req]),\n stream: (req) => Ref.update(sCalls, (xs) => [...xs, req]),\n }),\n )\n const live = Layer.merge(transcriberLayer, Layer.succeed(SttStreaming, undefined))\n return {\n layer: live,\n recorder: Effect.gen(function* () {\n const transcribeCalls = yield* Ref.get(tCalls)\n const streamCalls = yield* Ref.get(sCalls)\n return { transcribeCalls, streamCalls }\n }),\n }\n}\n\n/**\n * Variant that omits the `SttStreaming` marker — use to test that\n * consumers calling `streamTranscriptionFrom` fail to compile against\n * a non-streaming provider.\n */\nexport const layerSyncOnly = (\n script: MockTranscriberScript,\n): {\n readonly layer: Layer.Layer<Transcriber>\n readonly recorder: Effect.Effect<MockTranscriberRecorder>\n} => {\n const tCalls = Ref.makeUnsafe<ReadonlyArray<CommonTranscribeRequest>>([])\n const sCalls = Ref.makeUnsafe<ReadonlyArray<CommonStreamTranscribeRequest>>([])\n const live = Layer.effect(\n Transcriber,\n makeService(script, {\n transcribe: (req) => Ref.update(tCalls, (xs) => [...xs, req]),\n stream: (req) => Ref.update(sCalls, (xs) => [...xs, req]),\n }),\n )\n return {\n layer: live,\n recorder: Effect.gen(function* () {\n const transcribeCalls = yield* Ref.get(tCalls)\n const streamCalls = yield* Ref.get(sCalls)\n return { transcribeCalls, streamCalls }\n }),\n }\n}\n"],"mappings":";;;;AA0BA,MAAM,eACJ,QACA,WAKA,OAAO,IAAI,aAAa;CACtB,MAAM,UAAU,OAAO,IAAI,KAAK,EAAE;CAClC,MAAM,UAAU,OAAO,IAAI,KAAK,EAAE;AAyClC,QAAO;EAvCL,aAAa,YACX,OAAO,IAAI,aAAa;AACtB,UAAO,OAAO,WAAW,QAAQ;GACjC,MAAM,IAAI,OAAO,IAAI,aAAa,UAAU,MAAM,IAAI,EAAE;GACxD,MAAM,WAAW,OAAO,eAAe,EAAE;AACzC,OAAI,KAAK,SAAS,OAChB,QAAO,OAAO,OAAO,KACnB,IAAIA,eAAuB;IACzB,UAAU;IACV,KAAK,8BAA8B,SAAS,OAAO,kCAAkC,IAAI,EAAE;IAC5F,CAAC,CACH;AAEH,UAAO,SAAS;IAChB;EACJ,0BACE,SACA,YAEA,OAAO,OACL,OAAO,IAAI,aAAa;AACtB,UAAO,OAAO,OAAO,QAAQ;GAC7B,MAAM,IAAI,OAAO,IAAI,aAAa,UAAU,MAAM,IAAI,EAAE;GACxD,MAAM,WAAW,OAAO,WAAW,EAAE;AACrC,OAAI,KAAK,SAAS,OAOhB,QAN0E,OAAO,KAC/E,IAAIA,eAAuB;IACzB,UAAU;IACV,KAAK,8BAA8B,SAAS,OAAO,8BAA8B,IAAI,EAAE;IACxF,CAAC,CAEY;AAIlB,UAAO,OAAO,MAAM,QAAQ,CAAC,KAAK,OAAO,OAAO,OAAO,aAAa,SAAS,GAAI,CAAC,CAAC;IACnF,CACH;EAES;EACd;;;;;;AAOJ,MAAa,SACX,WAIG;CACH,MAAM,SAAS,IAAI,WAAmD,EAAE,CAAC;CACzE,MAAM,SAAS,IAAI,WAAyD,EAAE,CAAC;CAC/E,MAAM,mBAAmB,MAAM,OAC7B,aACA,YAAY,QAAQ;EAClB,aAAa,QAAQ,IAAI,OAAO,SAAS,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC;EAC7D,SAAS,QAAQ,IAAI,OAAO,SAAS,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC;EAC1D,CAAC,CACH;AAED,QAAO;EACL,OAFW,MAAM,MAAM,kBAAkB,MAAM,QAAQ,cAAc,KAAA,EAAU,CAEpE;EACX,UAAU,OAAO,IAAI,aAAa;AAGhC,UAAO;IAAE,iBAAA,OAFsB,IAAI,IAAI,OAAO;IAEpB,aAAA,OADC,IAAI,IAAI,OAAO;IACH;IACvC;EACH;;;;;;;AAQH,MAAa,iBACX,WAIG;CACH,MAAM,SAAS,IAAI,WAAmD,EAAE,CAAC;CACzE,MAAM,SAAS,IAAI,WAAyD,EAAE,CAAC;AAQ/E,QAAO;EACL,OARW,MAAM,OACjB,aACA,YAAY,QAAQ;GAClB,aAAa,QAAQ,IAAI,OAAO,SAAS,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC;GAC7D,SAAS,QAAQ,IAAI,OAAO,SAAS,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC;GAC1D,CAAC,CAGS;EACX,UAAU,OAAO,IAAI,aAAa;AAGhC,UAAO;IAAE,iBAAA,OAFsB,IAAI,IAAI,OAAO;IAEpB,aAAA,OADC,IAAI,IAAI,OAAO;IACH;IACvC;EACH"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { d as Item, o as FunctionCall } from "../Items-Hg5AsYxl.mjs";
|
|
2
|
+
import { ToolResult } from "./Outcome.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/tool/HistoryCheck.d.ts
|
|
5
|
+
declare namespace HistoryCheck_d_exports {
|
|
6
|
+
export { cancelAllPending, findUnansweredCalls, isReconciled };
|
|
7
|
+
}
|
|
5
8
|
/**
|
|
6
9
|
* Return every `function_call` in `history` that does not have a matching
|
|
7
10
|
* `function_call_output` later in `history` (correlated by `call_id`).
|
|
@@ -20,5 +23,5 @@ declare const isReconciled: (history: ReadonlyArray<Item>) => boolean;
|
|
|
20
23
|
*/
|
|
21
24
|
declare const cancelAllPending: (history: ReadonlyArray<Item>, reason?: string) => ReadonlyArray<ToolResult>;
|
|
22
25
|
//#endregion
|
|
23
|
-
export { cancelAllPending, findUnansweredCalls, isReconciled };
|
|
26
|
+
export { cancelAllPending, findUnansweredCalls, isReconciled, HistoryCheck_d_exports as t };
|
|
24
27
|
//# sourceMappingURL=HistoryCheck.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HistoryCheck.d.mts","names":[],"sources":["../../src/tool/HistoryCheck.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"HistoryCheck.d.mts","names":[],"sources":["../../src/tool/HistoryCheck.ts"],"mappings":";;;;;;;;;;;;cAyBa,mBAAA,GAAuB,OAAA,EAAS,aAAA,CAAc,IAAA,MAAQ,aAAA,CAAc,YAAA;;cAMpE,YAAA,GAAgB,OAAA,EAAS,aAAA,CAAc,IAAA;;;;;AAApD;;;;cAWa,gBAAA,GACX,OAAA,EAAS,aAAA,CAAc,IAAA,GACvB,MAAA,cACC,aAAA,CAAc,UAAA"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { n as __exportAll } from "../chunk-uyGKjUfl.mjs";
|
|
1
2
|
import { isFunctionCall, isFunctionCallOutput } from "../domain/Items.mjs";
|
|
2
3
|
import { cancelled } from "./Outcome.mjs";
|
|
3
4
|
//#region src/tool/HistoryCheck.ts
|
|
@@ -13,6 +14,11 @@ import { cancelled } from "./Outcome.mjs";
|
|
|
13
14
|
* Recipe author calls these at known transition points (right before the
|
|
14
15
|
* next provider request). Not invoked from inside the loop.
|
|
15
16
|
*/
|
|
17
|
+
var HistoryCheck_exports = /* @__PURE__ */ __exportAll({
|
|
18
|
+
cancelAllPending: () => cancelAllPending,
|
|
19
|
+
findUnansweredCalls: () => findUnansweredCalls,
|
|
20
|
+
isReconciled: () => isReconciled
|
|
21
|
+
});
|
|
16
22
|
/**
|
|
17
23
|
* Return every `function_call` in `history` that does not have a matching
|
|
18
24
|
* `function_call_output` later in `history` (correlated by `call_id`).
|
|
@@ -34,6 +40,6 @@ const isReconciled = (history) => findUnansweredCalls(history).length === 0;
|
|
|
34
40
|
*/
|
|
35
41
|
const cancelAllPending = (history, reason) => findUnansweredCalls(history).map((call) => cancelled(call, reason));
|
|
36
42
|
//#endregion
|
|
37
|
-
export { cancelAllPending, findUnansweredCalls, isReconciled };
|
|
43
|
+
export { cancelAllPending, findUnansweredCalls, isReconciled, HistoryCheck_exports as t };
|
|
38
44
|
|
|
39
45
|
//# sourceMappingURL=HistoryCheck.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HistoryCheck.mjs","names":[],"sources":["../../src/tool/HistoryCheck.ts"],"sourcesContent":["/**\n * History-consistency primitives. Useful even WITHOUT HITL.\n *\n * Every provider rejects a new request if any prior `function_call` lacks\n * a matching `function_call_output`. Multi-turn flows that can be\n * interrupted, restarted, or branched (HITL, mid-stream abort, persisted\n * checkpoints, stateless HTTP servers) need to detect orphans and\n * synthesize closing outputs before submitting.\n *\n * Recipe author calls these at known transition points (right before the\n * next provider request). Not invoked from inside the loop.\n */\nimport {\n type FunctionCall,\n type Item,\n isFunctionCall,\n isFunctionCallOutput,\n} from \"../domain/Items.js\"\nimport { type ToolResult, cancelled } from \"./Outcome.js\"\n\n/**\n * Return every `function_call` in `history` that does not have a matching\n * `function_call_output` later in `history` (correlated by `call_id`).\n * Empty result = history is provider-submittable from this invariant.\n */\nexport const findUnansweredCalls = (
|
|
1
|
+
{"version":3,"file":"HistoryCheck.mjs","names":[],"sources":["../../src/tool/HistoryCheck.ts"],"sourcesContent":["/**\n * History-consistency primitives. Useful even WITHOUT HITL.\n *\n * Every provider rejects a new request if any prior `function_call` lacks\n * a matching `function_call_output`. Multi-turn flows that can be\n * interrupted, restarted, or branched (HITL, mid-stream abort, persisted\n * checkpoints, stateless HTTP servers) need to detect orphans and\n * synthesize closing outputs before submitting.\n *\n * Recipe author calls these at known transition points (right before the\n * next provider request). Not invoked from inside the loop.\n */\nimport {\n type FunctionCall,\n type Item,\n isFunctionCall,\n isFunctionCallOutput,\n} from \"../domain/Items.js\"\nimport { type ToolResult, cancelled } from \"./Outcome.js\"\n\n/**\n * Return every `function_call` in `history` that does not have a matching\n * `function_call_output` later in `history` (correlated by `call_id`).\n * Empty result = history is provider-submittable from this invariant.\n */\nexport const findUnansweredCalls = (history: ReadonlyArray<Item>): ReadonlyArray<FunctionCall> => {\n const answered = new Set(history.filter(isFunctionCallOutput).map((o) => o.call_id))\n return history.filter(isFunctionCall).filter((c) => !answered.has(c.call_id))\n}\n\n/** Cheap predicate: is this history submittable to a provider? */\nexport const isReconciled = (history: ReadonlyArray<Item>): boolean =>\n findUnansweredCalls(history).length === 0\n\n/**\n * Synthesize cancellation results for every unanswered call. Caller maps\n * via `toFunctionCallOutput` and appends to history before submitting.\n *\n * Use when: a new user message arrives mid-approval; an approval timer\n * fires; a persisted checkpoint contains orphans (crash recovery); a\n * stateless HTTP server reconstructed history from a stale checkpoint.\n */\nexport const cancelAllPending = (\n history: ReadonlyArray<Item>,\n reason?: string,\n): ReadonlyArray<ToolResult> => findUnansweredCalls(history).map((call) => cancelled(call, reason))\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,MAAa,uBAAuB,YAA8D;CAChG,MAAM,WAAW,IAAI,IAAI,QAAQ,OAAO,qBAAqB,CAAC,KAAK,MAAM,EAAE,QAAQ,CAAC;AACpF,QAAO,QAAQ,OAAO,eAAe,CAAC,QAAQ,MAAM,CAAC,SAAS,IAAI,EAAE,QAAQ,CAAC;;;AAI/E,MAAa,gBAAgB,YAC3B,oBAAoB,QAAQ,CAAC,WAAW;;;;;;;;;AAU1C,MAAa,oBACX,SACA,WAC8B,oBAAoB,QAAQ,CAAC,KAAK,SAAS,UAAU,MAAM,OAAO,CAAC"}
|
package/dist/tool/Outcome.d.mts
CHANGED
|
@@ -1,2 +1,138 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { o as FunctionCall, s as FunctionCallOutput } from "../Items-Hg5AsYxl.mjs";
|
|
2
|
+
import { Data } from "effect";
|
|
3
|
+
import * as _$effect_Unify0 from "effect/Unify";
|
|
4
|
+
|
|
5
|
+
//#region src/tool/Outcome.d.ts
|
|
6
|
+
declare namespace Outcome_d_exports {
|
|
7
|
+
export { ToolResult, cancelled, denied, executionError, isFailure, isValue, rejected, toFunctionCallOutput };
|
|
8
|
+
}
|
|
9
|
+
type ToolResult = Data.TaggedEnum<{
|
|
10
|
+
Value: {
|
|
11
|
+
readonly call_id: string;
|
|
12
|
+
readonly tool: string;
|
|
13
|
+
readonly value: unknown;
|
|
14
|
+
};
|
|
15
|
+
Failure: {
|
|
16
|
+
readonly call_id: string;
|
|
17
|
+
readonly tool: string;
|
|
18
|
+
readonly kind: string;
|
|
19
|
+
readonly reason?: string;
|
|
20
|
+
};
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Namespace of constructors, type guards, and matchers for `ToolResult`,
|
|
24
|
+
* provided by `Data.taggedEnum`. Use `ToolResult.$is("Value")` for type
|
|
25
|
+
* narrowing and `ToolResult.$match({ Value, Failure })` for exhaustive
|
|
26
|
+
* pattern matching. Synthetic-result helpers (`denied`, `cancelled`,
|
|
27
|
+
* `executionError`, `rejected`) below are kinder constructors than the
|
|
28
|
+
* raw `ToolResult.Failure(...)`.
|
|
29
|
+
*/
|
|
30
|
+
declare const ToolResult: {
|
|
31
|
+
readonly Value: Data.TaggedEnum.ConstructorFrom<{
|
|
32
|
+
readonly _tag: "Value";
|
|
33
|
+
readonly call_id: string;
|
|
34
|
+
readonly tool: string;
|
|
35
|
+
readonly value: unknown;
|
|
36
|
+
}, "_tag">;
|
|
37
|
+
readonly Failure: Data.TaggedEnum.ConstructorFrom<{
|
|
38
|
+
readonly _tag: "Failure";
|
|
39
|
+
readonly call_id: string;
|
|
40
|
+
readonly tool: string;
|
|
41
|
+
readonly kind: string;
|
|
42
|
+
readonly reason?: string;
|
|
43
|
+
}, "_tag">;
|
|
44
|
+
readonly $is: <Tag extends "Value" | "Failure">(tag: Tag) => (u: unknown) => u is Extract<{
|
|
45
|
+
readonly _tag: "Value";
|
|
46
|
+
readonly call_id: string;
|
|
47
|
+
readonly tool: string;
|
|
48
|
+
readonly value: unknown;
|
|
49
|
+
}, {
|
|
50
|
+
readonly _tag: Tag;
|
|
51
|
+
}> | Extract<{
|
|
52
|
+
readonly _tag: "Failure";
|
|
53
|
+
readonly call_id: string;
|
|
54
|
+
readonly tool: string;
|
|
55
|
+
readonly kind: string;
|
|
56
|
+
readonly reason?: string;
|
|
57
|
+
}, {
|
|
58
|
+
readonly _tag: Tag;
|
|
59
|
+
}>;
|
|
60
|
+
readonly $match: {
|
|
61
|
+
<Cases extends {
|
|
62
|
+
readonly Value: (args: {
|
|
63
|
+
readonly _tag: "Value";
|
|
64
|
+
readonly call_id: string;
|
|
65
|
+
readonly tool: string;
|
|
66
|
+
readonly value: unknown;
|
|
67
|
+
}) => any;
|
|
68
|
+
readonly Failure: (args: {
|
|
69
|
+
readonly _tag: "Failure";
|
|
70
|
+
readonly call_id: string;
|
|
71
|
+
readonly tool: string;
|
|
72
|
+
readonly kind: string;
|
|
73
|
+
readonly reason?: string;
|
|
74
|
+
}) => any;
|
|
75
|
+
}>(cases: Cases): (value: {
|
|
76
|
+
readonly _tag: "Value";
|
|
77
|
+
readonly call_id: string;
|
|
78
|
+
readonly tool: string;
|
|
79
|
+
readonly value: unknown;
|
|
80
|
+
} | {
|
|
81
|
+
readonly _tag: "Failure";
|
|
82
|
+
readonly call_id: string;
|
|
83
|
+
readonly tool: string;
|
|
84
|
+
readonly kind: string;
|
|
85
|
+
readonly reason?: string;
|
|
86
|
+
}) => _$effect_Unify0.Unify<ReturnType<Cases["Value" | "Failure"]>>;
|
|
87
|
+
<Cases extends {
|
|
88
|
+
readonly Value: (args: {
|
|
89
|
+
readonly _tag: "Value";
|
|
90
|
+
readonly call_id: string;
|
|
91
|
+
readonly tool: string;
|
|
92
|
+
readonly value: unknown;
|
|
93
|
+
}) => any;
|
|
94
|
+
readonly Failure: (args: {
|
|
95
|
+
readonly _tag: "Failure";
|
|
96
|
+
readonly call_id: string;
|
|
97
|
+
readonly tool: string;
|
|
98
|
+
readonly kind: string;
|
|
99
|
+
readonly reason?: string;
|
|
100
|
+
}) => any;
|
|
101
|
+
}>(value: {
|
|
102
|
+
readonly _tag: "Value";
|
|
103
|
+
readonly call_id: string;
|
|
104
|
+
readonly tool: string;
|
|
105
|
+
readonly value: unknown;
|
|
106
|
+
} | {
|
|
107
|
+
readonly _tag: "Failure";
|
|
108
|
+
readonly call_id: string;
|
|
109
|
+
readonly tool: string;
|
|
110
|
+
readonly kind: string;
|
|
111
|
+
readonly reason?: string;
|
|
112
|
+
}, cases: Cases): _$effect_Unify0.Unify<ReturnType<Cases["Value" | "Failure"]>>;
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
declare const isValue: (u: unknown) => u is {
|
|
116
|
+
readonly _tag: "Value";
|
|
117
|
+
readonly call_id: string;
|
|
118
|
+
readonly tool: string;
|
|
119
|
+
readonly value: unknown;
|
|
120
|
+
};
|
|
121
|
+
declare const isFailure: (u: unknown) => u is {
|
|
122
|
+
readonly _tag: "Failure";
|
|
123
|
+
readonly call_id: string;
|
|
124
|
+
readonly tool: string;
|
|
125
|
+
readonly kind: string;
|
|
126
|
+
readonly reason?: string;
|
|
127
|
+
};
|
|
128
|
+
declare const rejected: (call: FunctionCall, kind: string, reason?: string) => ToolResult;
|
|
129
|
+
/** Explicit user/policy rejection. */
|
|
130
|
+
declare const denied: (call: FunctionCall, reason?: string) => ToolResult;
|
|
131
|
+
/** Implicit non-answer (follow-up, inactivity, abort). */
|
|
132
|
+
declare const cancelled: (call: FunctionCall, reason?: string) => ToolResult;
|
|
133
|
+
/** Tool's own execution failed (parse error, schema, runtime crash). */
|
|
134
|
+
declare const executionError: (call: FunctionCall, reason: string) => ToolResult;
|
|
135
|
+
declare const toFunctionCallOutput: (r: ToolResult) => FunctionCallOutput;
|
|
136
|
+
//#endregion
|
|
137
|
+
export { ToolResult, cancelled, denied, executionError, isFailure, isValue, rejected, Outcome_d_exports as t, toFunctionCallOutput };
|
|
138
|
+
//# sourceMappingURL=Outcome.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Outcome.d.mts","names":[],"sources":["../../src/tool/Outcome.ts"],"mappings":";;;;;;;;KAqBY,UAAA,GAAa,IAAA,CAAK,UAAA;EAC5B,KAAA;IAAA,SACW,OAAA;IAAA,SACA,IAAA;IAAA,SACA,KAAA;EAAA;EAEX,OAAA;IAAA,SACW,OAAA;IAAA,SACA,IAAA;IAAA,SACA,IAAA;IAAA,SACA,MAAA;EAAA;AAAA;;;;;;AAYb;;;cAAa,UAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAEA,OAAA,GAAO,CAAA,cAAA,CAAA;EAAA;;;;;cACP,SAAA,GAAS,CAAA,cAAA,CAAA;EAAA;;;;;;cAMT,QAAA,GAAY,IAAA,EAAM,YAAA,EAAc,IAAA,UAAc,MAAA,cAAkB,UAAA;;cAShE,MAAA,GAAU,IAAA,EAAM,YAAA,EAAc,MAAA,cAAkB,UAAA;;cAIhD,SAAA,GAAa,IAAA,EAAM,YAAA,EAAc,MAAA,cAAkB,UAAA;;cAInD,cAAA,GAAkB,IAAA,EAAM,YAAA,EAAc,MAAA,aAAiB,UAAA;AAAA,cAOvD,oBAAA,GAAwB,CAAA,EAAG,UAAA,KAAa,kBAAA"}
|
package/dist/tool/Outcome.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { n as __exportAll } from "../chunk-uyGKjUfl.mjs";
|
|
1
2
|
import { functionCallOutput } from "../domain/Items.mjs";
|
|
2
|
-
import {
|
|
3
|
+
import { Data } from "effect";
|
|
3
4
|
//#region src/tool/Outcome.ts
|
|
4
5
|
/**
|
|
5
6
|
* Post-execution and synthetic tool results.
|
|
@@ -14,10 +15,28 @@ import { Match } from "effect";
|
|
|
14
15
|
* and `unknown` would invite non-serializable values (Date, Map, BigInt,
|
|
15
16
|
* fn). Recipes that want structured detail JSON.stringify themselves.
|
|
16
17
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
var Outcome_exports = /* @__PURE__ */ __exportAll({
|
|
19
|
+
ToolResult: () => ToolResult,
|
|
20
|
+
cancelled: () => cancelled,
|
|
21
|
+
denied: () => denied,
|
|
22
|
+
executionError: () => executionError,
|
|
23
|
+
isFailure: () => isFailure,
|
|
24
|
+
isValue: () => isValue,
|
|
25
|
+
rejected: () => rejected,
|
|
26
|
+
toFunctionCallOutput: () => toFunctionCallOutput
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* Namespace of constructors, type guards, and matchers for `ToolResult`,
|
|
30
|
+
* provided by `Data.taggedEnum`. Use `ToolResult.$is("Value")` for type
|
|
31
|
+
* narrowing and `ToolResult.$match({ Value, Failure })` for exhaustive
|
|
32
|
+
* pattern matching. Synthetic-result helpers (`denied`, `cancelled`,
|
|
33
|
+
* `executionError`, `rejected`) below are kinder constructors than the
|
|
34
|
+
* raw `ToolResult.Failure(...)`.
|
|
35
|
+
*/
|
|
36
|
+
const ToolResult = Data.taggedEnum();
|
|
37
|
+
const isValue = ToolResult.$is("Value");
|
|
38
|
+
const isFailure = ToolResult.$is("Failure");
|
|
39
|
+
const rejected = (call, kind, reason) => ToolResult.Failure({
|
|
21
40
|
call_id: call.call_id,
|
|
22
41
|
tool: call.name,
|
|
23
42
|
kind,
|
|
@@ -29,11 +48,14 @@ const denied = (call, reason) => rejected(call, "denied", reason);
|
|
|
29
48
|
const cancelled = (call, reason) => rejected(call, "cancelled", reason);
|
|
30
49
|
/** Tool's own execution failed (parse error, schema, runtime crash). */
|
|
31
50
|
const executionError = (call, reason) => rejected(call, "execution_error", reason);
|
|
32
|
-
const toFunctionCallOutput = (r) =>
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
51
|
+
const toFunctionCallOutput = (r) => ToolResult.$match(r, {
|
|
52
|
+
Value: (v) => functionCallOutput(v.call_id, JSON.stringify(v.value)),
|
|
53
|
+
Failure: (f) => functionCallOutput(f.call_id, JSON.stringify(f.reason !== void 0 ? {
|
|
54
|
+
kind: f.kind,
|
|
55
|
+
reason: f.reason
|
|
56
|
+
} : { kind: f.kind }))
|
|
57
|
+
});
|
|
36
58
|
//#endregion
|
|
37
|
-
export { cancelled, denied, executionError, isFailure, isValue, rejected, toFunctionCallOutput };
|
|
59
|
+
export { ToolResult, cancelled, denied, executionError, isFailure, isValue, rejected, Outcome_exports as t, toFunctionCallOutput };
|
|
38
60
|
|
|
39
61
|
//# sourceMappingURL=Outcome.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Outcome.mjs","names":[],"sources":["../../src/tool/Outcome.ts"],"sourcesContent":["/**\n * Post-execution and synthetic tool results.\n *\n * - Executed tools emit ToolResult.Value.\n * - Approval/cancellation policy emits synthetic ToolResult.Failure.\n *\n * Wire conversion stays at the recipe boundary via `toFunctionCallOutput`\n * so recipes can inspect, redact, or audit values before serialization.\n *\n * `output` and `reason` are `string`, not `unknown`: the wire wants strings,\n * and `unknown` would invite non-serializable values (Date, Map, BigInt,\n * fn). Recipes that want structured detail JSON.stringify themselves.\n */\nimport {
|
|
1
|
+
{"version":3,"file":"Outcome.mjs","names":[],"sources":["../../src/tool/Outcome.ts"],"sourcesContent":["/**\n * Post-execution and synthetic tool results.\n *\n * - Executed tools emit ToolResult.Value.\n * - Approval/cancellation policy emits synthetic ToolResult.Failure.\n *\n * Wire conversion stays at the recipe boundary via `toFunctionCallOutput`\n * so recipes can inspect, redact, or audit values before serialization.\n *\n * `output` and `reason` are `string`, not `unknown`: the wire wants strings,\n * and `unknown` would invite non-serializable values (Date, Map, BigInt,\n * fn). Recipes that want structured detail JSON.stringify themselves.\n */\nimport { Data } from \"effect\"\nimport type { FunctionCall, FunctionCallOutput } from \"../domain/Items.js\"\nimport { functionCallOutput } from \"../domain/Items.js\"\n\n// ---------------------------------------------------------------------------\n// ToolResult\n// ---------------------------------------------------------------------------\n\nexport type ToolResult = Data.TaggedEnum<{\n Value: {\n readonly call_id: string\n readonly tool: string\n readonly value: unknown\n }\n Failure: {\n readonly call_id: string\n readonly tool: string\n readonly kind: string\n readonly reason?: string\n }\n}>\n\n/**\n * Namespace of constructors, type guards, and matchers for `ToolResult`,\n * provided by `Data.taggedEnum`. Use `ToolResult.$is(\"Value\")` for type\n * narrowing and `ToolResult.$match({ Value, Failure })` for exhaustive\n * pattern matching. Synthetic-result helpers (`denied`, `cancelled`,\n * `executionError`, `rejected`) below are kinder constructors than the\n * raw `ToolResult.Failure(...)`.\n */\nexport const ToolResult = Data.taggedEnum<ToolResult>()\n\nexport const isValue = ToolResult.$is(\"Value\")\nexport const isFailure = ToolResult.$is(\"Failure\")\n\n// Synthesizers. `denied` and `cancelled` are operationally distinct;\n// anything else is just a recipe-chosen `kind` via `rejected`.\n// ---------------------------------------------------------------------------\n\nexport const rejected = (call: FunctionCall, kind: string, reason?: string): ToolResult =>\n ToolResult.Failure({\n call_id: call.call_id,\n tool: call.name,\n kind,\n ...(reason !== undefined ? { reason } : {}),\n })\n\n/** Explicit user/policy rejection. */\nexport const denied = (call: FunctionCall, reason?: string): ToolResult =>\n rejected(call, \"denied\", reason)\n\n/** Implicit non-answer (follow-up, inactivity, abort). */\nexport const cancelled = (call: FunctionCall, reason?: string): ToolResult =>\n rejected(call, \"cancelled\", reason)\n\n/** Tool's own execution failed (parse error, schema, runtime crash). */\nexport const executionError = (call: FunctionCall, reason: string): ToolResult =>\n rejected(call, \"execution_error\", reason)\n\n// ---------------------------------------------------------------------------\n// Wire conversion - the one place structured → string happens.\n// ---------------------------------------------------------------------------\n\nexport const toFunctionCallOutput = (r: ToolResult): FunctionCallOutput =>\n ToolResult.$match(r, {\n Value: (v) => functionCallOutput(v.call_id, JSON.stringify(v.value)),\n Failure: (f) =>\n functionCallOutput(\n f.call_id,\n JSON.stringify(\n f.reason !== undefined ? { kind: f.kind, reason: f.reason } : { kind: f.kind },\n ),\n ),\n })\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,MAAa,aAAa,KAAK,YAAwB;AAEvD,MAAa,UAAU,WAAW,IAAI,QAAQ;AAC9C,MAAa,YAAY,WAAW,IAAI,UAAU;AAMlD,MAAa,YAAY,MAAoB,MAAc,WACzD,WAAW,QAAQ;CACjB,SAAS,KAAK;CACd,MAAM,KAAK;CACX;CACA,GAAI,WAAW,KAAA,IAAY,EAAE,QAAQ,GAAG,EAAE;CAC3C,CAAC;;AAGJ,MAAa,UAAU,MAAoB,WACzC,SAAS,MAAM,UAAU,OAAO;;AAGlC,MAAa,aAAa,MAAoB,WAC5C,SAAS,MAAM,aAAa,OAAO;;AAGrC,MAAa,kBAAkB,MAAoB,WACjD,SAAS,MAAM,mBAAmB,OAAO;AAM3C,MAAa,wBAAwB,MACnC,WAAW,OAAO,GAAG;CACnB,QAAQ,MAAM,mBAAmB,EAAE,SAAS,KAAK,UAAU,EAAE,MAAM,CAAC;CACpE,UAAU,MACR,mBACE,EAAE,SACF,KAAK,UACH,EAAE,WAAW,KAAA,IAAY;EAAE,MAAM,EAAE;EAAM,QAAQ,EAAE;EAAQ,GAAG,EAAE,MAAM,EAAE,MAAM,CAC/E,CACF;CACJ,CAAC"}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import { o as FunctionCall } from "../Items-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { o as FunctionCall } from "../Items-Hg5AsYxl.mjs";
|
|
2
|
+
import { ToolResult } from "./Outcome.mjs";
|
|
3
|
+
import { ToolEvent } from "./ToolEvent.mjs";
|
|
4
4
|
import { Effect, Queue, Scope, Stream } from "effect";
|
|
5
5
|
|
|
6
6
|
//#region src/tool/Resolvers.d.ts
|
|
7
|
-
|
|
7
|
+
declare namespace Resolvers_d_exports {
|
|
8
|
+
export { ApprovalMapEntry, ToolCallDecision, ToolCallPlan, Verdict, approvalRequested, approve, fromApprovalMap, fromVerdictQueue, reject, splitToolCallDecisions };
|
|
9
|
+
}
|
|
10
|
+
type ToolCallPlan = {
|
|
8
11
|
readonly approved: ReadonlyArray<FunctionCall>;
|
|
9
12
|
readonly rejected: ReadonlyArray<ToolResult>;
|
|
10
|
-
}
|
|
13
|
+
};
|
|
11
14
|
type ToolCallDecision = {
|
|
12
15
|
readonly _tag: "Approved";
|
|
13
16
|
readonly call: FunctionCall;
|
|
@@ -19,11 +22,11 @@ declare const approve: (call: FunctionCall) => ToolCallDecision;
|
|
|
19
22
|
declare const reject: (result: ToolResult) => ToolCallDecision;
|
|
20
23
|
declare const splitToolCallDecisions: (decisions: ReadonlyArray<ToolCallDecision>) => ToolCallPlan;
|
|
21
24
|
declare const approvalRequested: (call: FunctionCall) => ToolEvent;
|
|
22
|
-
|
|
25
|
+
type Verdict = {
|
|
23
26
|
readonly call_id: string;
|
|
24
27
|
readonly decision: "approve" | "deny";
|
|
25
28
|
readonly reason?: string;
|
|
26
|
-
}
|
|
29
|
+
};
|
|
27
30
|
/**
|
|
28
31
|
* Queue-backed approval planner. Safe calls are returned immediately in
|
|
29
32
|
* `approved`; gated calls emit `ApprovalRequested` events and later produce
|
|
@@ -42,5 +45,5 @@ type ApprovalMapEntry = {
|
|
|
42
45
|
};
|
|
43
46
|
declare const fromApprovalMap: (predicate: (call: FunctionCall) => boolean, approvals: ReadonlyMap<string, ApprovalMapEntry>) => (calls: ReadonlyArray<FunctionCall>) => ToolCallPlan;
|
|
44
47
|
//#endregion
|
|
45
|
-
export { ApprovalMapEntry, ToolCallDecision, ToolCallPlan, Verdict, approvalRequested, approve, fromApprovalMap, fromVerdictQueue, reject, splitToolCallDecisions };
|
|
48
|
+
export { ApprovalMapEntry, ToolCallDecision, ToolCallPlan, Verdict, approvalRequested, approve, fromApprovalMap, fromVerdictQueue, reject, splitToolCallDecisions, Resolvers_d_exports as t };
|
|
46
49
|
//# sourceMappingURL=Resolvers.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Resolvers.d.mts","names":[],"sources":["../../src/tool/Resolvers.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"Resolvers.d.mts","names":[],"sources":["../../src/tool/Resolvers.ts"],"mappings":";;;;;;;;;KAYY,YAAA;EAAA,SACD,QAAA,EAAU,aAAA,CAAc,YAAA;EAAA,SACxB,QAAA,EAAU,aAAA,CAAc,UAAA;AAAA;AAAA,KAGvB,gBAAA;EAAA,SACG,IAAA;EAAA,SAA2B,IAAA,EAAM,YAAA;AAAA;EAAA,SACjC,IAAA;EAAA,SAA2B,MAAA,EAAQ,UAAA;AAAA;AAAA,cAErC,OAAA,GAAW,IAAA,EAAM,YAAA,KAAe,gBAAA;AAAA,cAKhC,MAAA,GAAU,MAAA,EAAQ,UAAA,KAAa,gBAAA;AAAA,cAK/B,sBAAA,GAA0B,SAAA,EAAW,aAAA,CAAc,gBAAA,MAAoB,YAAA;AAAA,cASvE,iBAAA,GAAqB,IAAA,EAAM,YAAA,KAAe,SAAA;AAAA,KAW3C,OAAA;EAAA,SACD,OAAA;EAAA,SACA,QAAA;EAAA,SACA,MAAA;AAAA;;;;;;cAQE,gBAAA,GACV,SAAA,GAAY,IAAA,EAAM,YAAA,cAA0B,QAAA,EAAU,KAAA,CAAM,OAAA,CAAQ,OAAA,OAEnE,KAAA,EAAO,aAAA,CAAc,YAAA,MACpB,MAAA,CAAO,MAAA;EAAA,SAEG,QAAA,EAAU,aAAA,CAAc,YAAA;EAAA,SACxB,SAAA,EAAW,MAAA,CAAO,MAAA,CAAO,gBAAA;EAAA,SACzB,QAAA,EAAU,MAAA,CAAO,MAAA,CAAO,SAAA;AAAA,UAGnC,KAAA,CAAM,KAAA;AAAA,KAkDE,gBAAA;EAAA,SACG,QAAA;AAAA;EAAA,SACA,QAAA;EAAA,SAA2B,MAAA;AAAA;AAAA,cAE7B,eAAA,GACV,SAAA,GAAY,IAAA,EAAM,YAAA,cAA0B,SAAA,EAAW,WAAA,SAAoB,gBAAA,OAC3E,KAAA,EAAO,aAAA,CAAc,YAAA,MAAgB,YAAA"}
|
package/dist/tool/Resolvers.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { n as __exportAll } from "../chunk-uyGKjUfl.mjs";
|
|
1
2
|
import { cancelled, denied } from "./Outcome.mjs";
|
|
2
3
|
import { Deferred, Effect, Queue, Stream } from "effect";
|
|
3
4
|
//#region src/tool/Resolvers.ts
|
|
@@ -8,6 +9,14 @@ import { Deferred, Effect, Queue, Stream } from "effect";
|
|
|
8
9
|
* results must be returned to the model. Tool execution stays explicit at
|
|
9
10
|
* the recipe boundary via `Toolkit.executeAll`.
|
|
10
11
|
*/
|
|
12
|
+
var Resolvers_exports = /* @__PURE__ */ __exportAll({
|
|
13
|
+
approvalRequested: () => approvalRequested,
|
|
14
|
+
approve: () => approve,
|
|
15
|
+
fromApprovalMap: () => fromApprovalMap,
|
|
16
|
+
fromVerdictQueue: () => fromVerdictQueue,
|
|
17
|
+
reject: () => reject,
|
|
18
|
+
splitToolCallDecisions: () => splitToolCallDecisions
|
|
19
|
+
});
|
|
11
20
|
const approve = (call) => ({
|
|
12
21
|
_tag: "Approved",
|
|
13
22
|
call
|
|
@@ -63,6 +72,6 @@ const fromApprovalMap = (predicate, approvals) => (calls) => splitToolCallDecisi
|
|
|
63
72
|
return v.decision === "approve" ? approve(call) : reject(denied(call, v.reason));
|
|
64
73
|
}));
|
|
65
74
|
//#endregion
|
|
66
|
-
export { approvalRequested, approve, fromApprovalMap, fromVerdictQueue, reject, splitToolCallDecisions };
|
|
75
|
+
export { approvalRequested, approve, fromApprovalMap, fromVerdictQueue, reject, splitToolCallDecisions, Resolvers_exports as t };
|
|
67
76
|
|
|
68
77
|
//# sourceMappingURL=Resolvers.mjs.map
|