@effect-uai/core 0.5.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/README.md +1 -1
  2. package/dist/{Audio-BfCTGnH3.d.mts → Audio-DPlTsNdz.d.mts} +3 -2
  3. package/dist/Audio-DPlTsNdz.d.mts.map +1 -0
  4. package/dist/{Items-BH8xUkoR.d.mts → Items-D8UaXQx_.d.mts} +15 -15
  5. package/dist/Items-D8UaXQx_.d.mts.map +1 -0
  6. package/dist/SandboxError-BvKypkJm.d.mts +158 -0
  7. package/dist/SandboxError-BvKypkJm.d.mts.map +1 -0
  8. package/dist/{Tool-87ViKCCO.d.mts → Tool-CiFXYjmR.d.mts} +11 -11
  9. package/dist/{Tool-87ViKCCO.d.mts.map → Tool-CiFXYjmR.d.mts.map} +1 -1
  10. package/dist/capabilities/Capabilities.d.mts +78 -0
  11. package/dist/capabilities/Capabilities.d.mts.map +1 -0
  12. package/dist/capabilities/Capabilities.mjs +65 -0
  13. package/dist/capabilities/Capabilities.mjs.map +1 -0
  14. package/dist/domain/Audio.d.mts +1 -1
  15. package/dist/domain/Audio.mjs.map +1 -1
  16. package/dist/domain/Items.d.mts +2 -2
  17. package/dist/domain/Items.mjs +15 -15
  18. package/dist/domain/Items.mjs.map +1 -1
  19. package/dist/domain/Music.d.mts +131 -72
  20. package/dist/domain/Music.d.mts.map +1 -1
  21. package/dist/domain/Music.mjs +36 -9
  22. package/dist/domain/Music.mjs.map +1 -1
  23. package/dist/domain/Transcript.d.mts +8 -2
  24. package/dist/domain/Transcript.d.mts.map +1 -1
  25. package/dist/domain/Transcript.mjs.map +1 -1
  26. package/dist/domain/Turn.d.mts +388 -2
  27. package/dist/domain/Turn.d.mts.map +1 -0
  28. package/dist/domain/Turn.mjs +13 -13
  29. package/dist/domain/Turn.mjs.map +1 -1
  30. package/dist/embedding-model/Embedding.d.mts +12 -2
  31. package/dist/embedding-model/Embedding.d.mts.map +1 -1
  32. package/dist/embedding-model/Embedding.mjs.map +1 -1
  33. package/dist/embedding-model/EmbeddingModel.d.mts +36 -23
  34. package/dist/embedding-model/EmbeddingModel.d.mts.map +1 -1
  35. package/dist/embedding-model/EmbeddingModel.mjs +20 -1
  36. package/dist/embedding-model/EmbeddingModel.mjs.map +1 -1
  37. package/dist/embedding-model/EmbeddingModel.test.mjs +15 -3
  38. package/dist/embedding-model/EmbeddingModel.test.mjs.map +1 -1
  39. package/dist/index.d.mts +13 -7
  40. package/dist/index.mjs +9 -3
  41. package/dist/language-model/LanguageModel.d.mts +5 -5
  42. package/dist/language-model/LanguageModel.d.mts.map +1 -1
  43. package/dist/language-model/LanguageModel.mjs.map +1 -1
  44. package/dist/loop/Loop.d.mts +37 -90
  45. package/dist/loop/Loop.d.mts.map +1 -1
  46. package/dist/loop/Loop.mjs +39 -93
  47. package/dist/loop/Loop.mjs.map +1 -1
  48. package/dist/loop/Loop.test.mjs +46 -54
  49. package/dist/loop/Loop.test.mjs.map +1 -1
  50. package/dist/music-generator/MusicGenerator.d.mts +48 -25
  51. package/dist/music-generator/MusicGenerator.d.mts.map +1 -1
  52. package/dist/music-generator/MusicGenerator.mjs +17 -9
  53. package/dist/music-generator/MusicGenerator.mjs.map +1 -1
  54. package/dist/music-generator/MusicGenerator.test.mjs +81 -56
  55. package/dist/music-generator/MusicGenerator.test.mjs.map +1 -1
  56. package/dist/sandbox/Memory.d.mts +53 -0
  57. package/dist/sandbox/Memory.d.mts.map +1 -0
  58. package/dist/sandbox/Memory.mjs +68 -0
  59. package/dist/sandbox/Memory.mjs.map +1 -0
  60. package/dist/sandbox/Sandbox.d.mts +717 -0
  61. package/dist/sandbox/Sandbox.d.mts.map +1 -0
  62. package/dist/sandbox/Sandbox.mjs +192 -0
  63. package/dist/sandbox/Sandbox.mjs.map +1 -0
  64. package/dist/sandbox/SandboxError.d.mts +2 -0
  65. package/dist/sandbox/SandboxError.mjs +89 -0
  66. package/dist/sandbox/SandboxError.mjs.map +1 -0
  67. package/dist/sandbox/SandboxImage.d.mts +28 -0
  68. package/dist/sandbox/SandboxImage.d.mts.map +1 -0
  69. package/dist/sandbox/SandboxImage.mjs +32 -0
  70. package/dist/sandbox/SandboxImage.mjs.map +1 -0
  71. package/dist/sandbox/SandboxNetwork.d.mts +34 -0
  72. package/dist/sandbox/SandboxNetwork.d.mts.map +1 -0
  73. package/dist/sandbox/SandboxNetwork.mjs +36 -0
  74. package/dist/sandbox/SandboxNetwork.mjs.map +1 -0
  75. package/dist/speech-synthesizer/SpeechSynthesizer.d.mts +84 -3
  76. package/dist/speech-synthesizer/SpeechSynthesizer.d.mts.map +1 -1
  77. package/dist/speech-synthesizer/SpeechSynthesizer.mjs +32 -2
  78. package/dist/speech-synthesizer/SpeechSynthesizer.mjs.map +1 -1
  79. package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs +59 -5
  80. package/dist/speech-synthesizer/SpeechSynthesizer.test.mjs.map +1 -1
  81. package/dist/testing/MockMusicGenerator.d.mts +12 -7
  82. package/dist/testing/MockMusicGenerator.d.mts.map +1 -1
  83. package/dist/testing/MockMusicGenerator.mjs +4 -3
  84. package/dist/testing/MockMusicGenerator.mjs.map +1 -1
  85. package/dist/testing/MockProvider.d.mts +3 -3
  86. package/dist/testing/MockProvider.d.mts.map +1 -1
  87. package/dist/testing/MockProvider.mjs.map +1 -1
  88. package/dist/testing/MockSandbox.d.mts +604 -0
  89. package/dist/testing/MockSandbox.d.mts.map +1 -0
  90. package/dist/testing/MockSandbox.mjs +160 -0
  91. package/dist/testing/MockSandbox.mjs.map +1 -0
  92. package/dist/testing/MockSpeechSynthesizer.d.mts +27 -12
  93. package/dist/testing/MockSpeechSynthesizer.d.mts.map +1 -1
  94. package/dist/testing/MockSpeechSynthesizer.mjs +75 -51
  95. package/dist/testing/MockSpeechSynthesizer.mjs.map +1 -1
  96. package/dist/tool/{Resolvers.d.mts → Approval.d.mts} +27 -27
  97. package/dist/tool/Approval.d.mts.map +1 -0
  98. package/dist/tool/{Resolvers.mjs → Approval.mjs} +18 -18
  99. package/dist/tool/Approval.mjs.map +1 -0
  100. package/dist/tool/{Resolvers.test.mjs → Approval.test.mjs} +40 -40
  101. package/dist/tool/Approval.test.mjs.map +1 -0
  102. package/dist/tool/HistoryCheck.d.mts +6 -6
  103. package/dist/tool/HistoryCheck.d.mts.map +1 -1
  104. package/dist/tool/HistoryCheck.mjs +5 -5
  105. package/dist/tool/HistoryCheck.mjs.map +1 -1
  106. package/dist/tool/Tool.d.mts +2 -2
  107. package/dist/tool/Tool.mjs +4 -4
  108. package/dist/tool/Tool.mjs.map +1 -1
  109. package/dist/tool/ToolEvent.d.mts +19 -19
  110. package/dist/tool/ToolEvent.d.mts.map +1 -1
  111. package/dist/tool/ToolEvent.mjs +8 -8
  112. package/dist/tool/ToolEvent.mjs.map +1 -1
  113. package/dist/tool/{Outcome.d.mts → ToolResult.d.mts} +29 -29
  114. package/dist/tool/ToolResult.d.mts.map +1 -0
  115. package/dist/tool/ToolResult.mjs +61 -0
  116. package/dist/tool/ToolResult.mjs.map +1 -0
  117. package/dist/tool/Toolkit.d.mts +58 -26
  118. package/dist/tool/Toolkit.d.mts.map +1 -1
  119. package/dist/tool/Toolkit.mjs +62 -34
  120. package/dist/tool/Toolkit.mjs.map +1 -1
  121. package/dist/tool/Toolkit.test.mjs +13 -13
  122. package/dist/tool/Toolkit.test.mjs.map +1 -1
  123. package/dist/transcriber/Transcriber.d.mts +11 -10
  124. package/dist/transcriber/Transcriber.d.mts.map +1 -1
  125. package/dist/transcriber/Transcriber.mjs.map +1 -1
  126. package/dist/transcriber/Transcriber.test.mjs +3 -3
  127. package/dist/transcriber/Transcriber.test.mjs.map +1 -1
  128. package/package.json +35 -7
  129. package/src/capabilities/Capabilities.ts +81 -0
  130. package/src/domain/Audio.ts +2 -1
  131. package/src/domain/Items.ts +9 -9
  132. package/src/domain/Music.ts +142 -68
  133. package/src/domain/Transcript.ts +7 -1
  134. package/src/domain/Turn.ts +16 -16
  135. package/src/embedding-model/Embedding.ts +11 -0
  136. package/src/embedding-model/EmbeddingModel.test.ts +15 -4
  137. package/src/embedding-model/EmbeddingModel.ts +48 -21
  138. package/src/index.ts +8 -2
  139. package/src/language-model/LanguageModel.ts +3 -3
  140. package/src/loop/Loop.test.ts +93 -91
  141. package/src/loop/Loop.ts +72 -170
  142. package/src/music-generator/MusicGenerator.test.ts +78 -53
  143. package/src/music-generator/MusicGenerator.ts +65 -24
  144. package/src/sandbox/Memory.ts +128 -0
  145. package/src/sandbox/Sandbox.ts +639 -0
  146. package/src/sandbox/SandboxError.ts +140 -0
  147. package/src/sandbox/SandboxImage.ts +26 -0
  148. package/src/sandbox/SandboxNetwork.ts +34 -0
  149. package/src/speech-synthesizer/SpeechSynthesizer.test.ts +92 -3
  150. package/src/speech-synthesizer/SpeechSynthesizer.ts +109 -0
  151. package/src/testing/MockMusicGenerator.ts +28 -18
  152. package/src/testing/MockProvider.ts +21 -20
  153. package/src/testing/MockSandbox.ts +342 -0
  154. package/src/testing/MockSpeechSynthesizer.ts +137 -77
  155. package/src/tool/{Resolvers.test.ts → Approval.test.ts} +45 -54
  156. package/src/tool/{Resolvers.ts → Approval.ts} +25 -25
  157. package/src/tool/HistoryCheck.ts +10 -13
  158. package/src/tool/Tool.ts +13 -15
  159. package/src/tool/ToolEvent.ts +7 -7
  160. package/src/tool/{Outcome.ts → ToolResult.ts} +20 -20
  161. package/src/tool/Toolkit.test.ts +13 -13
  162. package/src/tool/Toolkit.ts +97 -73
  163. package/src/transcriber/Transcriber.test.ts +3 -3
  164. package/src/transcriber/Transcriber.ts +10 -7
  165. package/dist/Audio-BfCTGnH3.d.mts.map +0 -1
  166. package/dist/Items-BH8xUkoR.d.mts.map +0 -1
  167. package/dist/Turn-0CwCAyVe.d.mts +0 -388
  168. package/dist/Turn-0CwCAyVe.d.mts.map +0 -1
  169. package/dist/tool/Outcome.d.mts.map +0 -1
  170. package/dist/tool/Outcome.mjs +0 -61
  171. package/dist/tool/Outcome.mjs.map +0 -1
  172. package/dist/tool/Resolvers.d.mts.map +0 -1
  173. package/dist/tool/Resolvers.mjs.map +0 -1
  174. package/dist/tool/Resolvers.test.mjs.map +0 -1
  175. /package/dist/tool/{Resolvers.test.d.mts → Approval.test.d.mts} +0 -0
@@ -0,0 +1,160 @@
1
+ import { ExecEvent, Sandbox, SandboxCustomImage, SandboxHostnameAllowlist, SandboxId, SandboxKernelSession, SandboxPauseResume, SandboxPortExposure, SandboxPty, SandboxSecretInjection, SandboxSnapshots, SandboxVolumes, SnapshotId, VolumeId } from "../sandbox/Sandbox.mjs";
2
+ import { SandboxExecFailed, SandboxInvalidRequest } from "../sandbox/SandboxError.mjs";
3
+ import { Array, Data, Effect, Layer, Ref, Stream } from "effect";
4
+ //#region src/testing/MockSandbox.ts
5
+ const Call = Data.taggedEnum();
6
+ const defaultExec = {
7
+ exitCode: 0,
8
+ stdout: "",
9
+ stderr: "",
10
+ durationMs: 0
11
+ };
12
+ const toBytes = (contents) => typeof contents === "string" ? new TextEncoder().encode(contents) : contents;
13
+ const seedFs = (files) => new Map(Object.entries(files ?? {}).map(([k, v]) => [k, toBytes(v)]));
14
+ const exhausted = (method, scripted, attempt) => new SandboxInvalidRequest({
15
+ provider: "mock",
16
+ reason: `MockSandbox exhausted: ${scripted} ${method}(s) scripted, but call ${attempt} was made`
17
+ });
18
+ const consume = (cursor, scripted, onMiss) => Ref.getAndUpdate(cursor, (n) => n + 1).pipe(Effect.flatMap((i) => i < scripted.length ? Effect.succeed(scripted[i]) : onMiss(i + 1)));
19
+ const buildInstance = (id, script, fs, execCursor, streamCursor, spawnCursor, record) => ({
20
+ id,
21
+ exec: (request) => record(Call.Exec({
22
+ id,
23
+ request
24
+ })).pipe(Effect.andThen(consume(execCursor, script.execs ?? [], () => Effect.succeed(defaultExec)))),
25
+ execStream: (request) => Stream.unwrap(record(Call.ExecStream({
26
+ id,
27
+ request
28
+ })).pipe(Effect.andThen(consume(streamCursor, script.streams ?? [], () => Effect.succeed([ExecEvent.Complete({
29
+ exitCode: 0,
30
+ durationMs: 0
31
+ })]))), Effect.map((events) => Stream.fromIterable(events)))),
32
+ spawn: (request) => record(Call.Spawn({
33
+ id,
34
+ request
35
+ })).pipe(Effect.andThen(consume(spawnCursor, script.spawns ?? [], (n) => Effect.fail(exhausted("spawn", (script.spawns ?? []).length, n)))), Effect.tap((handle) => Effect.addFinalizer(() => Effect.orDie(handle.kill)))),
36
+ files: {
37
+ read: (path) => record(Call.FileRead({
38
+ id,
39
+ path
40
+ })).pipe(Effect.andThen(Ref.get(fs)), Effect.flatMap((map) => map.has(path) ? Effect.succeed(map.get(path)) : Effect.fail(new SandboxExecFailed({
41
+ provider: "mock",
42
+ reason: `ENOENT: ${path}`,
43
+ raw: void 0
44
+ })))),
45
+ write: (path, contents) => record(Call.FileWrite({
46
+ id,
47
+ path,
48
+ contents
49
+ })).pipe(Effect.andThen(Ref.update(fs, (m) => new Map(m).set(path, toBytes(contents))))),
50
+ remove: (path) => record(Call.FileRemove({
51
+ id,
52
+ path
53
+ })).pipe(Effect.andThen(Ref.update(fs, (m) => {
54
+ const next = new Map(m);
55
+ next.delete(path);
56
+ return next;
57
+ }))),
58
+ mkdir: (path) => record(Call.FileMkdir({
59
+ id,
60
+ path
61
+ })),
62
+ list: (path) => record(Call.FileList({
63
+ id,
64
+ path
65
+ })).pipe(Effect.andThen(Ref.get(fs)), Effect.map((map) => {
66
+ const prefix = path.endsWith("/") ? path : `${path}/`;
67
+ const out = [];
68
+ for (const k of map.keys()) if (k.startsWith(prefix)) out.push({
69
+ path: k,
70
+ kind: "file"
71
+ });
72
+ return out;
73
+ })),
74
+ exists: (path) => record(Call.FileExists({
75
+ id,
76
+ path
77
+ })).pipe(Effect.andThen(Ref.get(fs)), Effect.map((map) => map.has(path)))
78
+ }
79
+ });
80
+ const buildService = (script, record) => {
81
+ const id = SandboxId(script.id ?? "mock-sandbox");
82
+ const acquireInstance = (sandboxId, onClose) => Effect.gen(function* () {
83
+ const fs = yield* Ref.make(seedFs(script.files));
84
+ const execCursor = yield* Ref.make(0);
85
+ const streamCursor = yield* Ref.make(0);
86
+ const spawnCursor = yield* Ref.make(0);
87
+ yield* Effect.addFinalizer(() => onClose);
88
+ return buildInstance(sandboxId, script, fs, execCursor, streamCursor, spawnCursor, record);
89
+ });
90
+ return {
91
+ create: (request) => record(Call.Create({ request })).pipe(Effect.andThen(acquireInstance(id, record(Call.Destroy({ id }))))),
92
+ attach: (sandboxId) => record(Call.Attach({ id: sandboxId })).pipe(Effect.andThen(acquireInstance(sandboxId, Effect.void))),
93
+ list: Effect.succeed(script.sandboxes ?? []),
94
+ destroy: (sandboxId) => record(Call.Destroy({ id: sandboxId })),
95
+ snapshots: {
96
+ create: (_from, name) => record(name === void 0 ? Call.SnapshotCreate({ id }) : Call.SnapshotCreate({
97
+ id,
98
+ name
99
+ })).pipe(Effect.as(SnapshotId(`mock-snapshot-${name ?? Math.random().toString(36).slice(2, 8)}`))),
100
+ destroy: (sid) => record(Call.SnapshotDestroy({ id: sid })),
101
+ list: Effect.succeed(script.snapshots ?? [])
102
+ },
103
+ volumes: {
104
+ create: (name, options) => record(options?.quotaBytes === void 0 ? Call.VolumeCreate({ name }) : Call.VolumeCreate({
105
+ name,
106
+ quotaBytes: options.quotaBytes
107
+ })).pipe(Effect.as(VolumeId(`mock-volume-${name}`))),
108
+ destroy: (vid) => record(Call.VolumeDestroy({ id: vid })),
109
+ list: Effect.succeed(script.volumes ?? [])
110
+ },
111
+ ports: { expose: (instance, port) => record(Call.ExposePort({
112
+ id: instance.id,
113
+ port
114
+ })).pipe(Effect.as({ url: (script.portUrl ?? ((p) => `http://mock.local:${p}`))(port) })) }
115
+ };
116
+ };
117
+ const makeRecorderUnsafe = () => {
118
+ const ref = Ref.makeUnsafe([]);
119
+ return {
120
+ record: (call) => Ref.update(ref, Array.append(call)),
121
+ recorder: Ref.get(ref).pipe(Effect.map((calls) => ({ calls })))
122
+ };
123
+ };
124
+ const allCapabilities = Layer.mergeAll(Layer.succeed(SandboxHostnameAllowlist, void 0), Layer.succeed(SandboxSecretInjection, void 0), Layer.succeed(SandboxSnapshots, void 0), Layer.succeed(SandboxPauseResume, void 0), Layer.succeed(SandboxVolumes, void 0), Layer.succeed(SandboxKernelSession, void 0), Layer.succeed(SandboxPty, void 0), Layer.succeed(SandboxCustomImage, void 0), Layer.succeed(SandboxPortExposure, void 0));
125
+ /**
126
+ * Layer that registers a `MockSandbox` against the `Sandbox` tag, with
127
+ * every capability marker shipped — use when the code under test
128
+ * exercises any of them.
129
+ */
130
+ const layer = (script = {}) => {
131
+ const { record, recorder } = makeRecorderUnsafe();
132
+ return {
133
+ layer: Layer.merge(Layer.succeed(Sandbox, buildService(script, record)), allCapabilities),
134
+ recorder
135
+ };
136
+ };
137
+ /**
138
+ * Layer with the `Sandbox` service but no capability markers. Use to
139
+ * verify that consumers calling `Sandbox.snapshot` / `createVolume` /
140
+ * etc. fail at `Effect.provide` with a type error.
141
+ */
142
+ const layerWithoutCapabilities = (script = {}) => {
143
+ const { record, recorder } = makeRecorderUnsafe();
144
+ return {
145
+ layer: Layer.succeed(Sandbox, buildService(script, record)),
146
+ recorder
147
+ };
148
+ };
149
+ /** Bare service value + recorder. Use with `Effect.provideService`. */
150
+ const make = (script = {}) => {
151
+ const { record, recorder } = makeRecorderUnsafe();
152
+ return {
153
+ service: buildService(script, record),
154
+ recorder
155
+ };
156
+ };
157
+ //#endregion
158
+ export { Call, layer, layerWithoutCapabilities, make };
159
+
160
+ //# sourceMappingURL=MockSandbox.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MockSandbox.mjs","names":["SandboxError.SandboxInvalidRequest","SandboxError.SandboxExecFailed","Arr"],"sources":["../../src/testing/MockSandbox.ts"],"sourcesContent":["import { Array as Arr, Data, Effect, Layer, Ref, Stream } from \"effect\"\nimport {\n ExecEvent,\n Sandbox,\n SandboxCustomImage,\n SandboxHostnameAllowlist,\n SandboxKernelSession,\n SandboxPauseResume,\n SandboxPortExposure,\n SandboxPty,\n SandboxSecretInjection,\n SandboxSnapshots,\n SandboxVolumes,\n type CommonCreateRequest,\n type CommonExecRequest,\n type CommonSpawnRequest,\n type ExecResult,\n type FileEntry,\n type ProcessHandle,\n SandboxId,\n type SandboxInstance,\n type SandboxRef,\n type SandboxService,\n SnapshotId,\n VolumeId,\n} from \"../sandbox/Sandbox.js\"\nimport * as SandboxError from \"../sandbox/SandboxError.js\"\n\n// ---------------------------------------------------------------------------\n// Call log\n// ---------------------------------------------------------------------------\n\n/**\n * One entry per side-effecting method call. Tests filter via\n * `Call.$is(...)` / `Call.$match`.\n */\nexport type Call = Data.TaggedEnum<{\n Create: { readonly request: CommonCreateRequest }\n Attach: { readonly id: SandboxId }\n Destroy: { readonly id: SandboxId }\n Exec: { readonly id: SandboxId; readonly request: CommonExecRequest }\n ExecStream: { readonly id: SandboxId; readonly request: CommonExecRequest }\n Spawn: { readonly id: SandboxId; readonly request: CommonSpawnRequest }\n FileRead: { readonly id: SandboxId; readonly path: string }\n FileWrite: {\n readonly id: SandboxId\n readonly path: string\n readonly contents: Uint8Array | string\n }\n FileRemove: { readonly id: SandboxId; readonly path: string }\n FileMkdir: { readonly id: SandboxId; readonly path: string }\n FileList: { readonly id: SandboxId; readonly path: string }\n FileExists: { readonly id: SandboxId; readonly path: string }\n ExposePort: { readonly id: SandboxId; readonly port: number }\n SnapshotCreate: { readonly id: SandboxId; readonly name?: string }\n SnapshotDestroy: { readonly id: SnapshotId }\n VolumeCreate: { readonly name: string; readonly quotaBytes?: number }\n VolumeDestroy: { readonly id: VolumeId }\n}>\n\nexport const Call = Data.taggedEnum<Call>()\n\nexport type MockSandboxRecorder = {\n readonly calls: ReadonlyArray<Call>\n}\n\n// ---------------------------------------------------------------------------\n// Script\n// ---------------------------------------------------------------------------\n\n/**\n * What this mock should hand back per call. Each method has its own\n * scripted queue and a sensible default when the queue is empty.\n * The filesystem is an in-memory mutable map seeded by `files`.\n */\nexport type MockSandboxScript = {\n readonly id?: string\n readonly execs?: ReadonlyArray<ExecResult>\n readonly streams?: ReadonlyArray<ReadonlyArray<ExecEvent>>\n readonly spawns?: ReadonlyArray<ProcessHandle>\n readonly files?: Readonly<Record<string, Uint8Array | string>>\n readonly sandboxes?: ReadonlyArray<SandboxRef>\n readonly snapshots?: ReadonlyArray<{ readonly id: SnapshotId; readonly name?: string }>\n readonly volumes?: ReadonlyArray<{ readonly id: VolumeId; readonly name: string }>\n readonly portUrl?: (port: number) => string\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nconst defaultExec: ExecResult = { exitCode: 0, stdout: \"\", stderr: \"\", durationMs: 0 }\n\nconst toBytes = (contents: Uint8Array | string) =>\n typeof contents === \"string\" ? new TextEncoder().encode(contents) : contents\n\nconst seedFs = (files: MockSandboxScript[\"files\"]) =>\n new Map(Object.entries(files ?? {}).map(([k, v]) => [k, toBytes(v)]))\n\nconst exhausted = (method: string, scripted: number, attempt: number) =>\n new SandboxError.SandboxInvalidRequest({\n provider: \"mock\",\n reason: `MockSandbox exhausted: ${scripted} ${method}(s) scripted, but call ${attempt} was made`,\n })\n\nconst consume = <A>(\n cursor: Ref.Ref<number>,\n scripted: ReadonlyArray<A>,\n onMiss: (attempt: number) => Effect.Effect<A, SandboxError.SandboxError>,\n) =>\n Ref.getAndUpdate(cursor, (n) => n + 1).pipe(\n Effect.flatMap((i) => (i < scripted.length ? Effect.succeed(scripted[i]!) : onMiss(i + 1))),\n )\n\n// ---------------------------------------------------------------------------\n// Service builder\n// ---------------------------------------------------------------------------\n\nconst buildInstance = (\n id: SandboxId,\n script: MockSandboxScript,\n fs: Ref.Ref<Map<string, Uint8Array>>,\n execCursor: Ref.Ref<number>,\n streamCursor: Ref.Ref<number>,\n spawnCursor: Ref.Ref<number>,\n record: (call: Call) => Effect.Effect<void>,\n): SandboxInstance => ({\n id,\n\n exec: (request) =>\n record(Call.Exec({ id, request })).pipe(\n Effect.andThen(consume(execCursor, script.execs ?? [], () => Effect.succeed(defaultExec))),\n ),\n\n execStream: (request) =>\n Stream.unwrap(\n record(Call.ExecStream({ id, request })).pipe(\n Effect.andThen(\n consume(streamCursor, script.streams ?? [], () =>\n Effect.succeed<ReadonlyArray<ExecEvent>>([\n ExecEvent.Complete({ exitCode: 0, durationMs: 0 }),\n ]),\n ),\n ),\n Effect.map(\n (events) =>\n Stream.fromIterable(events) as Stream.Stream<ExecEvent, SandboxError.SandboxError>,\n ),\n ),\n ),\n\n spawn: (request) =>\n record(Call.Spawn({ id, request })).pipe(\n Effect.andThen(\n consume(spawnCursor, script.spawns ?? [], (n) =>\n Effect.fail(exhausted(\"spawn\", (script.spawns ?? []).length, n)),\n ),\n ),\n Effect.tap((handle) => Effect.addFinalizer(() => Effect.orDie(handle.kill))),\n ),\n\n files: {\n read: (path) =>\n record(Call.FileRead({ id, path })).pipe(\n Effect.andThen(Ref.get(fs)),\n Effect.flatMap((map) =>\n map.has(path)\n ? Effect.succeed(map.get(path)!)\n : Effect.fail(\n new SandboxError.SandboxExecFailed({\n provider: \"mock\",\n reason: `ENOENT: ${path}`,\n raw: undefined,\n }),\n ),\n ),\n ),\n\n write: (path, contents) =>\n record(Call.FileWrite({ id, path, contents })).pipe(\n Effect.andThen(Ref.update(fs, (m) => new Map(m).set(path, toBytes(contents)))),\n ),\n\n remove: (path) =>\n record(Call.FileRemove({ id, path })).pipe(\n Effect.andThen(\n Ref.update(fs, (m) => {\n const next = new Map(m)\n next.delete(path)\n return next\n }),\n ),\n ),\n\n mkdir: (path) => record(Call.FileMkdir({ id, path })),\n\n list: (path) =>\n record(Call.FileList({ id, path })).pipe(\n Effect.andThen(Ref.get(fs)),\n Effect.map((map) => {\n const prefix = path.endsWith(\"/\") ? path : `${path}/`\n const out: Array<FileEntry> = []\n for (const k of map.keys()) {\n if (k.startsWith(prefix)) out.push({ path: k, kind: \"file\" })\n }\n return out\n }),\n ),\n\n exists: (path) =>\n record(Call.FileExists({ id, path })).pipe(\n Effect.andThen(Ref.get(fs)),\n Effect.map((map) => map.has(path)),\n ),\n },\n})\n\nconst buildService = (\n script: MockSandboxScript,\n record: (call: Call) => Effect.Effect<void>,\n): SandboxService => {\n const id = SandboxId(script.id ?? \"mock-sandbox\")\n\n const acquireInstance = (sandboxId: SandboxId, onClose: Effect.Effect<void>) =>\n Effect.gen(function* () {\n const fs = yield* Ref.make(seedFs(script.files))\n const execCursor = yield* Ref.make(0)\n const streamCursor = yield* Ref.make(0)\n const spawnCursor = yield* Ref.make(0)\n yield* Effect.addFinalizer(() => onClose)\n return buildInstance(sandboxId, script, fs, execCursor, streamCursor, spawnCursor, record)\n })\n\n return {\n create: (request) =>\n record(Call.Create({ request })).pipe(\n Effect.andThen(acquireInstance(id, record(Call.Destroy({ id })))),\n ),\n\n attach: (sandboxId) =>\n record(Call.Attach({ id: sandboxId })).pipe(\n // Attach detaches on scope close (no destroy).\n Effect.andThen(acquireInstance(sandboxId, Effect.void)),\n ),\n\n list: Effect.succeed(script.sandboxes ?? []),\n\n destroy: (sandboxId) => record(Call.Destroy({ id: sandboxId })),\n\n snapshots: {\n create: (_from, name) =>\n record(\n name === undefined ? Call.SnapshotCreate({ id }) : Call.SnapshotCreate({ id, name }),\n ).pipe(\n Effect.as(SnapshotId(`mock-snapshot-${name ?? Math.random().toString(36).slice(2, 8)}`)),\n ),\n destroy: (sid) => record(Call.SnapshotDestroy({ id: sid })),\n list: Effect.succeed(script.snapshots ?? []),\n },\n\n volumes: {\n create: (name, options) =>\n record(\n options?.quotaBytes === undefined\n ? Call.VolumeCreate({ name })\n : Call.VolumeCreate({ name, quotaBytes: options.quotaBytes }),\n ).pipe(Effect.as(VolumeId(`mock-volume-${name}`))),\n destroy: (vid) => record(Call.VolumeDestroy({ id: vid })),\n list: Effect.succeed(script.volumes ?? []),\n },\n\n ports: {\n expose: (instance, port) =>\n record(Call.ExposePort({ id: instance.id, port })).pipe(\n Effect.as({ url: (script.portUrl ?? ((p) => `http://mock.local:${p}`))(port) }),\n ),\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Recorder\n// ---------------------------------------------------------------------------\n\nconst makeRecorderUnsafe = () => {\n const ref = Ref.makeUnsafe<ReadonlyArray<Call>>([])\n return {\n record: (call: Call) => Ref.update(ref, Arr.append(call)),\n recorder: Ref.get(ref).pipe(Effect.map((calls): MockSandboxRecorder => ({ calls }))),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nconst allCapabilities = Layer.mergeAll(\n Layer.succeed(SandboxHostnameAllowlist, undefined),\n Layer.succeed(SandboxSecretInjection, undefined),\n Layer.succeed(SandboxSnapshots, undefined),\n Layer.succeed(SandboxPauseResume, undefined),\n Layer.succeed(SandboxVolumes, undefined),\n Layer.succeed(SandboxKernelSession, undefined),\n Layer.succeed(SandboxPty, undefined),\n Layer.succeed(SandboxCustomImage, undefined),\n Layer.succeed(SandboxPortExposure, undefined),\n)\n\n/**\n * Layer that registers a `MockSandbox` against the `Sandbox` tag, with\n * every capability marker shipped — use when the code under test\n * exercises any of them.\n */\nexport const layer = (script: MockSandboxScript = {}) => {\n const { record, recorder } = makeRecorderUnsafe()\n return {\n layer: Layer.merge(Layer.succeed(Sandbox, buildService(script, record)), allCapabilities),\n recorder,\n }\n}\n\n/**\n * Layer with the `Sandbox` service but no capability markers. Use to\n * verify that consumers calling `Sandbox.snapshot` / `createVolume` /\n * etc. fail at `Effect.provide` with a type error.\n */\nexport const layerWithoutCapabilities = (script: MockSandboxScript = {}) => {\n const { record, recorder } = makeRecorderUnsafe()\n return {\n layer: Layer.succeed(Sandbox, buildService(script, record)),\n recorder,\n }\n}\n\n/** Bare service value + recorder. Use with `Effect.provideService`. */\nexport const make = (script: MockSandboxScript = {}) => {\n const { record, recorder } = makeRecorderUnsafe()\n return {\n service: buildService(script, record),\n recorder,\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { n as AudioChunk, t as AudioBlob } from "../Audio-BfCTGnH3.mjs";
2
- import { CommonStreamSynthesizeRequest, CommonSynthesizeRequest, SpeechSynthesizer, TtsIncrementalText } from "../speech-synthesizer/SpeechSynthesizer.mjs";
1
+ import { n as AudioChunk, t as AudioBlob } from "../Audio-DPlTsNdz.mjs";
2
+ import { CommonStreamSynthesizeRequest, CommonSynthesizeDialogueRequest, CommonSynthesizeRequest, MultiSpeakerTts, SpeechSynthesizer, TtsIncrementalText } from "../speech-synthesizer/SpeechSynthesizer.mjs";
3
3
  import { Effect, Layer } from "effect";
4
4
 
5
5
  //#region src/testing/MockSpeechSynthesizer.d.ts
@@ -7,31 +7,46 @@ type MockSynthesizerRecorder = {
7
7
  readonly synthesizeCalls: ReadonlyArray<CommonSynthesizeRequest>;
8
8
  readonly streamSynthesisCalls: ReadonlyArray<CommonSynthesizeRequest>;
9
9
  readonly streamSynthesisFromCalls: ReadonlyArray<CommonStreamSynthesizeRequest>;
10
+ readonly synthesizeDialogueCalls: ReadonlyArray<CommonSynthesizeDialogueRequest>;
11
+ readonly streamSynthesizeDialogueCalls: ReadonlyArray<CommonSynthesizeDialogueRequest>;
10
12
  };
11
13
  type MockSynthesizerScript = {
12
14
  /** One blob per `synthesize` call, consumed in order. */readonly blobs?: ReadonlyArray<AudioBlob>; /** One chunk-list per `streamSynthesis` call, consumed in order. */
13
15
  readonly streamSynthesisChunks?: ReadonlyArray<ReadonlyArray<AudioChunk>>; /** One chunk-list per `streamSynthesisFrom` call, consumed in order. */
14
- readonly streamSynthesisFromChunks?: ReadonlyArray<ReadonlyArray<AudioChunk>>;
16
+ readonly streamSynthesisFromChunks?: ReadonlyArray<ReadonlyArray<AudioChunk>>; /** One blob per `synthesizeDialogue` call, consumed in order. */
17
+ readonly dialogueBlobs?: ReadonlyArray<AudioBlob>; /** One chunk-list per `streamSynthesizeDialogue` call, consumed in order. */
18
+ readonly streamSynthesizeDialogueChunks?: ReadonlyArray<ReadonlyArray<AudioChunk>>;
15
19
  };
16
20
  /**
17
- * Layer providing the `SpeechSynthesizer` service AND the
18
- * `TtsIncrementalText` capability marker. Use for the common case
19
- * where code under test exercises `streamSynthesisFrom`.
21
+ * Layer providing `SpeechSynthesizer` plus both capability markers
22
+ * (`TtsIncrementalText` and `MultiSpeakerTts`). Use for the common case
23
+ * where code under test exercises any of the optional methods.
20
24
  */
21
25
  declare const layer: (script: MockSynthesizerScript) => {
22
- readonly layer: Layer.Layer<SpeechSynthesizer | TtsIncrementalText>;
26
+ readonly layer: Layer.Layer<SpeechSynthesizer | TtsIncrementalText | MultiSpeakerTts>;
23
27
  readonly recorder: Effect.Effect<MockSynthesizerRecorder>;
24
28
  };
25
29
  /**
26
30
  * Variant that omits the `TtsIncrementalText` marker — simulates a
27
- * provider without incremental-text-in support (e.g. OpenAI, AWS
28
- * Polly non-Generative). Calls to `streamSynthesisFrom` in code under
29
- * test should be a compile-time error.
31
+ * provider without incremental-text-in support (e.g. OpenAI). Calls to
32
+ * `streamSynthesisFrom` in code under test should be a compile-time
33
+ * error. `MultiSpeakerTts` is still provided.
30
34
  */
31
35
  declare const layerWithoutIncremental: (script: MockSynthesizerScript) => {
32
- readonly layer: Layer.Layer<SpeechSynthesizer>;
36
+ readonly layer: Layer.Layer<SpeechSynthesizer | MultiSpeakerTts>;
37
+ readonly recorder: Effect.Effect<MockSynthesizerRecorder>;
38
+ };
39
+ /**
40
+ * Variant that omits the `MultiSpeakerTts` marker — simulates a
41
+ * provider without multi-speaker dialogue support (e.g. OpenAI,
42
+ * Inworld). Calls to `synthesizeDialogue` /
43
+ * `streamSynthesizeDialogue` in code under test should be a
44
+ * compile-time error.
45
+ */
46
+ declare const layerWithoutMultiSpeaker: (script: MockSynthesizerScript) => {
47
+ readonly layer: Layer.Layer<SpeechSynthesizer | TtsIncrementalText>;
33
48
  readonly recorder: Effect.Effect<MockSynthesizerRecorder>;
34
49
  };
35
50
  //#endregion
36
- export { MockSynthesizerRecorder, MockSynthesizerScript, layer, layerWithoutIncremental };
51
+ export { MockSynthesizerRecorder, MockSynthesizerScript, layer, layerWithoutIncremental, layerWithoutMultiSpeaker };
37
52
  //# sourceMappingURL=MockSpeechSynthesizer.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MockSpeechSynthesizer.d.mts","names":[],"sources":["../../src/testing/MockSpeechSynthesizer.ts"],"mappings":";;;;;KAWY,uBAAA;EAAA,SACD,eAAA,EAAiB,aAAA,CAAc,uBAAA;EAAA,SAC/B,oBAAA,EAAsB,aAAA,CAAc,uBAAA;EAAA,SACpC,wBAAA,EAA0B,aAAA,CAAc,6BAAA;AAAA;AAAA,KAGvC,qBAAA;EALgB,kEAOjB,KAAA,GAAQ,aAAA,CAAc,SAAA,GANA;EAAA,SAQtB,qBAAA,GAAwB,aAAA,CAAc,aAAA,CAAc,UAAA,IAP1B;EAAA,SAS1B,yBAAA,GAA4B,aAAA,CAAc,aAAA,CAAc,UAAA;AAAA;;;;;;cA8EtD,KAAA,GACX,MAAA,EAAQ,qBAAA;EAAA,SAEC,KAAA,EAAO,KAAA,CAAM,KAAA,CAAM,iBAAA,GAAoB,kBAAA;EAAA,SACvC,QAAA,EAAU,MAAA,CAAO,MAAA,CAAO,uBAAA;AAAA;;;AAxFnC;;;;cAuHa,uBAAA,GACX,MAAA,EAAQ,qBAAA;EAAA,SAEC,KAAA,EAAO,KAAA,CAAM,KAAA,CAAM,iBAAA;EAAA,SACnB,QAAA,EAAU,MAAA,CAAO,MAAA,CAAO,uBAAA;AAAA"}
1
+ {"version":3,"file":"MockSpeechSynthesizer.d.mts","names":[],"sources":["../../src/testing/MockSpeechSynthesizer.ts"],"mappings":";;;;;KAaY,uBAAA;EAAA,SACD,eAAA,EAAiB,aAAA,CAAc,uBAAA;EAAA,SAC/B,oBAAA,EAAsB,aAAA,CAAc,uBAAA;EAAA,SACpC,wBAAA,EAA0B,aAAA,CAAc,6BAAA;EAAA,SACxC,uBAAA,EAAyB,aAAA,CAAc,+BAAA;EAAA,SACvC,6BAAA,EAA+B,aAAA,CAAc,+BAAA;AAAA;AAAA,KAG5C,qBAAA;EANqB,kEAQtB,KAAA,GAAQ,aAAA,CAAc,SAAA,GAPI;EAAA,SAS1B,qBAAA,GAAwB,aAAA,CAAc,aAAA,CAAc,UAAA,IAR3B;EAAA,SAUzB,yBAAA,GAA4B,aAAA,CAAc,aAAA,CAAc,UAAA,IATzB;EAAA,SAW/B,aAAA,GAAgB,aAAA,CAAc,SAAA,GAXc;EAAA,SAa5C,8BAAA,GAAiC,aAAA,CAAc,aAAA,CAAc,UAAA;AAAA;;;;;;cAwI3D,KAAA,GACX,MAAA,EAAQ,qBAAA;EAAA,SAEC,KAAA,EAAO,KAAA,CAAM,KAAA,CAAM,iBAAA,GAAoB,kBAAA,GAAqB,eAAA;EAAA,SAC5D,QAAA,EAAU,MAAA,CAAO,MAAA,CAAO,uBAAA;AAAA;;;;;;;cAkBtB,uBAAA,GACX,MAAA,EAAQ,qBAAA;EAAA,SAEC,KAAA,EAAO,KAAA,CAAM,KAAA,CAAM,iBAAA,GAAoB,eAAA;EAAA,SACvC,QAAA,EAAU,MAAA,CAAO,MAAA,CAAO,uBAAA;AAAA;;;;;;;;cAiBtB,wBAAA,GACX,MAAA,EAAQ,qBAAA;EAAA,SAEC,KAAA,EAAO,KAAA,CAAM,KAAA,CAAM,iBAAA,GAAoB,kBAAA;EAAA,SACvC,QAAA,EAAU,MAAA,CAAO,MAAA,CAAO,uBAAA;AAAA"}
@@ -1,95 +1,119 @@
1
1
  import { InvalidRequest } from "../domain/AiError.mjs";
2
- import { SpeechSynthesizer, TtsIncrementalText } from "../speech-synthesizer/SpeechSynthesizer.mjs";
2
+ import { MultiSpeakerTts, SpeechSynthesizer, TtsIncrementalText } from "../speech-synthesizer/SpeechSynthesizer.mjs";
3
3
  import { Effect, Layer, Ref, Stream } from "effect";
4
4
  //#region src/testing/MockSpeechSynthesizer.ts
5
+ const exhausted = (label, scripted, call) => new InvalidRequest({
6
+ provider: "mock",
7
+ raw: `MockSpeechSynthesizer exhausted: ${scripted} ${label} scripted, but call ${call} was made`
8
+ });
5
9
  const makeService = (script, record) => Effect.gen(function* () {
6
10
  const bCursor = yield* Ref.make(0);
7
11
  const ssCursor = yield* Ref.make(0);
8
12
  const ssfCursor = yield* Ref.make(0);
13
+ const sdCursor = yield* Ref.make(0);
14
+ const ssdCursor = yield* Ref.make(0);
9
15
  return {
10
16
  synthesize: (request) => Effect.gen(function* () {
11
17
  yield* record.synthesize(request);
12
18
  const i = yield* Ref.getAndUpdate(bCursor, (n) => n + 1);
13
19
  const scripted = script.blobs ?? [];
14
- if (i >= scripted.length) return yield* new InvalidRequest({
15
- provider: "mock",
16
- raw: `MockSpeechSynthesizer exhausted: ${scripted.length} blobs scripted, but call ${i + 1} was made`
17
- });
20
+ if (i >= scripted.length) return yield* exhausted("blobs", scripted.length, i + 1);
18
21
  return scripted[i];
19
22
  }),
20
23
  streamSynthesis: (request) => Stream.unwrap(Effect.gen(function* () {
21
24
  yield* record.streamSynthesis(request);
22
25
  const i = yield* Ref.getAndUpdate(ssCursor, (n) => n + 1);
23
26
  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
- }));
27
+ if (i >= scripted.length) return Stream.fail(exhausted("streamSynthesis lists", scripted.length, i + 1));
28
28
  return Stream.fromIterable(scripted[i]);
29
29
  })),
30
30
  streamSynthesisFrom: (textIn, request) => Stream.unwrap(Effect.gen(function* () {
31
31
  yield* record.streamSynthesisFrom(request);
32
32
  const i = yield* Ref.getAndUpdate(ssfCursor, (n) => n + 1);
33
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
- }));
34
+ if (i >= scripted.length) return Stream.fail(exhausted("streamSynthesisFrom lists", scripted.length, i + 1));
38
35
  return Stream.drain(textIn).pipe(Stream.concat(Stream.fromIterable(scripted[i])));
36
+ })),
37
+ synthesizeDialogue: (request) => Effect.gen(function* () {
38
+ yield* record.synthesizeDialogue(request);
39
+ const i = yield* Ref.getAndUpdate(sdCursor, (n) => n + 1);
40
+ const scripted = script.dialogueBlobs ?? [];
41
+ if (i >= scripted.length) return yield* exhausted("dialogueBlobs", scripted.length, i + 1);
42
+ return scripted[i];
43
+ }),
44
+ streamSynthesizeDialogue: (request) => Stream.unwrap(Effect.gen(function* () {
45
+ yield* record.streamSynthesizeDialogue(request);
46
+ const i = yield* Ref.getAndUpdate(ssdCursor, (n) => n + 1);
47
+ const scripted = script.streamSynthesizeDialogueChunks ?? [];
48
+ if (i >= scripted.length) return Stream.fail(exhausted("streamSynthesizeDialogue lists", scripted.length, i + 1));
49
+ return Stream.fromIterable(scripted[i]);
39
50
  }))
40
51
  };
41
52
  });
53
+ const newBuffers = () => ({
54
+ bCalls: Ref.makeUnsafe([]),
55
+ ssCalls: Ref.makeUnsafe([]),
56
+ ssfCalls: Ref.makeUnsafe([]),
57
+ sdCalls: Ref.makeUnsafe([]),
58
+ ssdCalls: Ref.makeUnsafe([])
59
+ });
60
+ const recordFor = (b) => ({
61
+ synthesize: (req) => Ref.update(b.bCalls, (xs) => [...xs, req]),
62
+ streamSynthesis: (req) => Ref.update(b.ssCalls, (xs) => [...xs, req]),
63
+ streamSynthesisFrom: (req) => Ref.update(b.ssfCalls, (xs) => [...xs, req]),
64
+ synthesizeDialogue: (req) => Ref.update(b.sdCalls, (xs) => [...xs, req]),
65
+ streamSynthesizeDialogue: (req) => Ref.update(b.ssdCalls, (xs) => [...xs, req])
66
+ });
67
+ const recorderEffect = (b) => Effect.gen(function* () {
68
+ return {
69
+ synthesizeCalls: yield* Ref.get(b.bCalls),
70
+ streamSynthesisCalls: yield* Ref.get(b.ssCalls),
71
+ streamSynthesisFromCalls: yield* Ref.get(b.ssfCalls),
72
+ synthesizeDialogueCalls: yield* Ref.get(b.sdCalls),
73
+ streamSynthesizeDialogueCalls: yield* Ref.get(b.ssdCalls)
74
+ };
75
+ });
42
76
  /**
43
- * Layer providing the `SpeechSynthesizer` service AND the
44
- * `TtsIncrementalText` capability marker. Use for the common case
45
- * where code under test exercises `streamSynthesisFrom`.
77
+ * Layer providing `SpeechSynthesizer` plus both capability markers
78
+ * (`TtsIncrementalText` and `MultiSpeakerTts`). Use for the common case
79
+ * where code under test exercises any of the optional methods.
46
80
  */
47
81
  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
- }));
82
+ const buffers = newBuffers();
83
+ const synthesizerLayer = Layer.effect(SpeechSynthesizer, makeService(script, recordFor(buffers)));
56
84
  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
- })
85
+ layer: Layer.mergeAll(synthesizerLayer, Layer.succeed(TtsIncrementalText, void 0), Layer.succeed(MultiSpeakerTts, void 0)),
86
+ recorder: recorderEffect(buffers)
65
87
  };
66
88
  };
67
89
  /**
68
90
  * 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.
91
+ * provider without incremental-text-in support (e.g. OpenAI). Calls to
92
+ * `streamSynthesisFrom` in code under test should be a compile-time
93
+ * error. `MultiSpeakerTts` is still provided.
72
94
  */
73
95
  const layerWithoutIncremental = (script) => {
74
- const bCalls = Ref.makeUnsafe([]);
75
- const ssCalls = Ref.makeUnsafe([]);
76
- const ssfCalls = Ref.makeUnsafe([]);
96
+ const buffers = newBuffers();
77
97
  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
- })
98
+ layer: Layer.merge(Layer.effect(SpeechSynthesizer, makeService(script, recordFor(buffers))), Layer.succeed(MultiSpeakerTts, void 0)),
99
+ recorder: recorderEffect(buffers)
100
+ };
101
+ };
102
+ /**
103
+ * Variant that omits the `MultiSpeakerTts` marker — simulates a
104
+ * provider without multi-speaker dialogue support (e.g. OpenAI,
105
+ * Inworld). Calls to `synthesizeDialogue` /
106
+ * `streamSynthesizeDialogue` in code under test should be a
107
+ * compile-time error.
108
+ */
109
+ const layerWithoutMultiSpeaker = (script) => {
110
+ const buffers = newBuffers();
111
+ return {
112
+ layer: Layer.merge(Layer.effect(SpeechSynthesizer, makeService(script, recordFor(buffers))), Layer.succeed(TtsIncrementalText, void 0)),
113
+ recorder: recorderEffect(buffers)
90
114
  };
91
115
  };
92
116
  //#endregion
93
- export { layer, layerWithoutIncremental };
117
+ export { layer, layerWithoutIncremental, layerWithoutMultiSpeaker };
94
118
 
95
119
  //# sourceMappingURL=MockSpeechSynthesizer.mjs.map
@@ -1 +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* new AiError.InvalidRequest({\n provider: \"mock\",\n raw: `MockSpeechSynthesizer exhausted: ${scripted.length} blobs scripted, but call ${i + 1} was made`,\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":"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"}
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 type CommonStreamSynthesizeRequest,\n type CommonSynthesizeDialogueRequest,\n type CommonSynthesizeRequest,\n MultiSpeakerTts,\n SpeechSynthesizer,\n type SpeechSynthesizerService,\n TtsIncrementalText,\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 readonly synthesizeDialogueCalls: ReadonlyArray<CommonSynthesizeDialogueRequest>\n readonly streamSynthesizeDialogueCalls: ReadonlyArray<CommonSynthesizeDialogueRequest>\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 /** One blob per `synthesizeDialogue` call, consumed in order. */\n readonly dialogueBlobs?: ReadonlyArray<AudioBlob>\n /** One chunk-list per `streamSynthesizeDialogue` call, consumed in order. */\n readonly streamSynthesizeDialogueChunks?: ReadonlyArray<ReadonlyArray<AudioChunk>>\n}\n\ntype 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 readonly synthesizeDialogue: (req: CommonSynthesizeDialogueRequest) => Effect.Effect<void>\n readonly streamSynthesizeDialogue: (req: CommonSynthesizeDialogueRequest) => Effect.Effect<void>\n}\n\nconst exhausted = (label: string, scripted: number, call: number): AiError.AiError =>\n new AiError.InvalidRequest({\n provider: \"mock\",\n raw: `MockSpeechSynthesizer exhausted: ${scripted} ${label} scripted, but call ${call} was made`,\n })\n\nconst makeService = (script: MockSynthesizerScript, record: Record) =>\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 sdCursor = yield* Ref.make(0)\n const ssdCursor = 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) return yield* exhausted(\"blobs\", scripted.length, i + 1)\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(exhausted(\"streamSynthesis lists\", scripted.length, i + 1))\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 fail: Stream.Stream<AudioChunk, AiError.AiError | E, R> = Stream.fail(\n exhausted(\"streamSynthesisFrom lists\", scripted.length, i + 1),\n )\n return fail\n }\n return Stream.drain(textIn).pipe(Stream.concat(Stream.fromIterable(scripted[i]!)))\n }),\n ),\n synthesizeDialogue: (request) =>\n Effect.gen(function* () {\n yield* record.synthesizeDialogue(request)\n const i = yield* Ref.getAndUpdate(sdCursor, (n) => n + 1)\n const scripted = script.dialogueBlobs ?? []\n if (i >= scripted.length) {\n return yield* exhausted(\"dialogueBlobs\", scripted.length, i + 1)\n }\n return scripted[i]!\n }),\n streamSynthesizeDialogue: (request) =>\n Stream.unwrap(\n Effect.gen(function* () {\n yield* record.streamSynthesizeDialogue(request)\n const i = yield* Ref.getAndUpdate(ssdCursor, (n) => n + 1)\n const scripted = script.streamSynthesizeDialogueChunks ?? []\n if (i >= scripted.length) {\n return Stream.fail(\n exhausted(\"streamSynthesizeDialogue lists\", scripted.length, i + 1),\n )\n }\n return Stream.fromIterable(scripted[i]!)\n }),\n ),\n }\n return service\n })\n\ntype CallBuffers = {\n readonly bCalls: Ref.Ref<ReadonlyArray<CommonSynthesizeRequest>>\n readonly ssCalls: Ref.Ref<ReadonlyArray<CommonSynthesizeRequest>>\n readonly ssfCalls: Ref.Ref<ReadonlyArray<CommonStreamSynthesizeRequest>>\n readonly sdCalls: Ref.Ref<ReadonlyArray<CommonSynthesizeDialogueRequest>>\n readonly ssdCalls: Ref.Ref<ReadonlyArray<CommonSynthesizeDialogueRequest>>\n}\n\nconst newBuffers = (): CallBuffers => ({\n bCalls: Ref.makeUnsafe<ReadonlyArray<CommonSynthesizeRequest>>([]),\n ssCalls: Ref.makeUnsafe<ReadonlyArray<CommonSynthesizeRequest>>([]),\n ssfCalls: Ref.makeUnsafe<ReadonlyArray<CommonStreamSynthesizeRequest>>([]),\n sdCalls: Ref.makeUnsafe<ReadonlyArray<CommonSynthesizeDialogueRequest>>([]),\n ssdCalls: Ref.makeUnsafe<ReadonlyArray<CommonSynthesizeDialogueRequest>>([]),\n})\n\nconst recordFor = (b: CallBuffers): Record => ({\n synthesize: (req) => Ref.update(b.bCalls, (xs) => [...xs, req]),\n streamSynthesis: (req) => Ref.update(b.ssCalls, (xs) => [...xs, req]),\n streamSynthesisFrom: (req) => Ref.update(b.ssfCalls, (xs) => [...xs, req]),\n synthesizeDialogue: (req) => Ref.update(b.sdCalls, (xs) => [...xs, req]),\n streamSynthesizeDialogue: (req) => Ref.update(b.ssdCalls, (xs) => [...xs, req]),\n})\n\nconst recorderEffect = (b: CallBuffers): Effect.Effect<MockSynthesizerRecorder> =>\n Effect.gen(function* () {\n const synthesizeCalls = yield* Ref.get(b.bCalls)\n const streamSynthesisCalls = yield* Ref.get(b.ssCalls)\n const streamSynthesisFromCalls = yield* Ref.get(b.ssfCalls)\n const synthesizeDialogueCalls = yield* Ref.get(b.sdCalls)\n const streamSynthesizeDialogueCalls = yield* Ref.get(b.ssdCalls)\n return {\n synthesizeCalls,\n streamSynthesisCalls,\n streamSynthesisFromCalls,\n synthesizeDialogueCalls,\n streamSynthesizeDialogueCalls,\n }\n })\n\n/**\n * Layer providing `SpeechSynthesizer` plus both capability markers\n * (`TtsIncrementalText` and `MultiSpeakerTts`). Use for the common case\n * where code under test exercises any of the optional methods.\n */\nexport const layer = (\n script: MockSynthesizerScript,\n): {\n readonly layer: Layer.Layer<SpeechSynthesizer | TtsIncrementalText | MultiSpeakerTts>\n readonly recorder: Effect.Effect<MockSynthesizerRecorder>\n} => {\n const buffers = newBuffers()\n const synthesizerLayer = Layer.effect(SpeechSynthesizer, makeService(script, recordFor(buffers)))\n const live = Layer.mergeAll(\n synthesizerLayer,\n Layer.succeed(TtsIncrementalText, undefined),\n Layer.succeed(MultiSpeakerTts, undefined),\n )\n return { layer: live, recorder: recorderEffect(buffers) }\n}\n\n/**\n * Variant that omits the `TtsIncrementalText` marker — simulates a\n * provider without incremental-text-in support (e.g. OpenAI). Calls to\n * `streamSynthesisFrom` in code under test should be a compile-time\n * error. `MultiSpeakerTts` is still provided.\n */\nexport const layerWithoutIncremental = (\n script: MockSynthesizerScript,\n): {\n readonly layer: Layer.Layer<SpeechSynthesizer | MultiSpeakerTts>\n readonly recorder: Effect.Effect<MockSynthesizerRecorder>\n} => {\n const buffers = newBuffers()\n const live = Layer.merge(\n Layer.effect(SpeechSynthesizer, makeService(script, recordFor(buffers))),\n Layer.succeed(MultiSpeakerTts, undefined),\n )\n return { layer: live, recorder: recorderEffect(buffers) }\n}\n\n/**\n * Variant that omits the `MultiSpeakerTts` marker — simulates a\n * provider without multi-speaker dialogue support (e.g. OpenAI,\n * Inworld). Calls to `synthesizeDialogue` /\n * `streamSynthesizeDialogue` in code under test should be a\n * compile-time error.\n */\nexport const layerWithoutMultiSpeaker = (\n script: MockSynthesizerScript,\n): {\n readonly layer: Layer.Layer<SpeechSynthesizer | TtsIncrementalText>\n readonly recorder: Effect.Effect<MockSynthesizerRecorder>\n} => {\n const buffers = newBuffers()\n const live = Layer.merge(\n Layer.effect(SpeechSynthesizer, makeService(script, recordFor(buffers))),\n Layer.succeed(TtsIncrementalText, undefined),\n )\n return { layer: live, recorder: recorderEffect(buffers) }\n}\n"],"mappings":"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"}
@@ -1,29 +1,29 @@
1
- import { o as FunctionCall } from "../Items-BH8xUkoR.mjs";
2
- import { ToolResult } from "./Outcome.mjs";
1
+ import { v as ToolCall } from "../Items-D8UaXQx_.mjs";
2
+ import { ToolResult } from "./ToolResult.mjs";
3
3
  import { ToolEvent } from "./ToolEvent.mjs";
4
4
  import { Data, Effect, Queue, Scope, Stream } from "effect";
5
5
  import * as _$effect_Unify0 from "effect/Unify";
6
6
 
7
- //#region src/tool/Resolvers.d.ts
8
- declare namespace Resolvers_d_exports {
9
- export { ApprovalMapEntry, ToolCallDecision, ToolCallPlan, Verdict, approvalRequested, approve, fromApprovalMap, fromVerdictQueue, reject, splitToolCallDecisions };
7
+ //#region src/tool/Approval.d.ts
8
+ declare namespace Approval_d_exports {
9
+ export { ApprovalDecision, ApprovalMapEntry, ToolCallPlan, Verdict, approvalRequested, approve, fromMap, fromQueue, reject, splitApprovalDecisions };
10
10
  }
11
11
  type ToolCallPlan = {
12
- readonly approved: ReadonlyArray<FunctionCall>;
12
+ readonly approved: ReadonlyArray<ToolCall>;
13
13
  readonly rejected: ReadonlyArray<ToolResult>;
14
14
  };
15
- type ToolCallDecision = Data.TaggedEnum<{
15
+ type ApprovalDecision = Data.TaggedEnum<{
16
16
  Approved: {
17
- readonly call: FunctionCall;
17
+ readonly call: ToolCall;
18
18
  };
19
19
  Rejected: {
20
20
  readonly result: ToolResult;
21
21
  };
22
22
  }>;
23
- declare const ToolCallDecision: {
23
+ declare const ApprovalDecision: {
24
24
  readonly Approved: Data.TaggedEnum.ConstructorFrom<{
25
25
  readonly _tag: "Approved";
26
- readonly call: FunctionCall;
26
+ readonly call: ToolCall;
27
27
  }, "_tag">;
28
28
  readonly Rejected: Data.TaggedEnum.ConstructorFrom<{
29
29
  readonly _tag: "Rejected";
@@ -31,7 +31,7 @@ declare const ToolCallDecision: {
31
31
  }, "_tag">;
32
32
  readonly $is: <Tag extends "Approved" | "Rejected">(tag: Tag) => (u: unknown) => u is Extract<{
33
33
  readonly _tag: "Approved";
34
- readonly call: FunctionCall;
34
+ readonly call: ToolCall;
35
35
  }, {
36
36
  readonly _tag: Tag;
37
37
  }> | Extract<{
@@ -44,7 +44,7 @@ declare const ToolCallDecision: {
44
44
  <Cases extends {
45
45
  readonly Approved: (args: {
46
46
  readonly _tag: "Approved";
47
- readonly call: FunctionCall;
47
+ readonly call: ToolCall;
48
48
  }) => any;
49
49
  readonly Rejected: (args: {
50
50
  readonly _tag: "Rejected";
@@ -52,7 +52,7 @@ declare const ToolCallDecision: {
52
52
  }) => any;
53
53
  }>(cases: Cases): (value: {
54
54
  readonly _tag: "Approved";
55
- readonly call: FunctionCall;
55
+ readonly call: ToolCall;
56
56
  } | {
57
57
  readonly _tag: "Rejected";
58
58
  readonly result: ToolResult;
@@ -60,7 +60,7 @@ declare const ToolCallDecision: {
60
60
  <Cases extends {
61
61
  readonly Approved: (args: {
62
62
  readonly _tag: "Approved";
63
- readonly call: FunctionCall;
63
+ readonly call: ToolCall;
64
64
  }) => any;
65
65
  readonly Rejected: (args: {
66
66
  readonly _tag: "Rejected";
@@ -68,17 +68,17 @@ declare const ToolCallDecision: {
68
68
  }) => any;
69
69
  }>(value: {
70
70
  readonly _tag: "Approved";
71
- readonly call: FunctionCall;
71
+ readonly call: ToolCall;
72
72
  } | {
73
73
  readonly _tag: "Rejected";
74
74
  readonly result: ToolResult;
75
75
  }, cases: Cases): _$effect_Unify0.Unify<ReturnType<Cases["Approved" | "Rejected"]>>;
76
76
  };
77
77
  };
78
- declare const approve: (call: FunctionCall) => ToolCallDecision;
79
- declare const reject: (result: ToolResult) => ToolCallDecision;
80
- declare const splitToolCallDecisions: (decisions: ReadonlyArray<ToolCallDecision>) => ToolCallPlan;
81
- declare const approvalRequested: (call: FunctionCall) => ToolEvent;
78
+ declare const approve: (call: ToolCall) => ApprovalDecision;
79
+ declare const reject: (result: ToolResult) => ApprovalDecision;
80
+ declare const splitApprovalDecisions: (decisions: ReadonlyArray<ApprovalDecision>) => ToolCallPlan;
81
+ declare const approvalRequested: (call: ToolCall) => ToolEvent;
82
82
  type Verdict = {
83
83
  readonly call_id: string;
84
84
  readonly decision: "approve" | "deny";
@@ -87,12 +87,12 @@ type Verdict = {
87
87
  /**
88
88
  * Queue-backed approval planner. Safe calls are returned immediately in
89
89
  * `approved`; gated calls emit `ApprovalRequested` events and later produce
90
- * one `ToolCallDecision` when their matching verdict arrives.
90
+ * one `ApprovalDecision` when their matching verdict arrives.
91
91
  */
92
- declare const fromVerdictQueue: (predicate: (call: FunctionCall) => boolean, verdicts: Queue.Dequeue<Verdict>) => (calls: ReadonlyArray<FunctionCall>) => Effect.Effect<{
93
- readonly approved: ReadonlyArray<FunctionCall>;
94
- readonly decisions: Stream.Stream<ToolCallDecision>;
95
- readonly announce: Stream.Stream<ToolEvent>;
92
+ declare const fromQueue: (predicate: (call: ToolCall) => boolean, verdicts: Queue.Dequeue<Verdict>) => (calls: ReadonlyArray<ToolCall>) => Effect.Effect<{
93
+ readonly approved: ReadonlyArray<ToolCall>;
94
+ readonly decisions: Stream.Stream<ApprovalDecision>;
95
+ readonly approvalRequests: Stream.Stream<ToolEvent>;
96
96
  }, never, Scope.Scope>;
97
97
  type ApprovalMapEntry = {
98
98
  readonly decision: "approve";
@@ -100,7 +100,7 @@ type ApprovalMapEntry = {
100
100
  readonly decision: "deny";
101
101
  readonly reason?: string;
102
102
  };
103
- declare const fromApprovalMap: (predicate: (call: FunctionCall) => boolean, approvals: ReadonlyMap<string, ApprovalMapEntry>) => (calls: ReadonlyArray<FunctionCall>) => ToolCallPlan;
103
+ declare const fromMap: (predicate: (call: ToolCall) => boolean, approvals: ReadonlyMap<string, ApprovalMapEntry>) => (calls: ReadonlyArray<ToolCall>) => ToolCallPlan;
104
104
  //#endregion
105
- export { ApprovalMapEntry, ToolCallDecision, ToolCallPlan, Verdict, approvalRequested, approve, fromApprovalMap, fromVerdictQueue, reject, splitToolCallDecisions, Resolvers_d_exports as t };
106
- //# sourceMappingURL=Resolvers.d.mts.map
105
+ export { ApprovalDecision, ApprovalMapEntry, ToolCallPlan, Verdict, approvalRequested, approve, fromMap, fromQueue, reject, splitApprovalDecisions, Approval_d_exports as t };
106
+ //# sourceMappingURL=Approval.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Approval.d.mts","names":[],"sources":["../../src/tool/Approval.ts"],"mappings":";;;;;;;;;;KAYY,YAAA;EAAA,SACD,QAAA,EAAU,aAAA,CAAc,QAAA;EAAA,SACxB,QAAA,EAAU,aAAA,CAAc,UAAA;AAAA;AAAA,KAGvB,gBAAA,GAAmB,IAAA,CAAK,UAAA;EAClC,QAAA;IAAA,SAAqB,IAAA,EAAM,QAAA;EAAA;EAC3B,QAAA;IAAA,SAAqB,MAAA,EAAQ,UAAA;EAAA;AAAA;AAAA,cAGlB,gBAAA;EAAA;;mBAJgB,QAAA;EAAA;EAAA;;qBACE,UAAA;EAAA;EAAA;;mBADF,QAAA;EAAA;IAAA;;;qBACE,UAAA;EAAA;IAAA;;;;;;uBADF,QAAA;MAAA;MAAA;;yBACE,UAAA;MAAA;IAAA;;qBADF,QAAA;IAAA;MAAA;uBACE,UAAA;IAAA;;;;uBADF,QAAA;MAAA;MAAA;;yBACE,UAAA;MAAA;IAAA;;qBADF,QAAA;IAAA;MAAA;uBACE,UAAA;IAAA;;;cAKlB,OAAA,GAAW,IAAA,EAAM,QAAA,KAAW,gBAAA;AAAA,cAE5B,MAAA,GAAU,MAAA,EAAQ,UAAA,KAAa,gBAAA;AAAA,cAG/B,sBAAA,GAA0B,SAAA,EAAW,aAAA,CAAc,gBAAA,MAAoB,YAAA;AAAA,cASvE,iBAAA,GAAqB,IAAA,EAAM,QAAA,KAAW,SAAA;AAAA,KAWvC,OAAA;EAAA,SACD,OAAA;EAAA,SACA,QAAA;EAAA,SACA,MAAA;AAAA;;;;;;cAQE,SAAA,GACV,SAAA,GAAY,IAAA,EAAM,QAAA,cAAsB,QAAA,EAAU,KAAA,CAAM,OAAA,CAAQ,OAAA,OAE/D,KAAA,EAAO,aAAA,CAAc,QAAA,MACpB,MAAA,CAAO,MAAA;EAAA,SAEG,QAAA,EAAU,aAAA,CAAc,QAAA;EAAA,SACxB,SAAA,EAAW,MAAA,CAAO,MAAA,CAAO,gBAAA;EAAA,SACzB,gBAAA,EAAkB,MAAA,CAAO,MAAA,CAAO,SAAA;AAAA,UAG3C,KAAA,CAAM,KAAA;AAAA,KAkDE,gBAAA;EAAA,SACG,QAAA;AAAA;EAAA,SACA,QAAA;EAAA,SAA2B,MAAA;AAAA;AAAA,cAE7B,OAAA,GACV,SAAA,GAAY,IAAA,EAAM,QAAA,cAAsB,SAAA,EAAW,WAAA,SAAoB,gBAAA,OACvE,KAAA,EAAO,aAAA,CAAc,QAAA,MAAY,YAAA"}