@effect-uai/core 0.18.0 → 0.19.0-dev-20261110065930

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 (162) hide show
  1. package/README.md +4 -4
  2. package/dist/Content-D_Qfn8Ja.d.mts +48 -0
  3. package/dist/Content-D_Qfn8Ja.d.mts.map +1 -0
  4. package/dist/File-B923KvZ9.d.mts +46 -0
  5. package/dist/File-B923KvZ9.d.mts.map +1 -0
  6. package/dist/{Image-Cv6iBLTy.d.mts → Image-Bzc1H_UK.d.mts} +19 -8
  7. package/dist/Image-Bzc1H_UK.d.mts.map +1 -0
  8. package/dist/{Items-C7MyrYPX.d.mts → Items-Bvx8s9QH.d.mts} +109 -16
  9. package/dist/Items-Bvx8s9QH.d.mts.map +1 -0
  10. package/dist/{Loop-ChpaO-ya.d.mts → Loop-CeA0AelN.d.mts} +7 -6
  11. package/dist/Loop-CeA0AelN.d.mts.map +1 -0
  12. package/dist/Tool-Bkryw6-h.d.mts +206 -0
  13. package/dist/Tool-Bkryw6-h.d.mts.map +1 -0
  14. package/dist/ToolEvent-9inLx5cI.d.mts +22 -0
  15. package/dist/ToolEvent-9inLx5cI.d.mts.map +1 -0
  16. package/dist/ToolOutput-BNTIQgGB.d.mts +151 -0
  17. package/dist/ToolOutput-BNTIQgGB.d.mts.map +1 -0
  18. package/dist/Toolkit-D2VGeD5R.d.mts +212 -0
  19. package/dist/Toolkit-D2VGeD5R.d.mts.map +1 -0
  20. package/dist/browser/BrowserTool.d.mts +84 -22
  21. package/dist/browser/BrowserTool.d.mts.map +1 -1
  22. package/dist/browser/BrowserTool.mjs +5 -0
  23. package/dist/browser/BrowserTool.mjs.map +1 -1
  24. package/dist/capabilities/Capabilities.d.mts +1 -1
  25. package/dist/decision-model/Decision.test.mjs +1 -1
  26. package/dist/{dist-C8RmtoR8.mjs → dist-B5K-y4Be.mjs} +51 -32
  27. package/dist/dist-B5K-y4Be.mjs.map +1 -0
  28. package/dist/domain/File.d.mts +2 -0
  29. package/dist/domain/File.mjs +51 -0
  30. package/dist/domain/File.mjs.map +1 -0
  31. package/dist/domain/Image.d.mts +2 -2
  32. package/dist/domain/Image.mjs +12 -2
  33. package/dist/domain/Image.mjs.map +1 -1
  34. package/dist/domain/Items.d.mts +2 -2
  35. package/dist/domain/Items.mjs +65 -4
  36. package/dist/domain/Items.mjs.map +1 -1
  37. package/dist/domain/Realtime.d.mts +72 -490
  38. package/dist/domain/Realtime.d.mts.map +1 -1
  39. package/dist/domain/Research.d.mts +1 -1
  40. package/dist/domain/Transcript.test.mjs +1 -1
  41. package/dist/domain/Turn.d.mts +57 -262
  42. package/dist/domain/Turn.d.mts.map +1 -1
  43. package/dist/domain/Turn.mjs +1 -1
  44. package/dist/embedding-model/Embedding.d.mts +1 -1
  45. package/dist/image-generator/ImageGenerator.d.mts +10 -66
  46. package/dist/image-generator/ImageGenerator.d.mts.map +1 -1
  47. package/dist/index.d.mts +10 -9
  48. package/dist/index.mjs +7 -6
  49. package/dist/language-model/LanguageModel.d.mts +2 -2
  50. package/dist/loop/Loop.d.mts +1 -1
  51. package/dist/loop/Loop.mjs.map +1 -1
  52. package/dist/messenger/Messenger.d.mts +43 -289
  53. package/dist/messenger/Messenger.d.mts.map +1 -1
  54. package/dist/messenger/MessengerAdapter.test.mjs +1 -1
  55. package/dist/observability/Metrics.d.mts +1 -1
  56. package/dist/observability/Metrics.test.mjs +1 -1
  57. package/dist/observability/Telemetry.test.mjs +1 -1
  58. package/dist/realtime/RealtimeSession.d.mts +1 -1
  59. package/dist/realtime/RealtimeSession.test.mjs +1 -1
  60. package/dist/sandbox/Sandbox.d.mts +32 -237
  61. package/dist/sandbox/Sandbox.d.mts.map +1 -1
  62. package/dist/streaming/Multipart.mjs +2 -1
  63. package/dist/streaming/Multipart.mjs.map +1 -1
  64. package/dist/streaming/Multipart.test.mjs +28 -0
  65. package/dist/streaming/Multipart.test.mjs.map +1 -0
  66. package/dist/streaming/Settle.test.mjs +1 -1
  67. package/dist/streaming/WebSocketSession.test.mjs +1 -1
  68. package/dist/testing/MockMessenger.d.mts +19 -134
  69. package/dist/testing/MockMessenger.d.mts.map +1 -1
  70. package/dist/testing/MockProvider.d.mts +1 -1
  71. package/dist/testing/MockSandbox.d.mts +65 -446
  72. package/dist/testing/MockSandbox.d.mts.map +1 -1
  73. package/dist/tool/Content.d.mts +2 -0
  74. package/dist/tool/Content.mjs +46 -0
  75. package/dist/tool/Content.mjs.map +1 -0
  76. package/dist/tool/Content.test.d.mts +1 -0
  77. package/dist/tool/Content.test.mjs +48 -0
  78. package/dist/tool/Content.test.mjs.map +1 -0
  79. package/dist/tool/HistoryCheck.d.mts +6 -15
  80. package/dist/tool/HistoryCheck.d.mts.map +1 -1
  81. package/dist/tool/HistoryCheck.mjs +10 -24
  82. package/dist/tool/HistoryCheck.mjs.map +1 -1
  83. package/dist/tool/Tool.d.mts +2 -2
  84. package/dist/tool/Tool.mjs +55 -130
  85. package/dist/tool/Tool.mjs.map +1 -1
  86. package/dist/tool/Tool.test.mjs +220 -176
  87. package/dist/tool/Tool.test.mjs.map +1 -1
  88. package/dist/tool/ToolDecision.d.mts +164 -0
  89. package/dist/tool/ToolDecision.d.mts.map +1 -0
  90. package/dist/tool/ToolDecision.mjs +146 -0
  91. package/dist/tool/ToolDecision.mjs.map +1 -0
  92. package/dist/tool/ToolDecision.test.d.mts +1 -0
  93. package/dist/tool/ToolDecision.test.mjs +330 -0
  94. package/dist/tool/ToolDecision.test.mjs.map +1 -0
  95. package/dist/tool/ToolEvent.d.mts +2 -2
  96. package/dist/tool/ToolEvent.mjs +2 -34
  97. package/dist/tool/ToolEvent.mjs.map +1 -1
  98. package/dist/tool/ToolOutput.d.mts +2 -0
  99. package/dist/tool/ToolOutput.mjs +128 -0
  100. package/dist/tool/ToolOutput.mjs.map +1 -0
  101. package/dist/tool/ToolOutput.test.d.mts +1 -0
  102. package/dist/tool/ToolOutput.test.mjs +153 -0
  103. package/dist/tool/ToolOutput.test.mjs.map +1 -0
  104. package/dist/tool/Toolkit.d.mts +2 -2
  105. package/dist/tool/Toolkit.mjs +230 -165
  106. package/dist/tool/Toolkit.mjs.map +1 -1
  107. package/dist/tool/Toolkit.test.mjs +431 -389
  108. package/dist/tool/Toolkit.test.mjs.map +1 -1
  109. package/dist/web-read/WebReadTool.d.mts +2 -2
  110. package/dist/web-read/WebReadTool.mjs +1 -0
  111. package/dist/web-read/WebReadTool.mjs.map +1 -1
  112. package/dist/web-search/WebSearchTool.d.mts +2 -2
  113. package/dist/web-search/WebSearchTool.mjs +1 -0
  114. package/dist/web-search/WebSearchTool.mjs.map +1 -1
  115. package/package.json +17 -9
  116. package/src/browser/BrowserTool.ts +5 -0
  117. package/src/domain/File.ts +79 -0
  118. package/src/domain/Image.ts +14 -4
  119. package/src/domain/Items.ts +39 -3
  120. package/src/index.ts +3 -2
  121. package/src/loop/Loop.ts +24 -13
  122. package/src/streaming/Multipart.test.ts +26 -0
  123. package/src/streaming/Multipart.ts +5 -4
  124. package/src/tool/Content.test.ts +40 -0
  125. package/src/tool/Content.ts +38 -0
  126. package/src/tool/HistoryCheck.ts +21 -26
  127. package/src/tool/Tool.test.ts +240 -241
  128. package/src/tool/Tool.ts +203 -308
  129. package/src/tool/ToolDecision.test.ts +301 -0
  130. package/src/tool/ToolDecision.ts +360 -0
  131. package/src/tool/ToolEvent.ts +21 -41
  132. package/src/tool/ToolOutput.test.ts +132 -0
  133. package/src/tool/ToolOutput.ts +198 -0
  134. package/src/tool/Toolkit.test.ts +594 -454
  135. package/src/tool/Toolkit.ts +631 -356
  136. package/src/web-read/WebReadTool.ts +2 -1
  137. package/src/web-search/WebSearchTool.ts +2 -1
  138. package/dist/Image-Cv6iBLTy.d.mts.map +0 -1
  139. package/dist/Items-C7MyrYPX.d.mts.map +0 -1
  140. package/dist/Loop-ChpaO-ya.d.mts.map +0 -1
  141. package/dist/Tool-BF78QWtn.d.mts +0 -314
  142. package/dist/Tool-BF78QWtn.d.mts.map +0 -1
  143. package/dist/ToolEvent-Di4a723B.d.mts +0 -144
  144. package/dist/ToolEvent-Di4a723B.d.mts.map +0 -1
  145. package/dist/ToolResult-BsYQRjmW.d.mts +0 -152
  146. package/dist/ToolResult-BsYQRjmW.d.mts.map +0 -1
  147. package/dist/Toolkit-tlL0F2YR.d.mts +0 -193
  148. package/dist/Toolkit-tlL0F2YR.d.mts.map +0 -1
  149. package/dist/dist-C8RmtoR8.mjs.map +0 -1
  150. package/dist/tool/Approval.d.mts +0 -113
  151. package/dist/tool/Approval.d.mts.map +0 -1
  152. package/dist/tool/Approval.mjs +0 -80
  153. package/dist/tool/Approval.mjs.map +0 -1
  154. package/dist/tool/Approval.test.mjs +0 -371
  155. package/dist/tool/Approval.test.mjs.map +0 -1
  156. package/dist/tool/ToolResult.d.mts +0 -2
  157. package/dist/tool/ToolResult.mjs +0 -85
  158. package/dist/tool/ToolResult.mjs.map +0 -1
  159. package/src/tool/Approval.test.ts +0 -400
  160. package/src/tool/Approval.ts +0 -181
  161. package/src/tool/ToolResult.ts +0 -114
  162. /package/dist/{tool/Approval.test.d.mts → streaming/Multipart.test.d.mts} +0 -0
@@ -1,25 +1,26 @@
1
1
  import { BrowserError } from "./BrowserError.mjs";
2
2
  import { BrowserSession } from "./Browser.mjs";
3
- import { l as Tool } from "../Tool-BF78QWtn.mjs";
3
+ import { _ as ToolInputSchema, d as Tool, u as Run } from "../Tool-Bkryw6-h.mjs";
4
+ import { Schema } from "effect";
4
5
  declare namespace BrowserTool_d_exports {
5
6
  export { browserToolkit, clickTool, fillTool, gotoTool, pressTool, scrollTool };
6
7
  }
7
8
  declare const gotoTool: (session: BrowserSession) => Tool<"browser_goto", {
8
9
  readonly url: string;
9
- }, unknown, string, BrowserError, never>;
10
+ }, string, never, BrowserError, never>;
10
11
  declare const clickTool: (session: BrowserSession) => Tool<"browser_click", {
11
12
  readonly ref: string;
12
- }, unknown, string, BrowserError, never>;
13
+ }, string, never, BrowserError, never>;
13
14
  declare const fillTool: (session: BrowserSession) => Tool<"browser_fill", {
14
15
  readonly ref: string;
15
16
  readonly text: string;
16
- }, unknown, string, BrowserError, never>;
17
+ }, string, never, BrowserError, never>;
17
18
  declare const pressTool: (session: BrowserSession) => Tool<"browser_press", {
18
19
  readonly key: string;
19
- }, unknown, string, BrowserError, never>;
20
+ }, string, never, BrowserError, never>;
20
21
  declare const scrollTool: (session: BrowserSession) => Tool<"browser_scroll", {
21
22
  readonly direction: "down" | "up";
22
- }, unknown, string, BrowserError, never>;
23
+ }, string, never, BrowserError, never>;
23
24
  /**
24
25
  * The canonical browser action verbs bundled as a `Toolkit`, closed over a
25
26
  * live `BrowserSession`. Compose it with a recipe-local page-reading tool and
@@ -34,22 +35,83 @@ declare const scrollTool: (session: BrowserSession) => Tool<"browser_scroll", {
34
35
  * constructors directly. Run a turn's calls with `{ concurrency: 1 }`.
35
36
  */
36
37
  declare const browserToolkit: (session: BrowserSession) => {
37
- browser_click: Tool<"browser_click", {
38
- readonly ref: string;
39
- }, unknown, string, BrowserError, never>;
40
- browser_fill: Tool<"browser_fill", {
41
- readonly ref: string;
42
- readonly text: string;
43
- }, unknown, string, BrowserError, never>;
44
- browser_goto: Tool<"browser_goto", {
45
- readonly url: string;
46
- }, unknown, string, BrowserError, never>;
47
- browser_press: Tool<"browser_press", {
48
- readonly key: string;
49
- }, unknown, string, BrowserError, never>;
50
- browser_scroll: Tool<"browser_scroll", {
51
- readonly direction: "down" | "up";
52
- }, unknown, string, BrowserError, never>;
38
+ browser_click: {
39
+ readonly name: "browser_click";
40
+ readonly description: string;
41
+ readonly inputSchema: ToolInputSchema<{
42
+ readonly ref: string;
43
+ }>;
44
+ readonly outputSchema?: Schema.Codec<string, any, never, never>;
45
+ readonly failureSchema?: Schema.Codec<never, any, never, never>;
46
+ readonly strict?: boolean;
47
+ } & {
48
+ readonly _tag: "LocalTool";
49
+ readonly run: Run<{
50
+ readonly ref: string;
51
+ }, string, BrowserError, never>;
52
+ };
53
+ browser_fill: {
54
+ readonly name: "browser_fill";
55
+ readonly description: string;
56
+ readonly inputSchema: ToolInputSchema<{
57
+ readonly ref: string;
58
+ readonly text: string;
59
+ }>;
60
+ readonly outputSchema?: Schema.Codec<string, any, never, never>;
61
+ readonly failureSchema?: Schema.Codec<never, any, never, never>;
62
+ readonly strict?: boolean;
63
+ } & {
64
+ readonly _tag: "LocalTool";
65
+ readonly run: Run<{
66
+ readonly ref: string;
67
+ readonly text: string;
68
+ }, string, BrowserError, never>;
69
+ };
70
+ browser_goto: {
71
+ readonly name: "browser_goto";
72
+ readonly description: string;
73
+ readonly inputSchema: ToolInputSchema<{
74
+ readonly url: string;
75
+ }>;
76
+ readonly outputSchema?: Schema.Codec<string, any, never, never>;
77
+ readonly failureSchema?: Schema.Codec<never, any, never, never>;
78
+ readonly strict?: boolean;
79
+ } & {
80
+ readonly _tag: "LocalTool";
81
+ readonly run: Run<{
82
+ readonly url: string;
83
+ }, string, BrowserError, never>;
84
+ };
85
+ browser_press: {
86
+ readonly name: "browser_press";
87
+ readonly description: string;
88
+ readonly inputSchema: ToolInputSchema<{
89
+ readonly key: string;
90
+ }>;
91
+ readonly outputSchema?: Schema.Codec<string, any, never, never>;
92
+ readonly failureSchema?: Schema.Codec<never, any, never, never>;
93
+ readonly strict?: boolean;
94
+ } & {
95
+ readonly _tag: "LocalTool";
96
+ readonly run: Run<{
97
+ readonly key: string;
98
+ }, string, BrowserError, never>;
99
+ };
100
+ browser_scroll: {
101
+ readonly name: "browser_scroll";
102
+ readonly description: string;
103
+ readonly inputSchema: ToolInputSchema<{
104
+ readonly direction: "down" | "up";
105
+ }>;
106
+ readonly outputSchema?: Schema.Codec<string, any, never, never>;
107
+ readonly failureSchema?: Schema.Codec<never, any, never, never>;
108
+ readonly strict?: boolean;
109
+ } & {
110
+ readonly _tag: "LocalTool";
111
+ readonly run: Run<{
112
+ readonly direction: "down" | "up";
113
+ }, string, BrowserError, never>;
114
+ };
53
115
  };
54
116
  //#endregion
55
117
  export { browserToolkit, clickTool, fillTool, gotoTool, pressTool, scrollTool, BrowserTool_d_exports as t };
@@ -1 +1 @@
1
- {"version":3,"file":"BrowserTool.d.mts","names":[],"sources":["../../src/browser/BrowserTool.ts"],"mappings":";;;;;;cAoEa,WAAQ,SAAa,mBAAc;;oBAAd;cAcrB,YAAS,SAAa,mBAAc;;oBAAd;cActB,WAAQ,SAAa,mBAAc;;;oBAAd;cAerB,YAAS,SAAa,mBAAc;;oBAAd;cActB,aAAU,SAAa,mBAAc;;oBAAd;;;;;;;;;;;;;;cA4BvB,iBAAc,SAAa;;;sBAAA"}
1
+ {"version":3,"file":"BrowserTool.d.mts","names":[],"sources":["../../src/browser/BrowserTool.ts"],"mappings":";;;;;;;cAoEa,WAAQ,SAAa,mBAAc;;kBAAd;cAerB,YAAS,SAAa,mBAAc;;kBAAd;cAetB,WAAQ,SAAa,mBAAc;;;kBAAd;cAgBrB,YAAS,SAAa,mBAAc;;kBAAd;cAetB,aAAU,SAAa,mBAAc;;kBAAd;;;;;;;;;;;;;;cA6BvB,iBAAc,SAAa"}
@@ -25,6 +25,7 @@ const gotoTool = (session) => make({
25
25
  name: "browser_goto",
26
26
  description: "Navigate the browser to an absolute URL.",
27
27
  inputSchema: fromEffectSchema(GotoArgs),
28
+ outputSchema: Schema.String,
28
29
  run: (args) => Effect.andThen(session.goto(args.url), okAt(session)).pipe(Effect.withSpan("browser_goto", {
29
30
  kind: "client",
30
31
  attributes: { "browser.url": args.url }
@@ -34,6 +35,7 @@ const clickTool = (session) => make({
34
35
  name: "browser_click",
35
36
  description: "Click the element named by ref. A click may navigate to a new page.",
36
37
  inputSchema: fromEffectSchema(ClickArgs),
38
+ outputSchema: Schema.String,
37
39
  run: (args) => Effect.andThen(session.click(args.ref), okAt(session)).pipe(Effect.withSpan("browser_click", {
38
40
  kind: "client",
39
41
  attributes: { "browser.ref": args.ref }
@@ -43,6 +45,7 @@ const fillTool = (session) => make({
43
45
  name: "browser_fill",
44
46
  description: "Put text into the input named by ref. Filling alone does not submit; press Enter to submit the input.",
45
47
  inputSchema: fromEffectSchema(FillArgs),
48
+ outputSchema: Schema.String,
46
49
  run: (args) => Effect.andThen(session.fill(args.ref, args.text), okAt(session)).pipe(Effect.withSpan("browser_fill", {
47
50
  kind: "client",
48
51
  attributes: { "browser.ref": args.ref }
@@ -52,6 +55,7 @@ const pressTool = (session) => make({
52
55
  name: "browser_press",
53
56
  description: "Press a keyboard key against the focused element.",
54
57
  inputSchema: fromEffectSchema(PressArgs),
58
+ outputSchema: Schema.String,
55
59
  run: (args) => Effect.andThen(session.press(args.key), okAt(session)).pipe(Effect.withSpan("browser_press", {
56
60
  kind: "client",
57
61
  attributes: { "browser.key": args.key }
@@ -61,6 +65,7 @@ const scrollTool = (session) => make({
61
65
  name: "browser_scroll",
62
66
  description: "Scroll the viewport. Only useful to bring an element into view - a page-reading tool's text is already scroll-independent.",
63
67
  inputSchema: fromEffectSchema(ScrollArgs),
68
+ outputSchema: Schema.String,
64
69
  run: (args) => Effect.andThen(session.scroll({ direction: args.direction }), okAt(session)).pipe(Effect.withSpan("browser_scroll", {
65
70
  kind: "client",
66
71
  attributes: { "browser.direction": args.direction }
@@ -1 +1 @@
1
- {"version":3,"file":"BrowserTool.mjs","names":["Tool.make","Tool.fromEffectSchema","Toolkit.make"],"sources":["../../src/browser/BrowserTool.ts"],"sourcesContent":["import { Effect, Schema } from \"effect\"\nimport * as Tool from \"../tool/Tool.js\"\nimport * as Toolkit from \"../tool/Toolkit.js\"\nimport type { BrowserSession } from \"./Browser.js\"\n\n// ---------------------------------------------------------------------------\n// Model-facing argument schemas. Annotated so the descriptions reach the\n// model through the rendered JSON Schema (JSDoc does not).\n// ---------------------------------------------------------------------------\n\nconst GotoArgs = Schema.Struct({\n url: Schema.String.annotate({ description: \"Absolute URL to navigate to.\" }),\n})\n\nconst ClickArgs = Schema.Struct({\n ref: Schema.String.annotate({\n description: \"A CSS selector, or an element @ref if a page-reading tool provides one.\",\n }),\n})\n\nconst FillArgs = Schema.Struct({\n ref: Schema.String.annotate({\n description: \"A CSS selector (or element @ref) of the input to fill.\",\n }),\n text: Schema.String.annotate({ description: \"The text to put in the input.\" }),\n})\n\nconst PressArgs = Schema.Struct({\n key: Schema.String.annotate({\n description: 'Key to press, e.g. \"Enter\" to submit the focused input, \"Tab\", \"Escape\".',\n }),\n})\n\nconst ScrollArgs = Schema.Struct({\n direction: Schema.Literals([\"up\", \"down\"]).annotate({\n description: \"Scroll the viewport up or down.\",\n }),\n})\n\n// ---------------------------------------------------------------------------\n// Uniform action outcome: the model always learns where the action left it.\n// ---------------------------------------------------------------------------\n\nconst currentUrl = (session: BrowserSession): Effect.Effect<string> =>\n session.evaluate(\"location.href\").pipe(\n Effect.flatMap(Schema.decodeUnknownEffect(Schema.String)),\n Effect.orElseSucceed(() => \"(unknown)\"),\n )\n\nconst okAt = (session: BrowserSession): Effect.Effect<string> =>\n Effect.map(currentUrl(session), (url) => `ok (now at ${url})`)\n\n// ---------------------------------------------------------------------------\n// The canonical browser action tools, each closed over a live `BrowserSession`\n// and failing with the full `BrowserError`. `Output` is a compact outcome\n// (`ok (now at <url>)`), not a page dump - a page-reading tool is the recipe's\n// to define, so history does not accumulate a full page per action.\n//\n// A failed action (stale ref, dead control, timeout) fails typed on the error\n// channel. Whether the model gets to recover from it is the loop's decision:\n// wrap the toolkit in `Toolkit.describeFailures(BrowserError.describe)` to\n// surface failures to the model, or map selectively to keep session/infra\n// errors (e.g. `BrowserSessionExpired`) fatal.\n//\n// Browser actions are order-dependent (fill, then press Enter): run a turn's\n// calls with `{ concurrency: 1 }`.\n// ---------------------------------------------------------------------------\n\nexport const gotoTool = (session: BrowserSession) =>\n Tool.make({\n name: \"browser_goto\",\n description: \"Navigate the browser to an absolute URL.\",\n inputSchema: Tool.fromEffectSchema(GotoArgs),\n run: (args) =>\n Effect.andThen(session.goto(args.url), okAt(session)).pipe(\n Effect.withSpan(\"browser_goto\", {\n kind: \"client\",\n attributes: { \"browser.url\": args.url },\n }),\n ),\n })\n\nexport const clickTool = (session: BrowserSession) =>\n Tool.make({\n name: \"browser_click\",\n description: \"Click the element named by ref. A click may navigate to a new page.\",\n inputSchema: Tool.fromEffectSchema(ClickArgs),\n run: (args) =>\n Effect.andThen(session.click(args.ref), okAt(session)).pipe(\n Effect.withSpan(\"browser_click\", {\n kind: \"client\",\n attributes: { \"browser.ref\": args.ref },\n }),\n ),\n })\n\nexport const fillTool = (session: BrowserSession) =>\n Tool.make({\n name: \"browser_fill\",\n description:\n \"Put text into the input named by ref. Filling alone does not submit; press Enter to submit the input.\",\n inputSchema: Tool.fromEffectSchema(FillArgs),\n run: (args) =>\n Effect.andThen(session.fill(args.ref, args.text), okAt(session)).pipe(\n Effect.withSpan(\"browser_fill\", {\n kind: \"client\",\n attributes: { \"browser.ref\": args.ref },\n }),\n ),\n })\n\nexport const pressTool = (session: BrowserSession) =>\n Tool.make({\n name: \"browser_press\",\n description: \"Press a keyboard key against the focused element.\",\n inputSchema: Tool.fromEffectSchema(PressArgs),\n run: (args) =>\n Effect.andThen(session.press(args.key), okAt(session)).pipe(\n Effect.withSpan(\"browser_press\", {\n kind: \"client\",\n attributes: { \"browser.key\": args.key },\n }),\n ),\n })\n\nexport const scrollTool = (session: BrowserSession) =>\n Tool.make({\n name: \"browser_scroll\",\n description:\n \"Scroll the viewport. Only useful to bring an element into view - a page-reading tool's text is already scroll-independent.\",\n inputSchema: Tool.fromEffectSchema(ScrollArgs),\n run: (args) =>\n Effect.andThen(session.scroll({ direction: args.direction }), okAt(session)).pipe(\n Effect.withSpan(\"browser_scroll\", {\n kind: \"client\",\n attributes: { \"browser.direction\": args.direction },\n }),\n ),\n })\n\n/**\n * The canonical browser action verbs bundled as a `Toolkit`, closed over a\n * live `BrowserSession`. Compose it with a recipe-local page-reading tool and\n * whatever finish/signal tools the agent needs:\n *\n * const toolkit = yield* Toolkit.compose(\n * browserToolkit(session),\n * Toolkit.make(readPageTool(session), finishTool),\n * )\n *\n * For an à-la-carte subset, use the individual `gotoTool` / `clickTool` / …\n * constructors directly. Run a turn's calls with `{ concurrency: 1 }`.\n */\nexport const browserToolkit = (session: BrowserSession) =>\n Toolkit.make(\n gotoTool(session),\n clickTool(session),\n fillTool(session),\n pressTool(session),\n scrollTool(session),\n )\n"],"mappings":"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"}
1
+ {"version":3,"file":"BrowserTool.mjs","names":["Tool.make","Tool.fromEffectSchema","Toolkit.make"],"sources":["../../src/browser/BrowserTool.ts"],"sourcesContent":["import { Effect, Schema } from \"effect\"\nimport * as Tool from \"../tool/Tool.js\"\nimport * as Toolkit from \"../tool/Toolkit.js\"\nimport type { BrowserSession } from \"./Browser.js\"\n\n// ---------------------------------------------------------------------------\n// Model-facing argument schemas. Annotated so the descriptions reach the\n// model through the rendered JSON Schema (JSDoc does not).\n// ---------------------------------------------------------------------------\n\nconst GotoArgs = Schema.Struct({\n url: Schema.String.annotate({ description: \"Absolute URL to navigate to.\" }),\n})\n\nconst ClickArgs = Schema.Struct({\n ref: Schema.String.annotate({\n description: \"A CSS selector, or an element @ref if a page-reading tool provides one.\",\n }),\n})\n\nconst FillArgs = Schema.Struct({\n ref: Schema.String.annotate({\n description: \"A CSS selector (or element @ref) of the input to fill.\",\n }),\n text: Schema.String.annotate({ description: \"The text to put in the input.\" }),\n})\n\nconst PressArgs = Schema.Struct({\n key: Schema.String.annotate({\n description: 'Key to press, e.g. \"Enter\" to submit the focused input, \"Tab\", \"Escape\".',\n }),\n})\n\nconst ScrollArgs = Schema.Struct({\n direction: Schema.Literals([\"up\", \"down\"]).annotate({\n description: \"Scroll the viewport up or down.\",\n }),\n})\n\n// ---------------------------------------------------------------------------\n// Uniform action outcome: the model always learns where the action left it.\n// ---------------------------------------------------------------------------\n\nconst currentUrl = (session: BrowserSession): Effect.Effect<string> =>\n session.evaluate(\"location.href\").pipe(\n Effect.flatMap(Schema.decodeUnknownEffect(Schema.String)),\n Effect.orElseSucceed(() => \"(unknown)\"),\n )\n\nconst okAt = (session: BrowserSession): Effect.Effect<string> =>\n Effect.map(currentUrl(session), (url) => `ok (now at ${url})`)\n\n// ---------------------------------------------------------------------------\n// The canonical browser action tools, each closed over a live `BrowserSession`\n// and failing with the full `BrowserError`. `Output` is a compact outcome\n// (`ok (now at <url>)`), not a page dump - a page-reading tool is the recipe's\n// to define, so history does not accumulate a full page per action.\n//\n// A failed action (stale ref, dead control, timeout) fails typed on the error\n// channel. Whether the model gets to recover from it is the loop's decision:\n// wrap the toolkit in `Toolkit.describeFailures(BrowserError.describe)` to\n// surface failures to the model, or map selectively to keep session/infra\n// errors (e.g. `BrowserSessionExpired`) fatal.\n//\n// Browser actions are order-dependent (fill, then press Enter): run a turn's\n// calls with `{ concurrency: 1 }`.\n// ---------------------------------------------------------------------------\n\nexport const gotoTool = (session: BrowserSession) =>\n Tool.make({\n name: \"browser_goto\",\n description: \"Navigate the browser to an absolute URL.\",\n inputSchema: Tool.fromEffectSchema(GotoArgs),\n outputSchema: Schema.String,\n run: (args) =>\n Effect.andThen(session.goto(args.url), okAt(session)).pipe(\n Effect.withSpan(\"browser_goto\", {\n kind: \"client\",\n attributes: { \"browser.url\": args.url },\n }),\n ),\n })\n\nexport const clickTool = (session: BrowserSession) =>\n Tool.make({\n name: \"browser_click\",\n description: \"Click the element named by ref. A click may navigate to a new page.\",\n inputSchema: Tool.fromEffectSchema(ClickArgs),\n outputSchema: Schema.String,\n run: (args) =>\n Effect.andThen(session.click(args.ref), okAt(session)).pipe(\n Effect.withSpan(\"browser_click\", {\n kind: \"client\",\n attributes: { \"browser.ref\": args.ref },\n }),\n ),\n })\n\nexport const fillTool = (session: BrowserSession) =>\n Tool.make({\n name: \"browser_fill\",\n description:\n \"Put text into the input named by ref. Filling alone does not submit; press Enter to submit the input.\",\n inputSchema: Tool.fromEffectSchema(FillArgs),\n outputSchema: Schema.String,\n run: (args) =>\n Effect.andThen(session.fill(args.ref, args.text), okAt(session)).pipe(\n Effect.withSpan(\"browser_fill\", {\n kind: \"client\",\n attributes: { \"browser.ref\": args.ref },\n }),\n ),\n })\n\nexport const pressTool = (session: BrowserSession) =>\n Tool.make({\n name: \"browser_press\",\n description: \"Press a keyboard key against the focused element.\",\n inputSchema: Tool.fromEffectSchema(PressArgs),\n outputSchema: Schema.String,\n run: (args) =>\n Effect.andThen(session.press(args.key), okAt(session)).pipe(\n Effect.withSpan(\"browser_press\", {\n kind: \"client\",\n attributes: { \"browser.key\": args.key },\n }),\n ),\n })\n\nexport const scrollTool = (session: BrowserSession) =>\n Tool.make({\n name: \"browser_scroll\",\n description:\n \"Scroll the viewport. Only useful to bring an element into view - a page-reading tool's text is already scroll-independent.\",\n inputSchema: Tool.fromEffectSchema(ScrollArgs),\n outputSchema: Schema.String,\n run: (args) =>\n Effect.andThen(session.scroll({ direction: args.direction }), okAt(session)).pipe(\n Effect.withSpan(\"browser_scroll\", {\n kind: \"client\",\n attributes: { \"browser.direction\": args.direction },\n }),\n ),\n })\n\n/**\n * The canonical browser action verbs bundled as a `Toolkit`, closed over a\n * live `BrowserSession`. Compose it with a recipe-local page-reading tool and\n * whatever finish/signal tools the agent needs:\n *\n * const toolkit = yield* Toolkit.compose(\n * browserToolkit(session),\n * Toolkit.make(readPageTool(session), finishTool),\n * )\n *\n * For an à-la-carte subset, use the individual `gotoTool` / `clickTool` / …\n * constructors directly. Run a turn's calls with `{ concurrency: 1 }`.\n */\nexport const browserToolkit = (session: BrowserSession) =>\n Toolkit.make(\n gotoTool(session),\n clickTool(session),\n fillTool(session),\n pressTool(session),\n scrollTool(session),\n )\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { o as HistoryItem, r as ContentBlock } from "../Items-C7MyrYPX.mjs";
1
+ import { o as HistoryItem, r as ContentBlock } from "../Items-Bvx8s9QH.mjs";
2
2
  import { Effect } from "effect";
3
3
  declare namespace Capabilities_d_exports {
4
4
  export { CapabilityWarning, warnDropped, warnDroppedBlocks, warnDroppedWhen };
@@ -4,7 +4,7 @@ import { DecisionModel, decide } from "./DecisionModel.mjs";
4
4
  import { m as describe } from "../dist-DzeSyeYF.mjs";
5
5
  import { n as globalExpect } from "../index.C4tKZ0yW-LuFnBtmu.mjs";
6
6
  import { t as import_dist } from "../dist-DNeuh84d.mjs";
7
- import { t as it } from "../dist-C8RmtoR8.mjs";
7
+ import { t as it } from "../dist-B5K-y4Be.mjs";
8
8
  import { Effect, Layer, Option, Ref, Schema } from "effect";
9
9
  //#region src/decision-model/Decision.test.ts
10
10
  const triage = make({
@@ -5,36 +5,38 @@ import * as Cause from "effect/Cause";
5
5
  import * as Duration from "effect/Duration";
6
6
  import * as Effect from "effect/Effect";
7
7
  import * as Exit from "effect/Exit";
8
+ import "effect/Fiber";
8
9
  import { constVoid, flow, pipe } from "effect/Function";
9
10
  import * as Layer from "effect/Layer";
10
11
  import * as Schedule from "effect/Schedule";
11
12
  import * as Scope from "effect/Scope";
12
13
  import * as TestClock from "effect/testing/TestClock";
13
14
  import * as TestConsole from "effect/testing/TestConsole";
14
- //#region ../../node_modules/.pnpm/@effect+vitest@4.0.1_effect@4.0.1_vitest@5.0.3_@types+node@26.2.0_vite@7.3.2_@types+nod_65816e3353e20bfeb9b2e1494bdddeef/node_modules/@effect/vitest/dist/internal/internal.js
15
+ //#region ../../node_modules/.pnpm/@effect+vitest@4.1.2_effect@4.1.2_vitest@5.0.3_@types+node@26.2.0_vite@7.3.2_@types+nod_a2fffe0deec250ef9d6207b86a9a1ab8/node_modules/@effect/vitest/dist/internal/internal.js
15
16
  /**
16
17
  * @since 4.0.0
17
18
  */
18
19
  const getCurrentSuite = TestRunner.getCurrentSuite;
19
- const runPromise = /*#__PURE__*/ Effect.fnUntraced(function* (effect, _ctx) {
20
- const exit = yield* Effect.exit(effect);
20
+ const runPromise = (effect, ctx) => Effect.runPromise(Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
21
+ const exit = yield* Effect.exit(restore(effect));
21
22
  if (Exit.isFailure(exit)) {
22
23
  const errors = Cause.prettyErrors(exit.cause);
23
24
  for (let i = 0; i < errors.length; i++) yield* Effect.logError(errors[i]);
24
25
  }
25
26
  return yield* exit;
26
- }, (effect, _, ctx) => Effect.runPromise(effect, { signal: ctx?.signal }));
27
+ })), { signal: ctx?.signal });
28
+ const settleOnAbort = (ctx, promise) => {
29
+ const onAbort = () => ctx.onTestFinished(() => promise.then(constVoid, constVoid));
30
+ ctx.signal.addEventListener("abort", onAbort, { once: true });
31
+ const cleanup = () => ctx.signal.removeEventListener("abort", onAbort);
32
+ promise.then(cleanup, cleanup);
33
+ if (ctx.signal.aborted) onAbort();
34
+ return promise;
35
+ };
27
36
  /** @internal */
28
37
  const runTest = (ctx) => (effect) => {
29
38
  const promise = runPromise(effect, ctx);
30
- if (ctx) {
31
- const onAbort = () => ctx.onTestFinished(() => promise.then(constVoid, constVoid));
32
- ctx.signal.addEventListener("abort", onAbort, { once: true });
33
- const cleanup = () => ctx.signal.removeEventListener("abort", onAbort);
34
- promise.then(cleanup, cleanup);
35
- if (ctx.signal.aborted) onAbort();
36
- }
37
- return promise;
39
+ return ctx ? settleOnAbort(ctx, promise) : promise;
38
40
  };
39
41
  const TestEnv = /*#__PURE__*/ Layer.mergeAll(TestConsole.layer, /*#__PURE__*/ TestClock.layer());
40
42
  /** @internal */
@@ -70,6 +72,9 @@ const collectTasks = (tasks, acc = []) => {
70
72
  }
71
73
  return acc;
72
74
  };
75
+ const runsMoreThanOnce = (task) => {
76
+ return ((typeof task.retry === "number" ? task.retry : task.retry?.count) ?? 0) > 0 || (task.repeats ?? 0) > 0;
77
+ };
73
78
  const registerProp = (it, name, arbitraries, property, timeout) => {
74
79
  const arbitrary = makeArbitrary(arbitraries);
75
80
  it(name, testOptions(timeout), withFixturesOf(() => {}, (ctx) => runCheck(ctx, arbitrary, (values) => property(values, ctx), checkOptions(timeout))));
@@ -89,11 +94,35 @@ const makeTester = (mapEffect, it) => {
89
94
  prop
90
95
  });
91
96
  };
92
- const makeProp = (it) => (name, arbitraries, self, timeout) => registerProp(it, name, arbitraries, (values, ctx) => self(values, ctx) !== false, timeout);
97
+ const makeProp = (it) => (name, arbitraries, self, timeout) => registerProp(it, name, arbitraries, (values, ctx) => {
98
+ const result = self(values, ctx);
99
+ if (result !== void 0 && typeof result !== "boolean") throw new TypeError("it.prop callbacks must return boolean or void. Use it.effect.prop for Effect callbacks.");
100
+ return result !== false;
101
+ }, timeout);
93
102
  const makeLayer = (it) => (layer_, options) => (...args) => {
94
103
  const excludeTestServices = options?.excludeTestServices ?? false;
95
104
  const withTestEnv = excludeTestServices ? layer_ : Layer.provideMerge(layer_, TestEnv);
96
105
  const memoMap = options?.memoMap ?? Effect.runSync(Layer.makeMemoMap);
106
+ const buildPerTest = options?.buildPerTest ?? false;
107
+ const suiteOptions = options?.concurrent === void 0 ? {} : { concurrent: options.concurrent };
108
+ const makeBlockMethods = (provide) => makeItProxy(it, {
109
+ effect: makeTester((effect) => provide(Effect.scoped(effect)), it),
110
+ prop: makeProp(it),
111
+ flakyTest,
112
+ layer(nestedLayer, nestedOptions) {
113
+ return makeLayer(it)(Layer.provideMerge(nestedLayer, withTestEnv), {
114
+ ...nestedOptions,
115
+ memoMap: Layer.forkMemoMapUnsafe(memoMap),
116
+ excludeTestServices,
117
+ buildPerTest: buildPerTest || nestedOptions?.buildPerTest === true
118
+ });
119
+ }
120
+ });
121
+ if (buildPerTest) {
122
+ const methods = makeBlockMethods((effect) => Effect.scopedWith((scope) => Layer.buildWithMemoMap(withTestEnv, Layer.forkMemoMapUnsafe(memoMap), scope).pipe(Effect.orDie, Effect.flatMap((context) => Effect.provide(effect, context)))));
123
+ if (args.length === 1) return args[0](methods);
124
+ return describe(args[0], suiteOptions, () => args[1](methods));
125
+ }
97
126
  const scope = Effect.runSync(Scope.make());
98
127
  const contextEffect = Layer.buildWithMemoMap(withTestEnv, memoMap, scope).pipe(Effect.orDie, Effect.cached, Effect.runSync);
99
128
  let closed = false;
@@ -102,18 +131,7 @@ const makeLayer = (it) => (layer_, options) => (...args) => {
102
131
  closed = true;
103
132
  return runPromise(Scope.close(scope, Exit.void));
104
133
  };
105
- const methods = makeItProxy(it, {
106
- effect: makeTester((effect) => Effect.flatMap(contextEffect, (context) => effect.pipe(Effect.scoped, Effect.provide(context))), it),
107
- prop: makeProp(it),
108
- flakyTest,
109
- layer(nestedLayer, options) {
110
- return makeLayer(it)(Layer.provideMerge(nestedLayer, withTestEnv), {
111
- ...options,
112
- memoMap: Layer.forkMemoMapUnsafe(memoMap),
113
- excludeTestServices
114
- });
115
- }
116
- });
134
+ const methods = makeBlockMethods((effect) => Effect.flatMap(contextEffect, (context) => Effect.provide(effect, context)));
117
135
  if (args.length === 1) {
118
136
  const currentSuite = getCurrentSuite();
119
137
  const previousTasks = new Set(currentSuite.tasks);
@@ -124,10 +142,11 @@ const makeLayer = (it) => (layer_, options) => (...args) => {
124
142
  return;
125
143
  }
126
144
  const blockTaskSet = new Set(blockTasks);
145
+ const releaseAfterLastTest = !blockTasks.some(runsMoreThanOnce);
127
146
  let remaining = blockTasks.length;
128
147
  beforeEach(({ onTestFinished, signal, task }) => {
129
148
  if (!blockTaskSet.has(task)) return;
130
- onTestFinished(() => {
149
+ if (releaseAfterLastTest) onTestFinished(() => {
131
150
  remaining--;
132
151
  if (remaining === 0) return closeScope();
133
152
  });
@@ -136,7 +155,6 @@ const makeLayer = (it) => (layer_, options) => (...args) => {
136
155
  afterAll(() => closeScope(), hookTimeout(options?.timeout));
137
156
  return;
138
157
  }
139
- const suiteOptions = options?.concurrent === void 0 ? {} : { concurrent: options.concurrent };
140
158
  return describe(args[0], suiteOptions, () => {
141
159
  beforeAll(() => runPromise(Effect.asVoid(contextEffect)), hookTimeout(options?.timeout));
142
160
  afterAll(() => closeScope(), hookTimeout(options?.timeout));
@@ -158,15 +176,16 @@ const it$1 = /*#__PURE__*/ makeMethods(it$2);
158
176
  /** @internal */
159
177
  const { effect, layer, live, prop } = it$1;
160
178
  //#endregion
161
- //#region ../../node_modules/.pnpm/@effect+vitest@4.0.1_effect@4.0.1_vitest@5.0.3_@types+node@26.2.0_vite@7.3.2_@types+nod_65816e3353e20bfeb9b2e1494bdddeef/node_modules/@effect/vitest/dist/index.js
162
- /**
163
- * @since 4.0.0
164
- */
179
+ //#region ../../node_modules/.pnpm/@effect+vitest@4.1.2_effect@4.1.2_vitest@5.0.3_@types+node@26.2.0_vite@7.3.2_@types+nod_a2fffe0deec250ef9d6207b86a9a1ab8/node_modules/@effect/vitest/dist/index.js
165
180
  /**
181
+ * Vitest test API extended with Effect test helpers.
182
+ *
183
+ * @stability unstable
184
+ * @category testing
166
185
  * @since 4.0.0
167
186
  */
168
187
  const it = it$1;
169
188
  //#endregion
170
189
  export { it as t };
171
190
 
172
- //# sourceMappingURL=dist-C8RmtoR8.mjs.map
191
+ //# sourceMappingURL=dist-B5K-y4Be.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dist-B5K-y4Be.mjs","names":["V.describe","it","V.it","internal.it"],"sources":["../../../node_modules/.pnpm/@effect+vitest@4.1.2_effect@4.1.2_vitest@5.0.3_@types+node@26.2.0_vite@7.3.2_@types+nod_a2fffe0deec250ef9d6207b86a9a1ab8/node_modules/@effect/vitest/dist/internal/internal.js","../../../node_modules/.pnpm/@effect+vitest@4.1.2_effect@4.1.2_vitest@5.0.3_@types+node@26.2.0_vite@7.3.2_@types+nod_a2fffe0deec250ef9d6207b86a9a1ab8/node_modules/@effect/vitest/dist/index.js"],"sourcesContent":["/**\n * @since 4.0.0\n */\nimport * as Arbitrary from \"effect/Arbitrary\";\nimport * as Cause from \"effect/Cause\";\nimport * as Duration from \"effect/Duration\";\nimport * as Effect from \"effect/Effect\";\nimport * as Exit from \"effect/Exit\";\nimport * as Fiber from \"effect/Fiber\";\nimport { constVoid, flow, pipe } from \"effect/Function\";\nimport * as Layer from \"effect/Layer\";\nimport * as Schedule from \"effect/Schedule\";\nimport * as Scope from \"effect/Scope\";\nimport * as TestClock from \"effect/testing/TestClock\";\nimport * as TestConsole from \"effect/testing/TestConsole\";\nimport * as V from \"vitest\";\nconst getCurrentSuite = V.TestRunner.getCurrentSuite;\nconst runPromise = (effect, ctx) => Effect.runPromise(\n// Only the test is interruptible: once the signal aborts, the fiber stops\n// at its next interruptible step, which would skip reporting the defects\n// raised by finalizers.\nEffect.uninterruptibleMask(restore => Effect.gen(function* () {\n const exit = yield* Effect.exit(restore(effect));\n if (Exit.isFailure(exit)) {\n const errors = Cause.prettyErrors(exit.cause);\n for (let i = 0; i < errors.length; i++) {\n yield* Effect.logError(errors[i]);\n }\n }\n return yield* exit;\n})), {\n signal: ctx?.signal\n});\nconst settleOnAbort = (ctx, promise) => {\n // Vitest stops awaiting the promise once the signal aborts (timeout or\n // cancellation), so only then add a hook that waits for the finalizers.\n // Registering it unconditionally would change the teardown of every test.\n const onAbort = () => ctx.onTestFinished(() => promise.then(constVoid, constVoid));\n ctx.signal.addEventListener(\"abort\", onAbort, {\n once: true\n });\n const cleanup = () => ctx.signal.removeEventListener(\"abort\", onAbort);\n promise.then(cleanup, cleanup);\n // A retry after a timed-out attempt reuses the aborted signal, so no event fires.\n if (ctx.signal.aborted) onAbort();\n return promise;\n};\n/** @internal */\nconst runTest = ctx => effect => {\n const promise = runPromise(effect, ctx);\n return ctx ? settleOnAbort(ctx, promise) : promise;\n};\nconst TestEnv = /*#__PURE__*/Layer.mergeAll(TestConsole.layer, /*#__PURE__*/TestClock.layer());\n/** @internal */\nexport const addEqualityTesters = () => {\n V.expect.addEqualityTesters([]);\n};\n/** @internal */\nconst testOptions = timeout => typeof timeout === \"number\" ? {\n timeout\n} : timeout ?? {};\nconst hookTimeout = timeout => timeout === undefined ? undefined : Duration.toMillis(Duration.fromInputUnsafe(timeout));\nconst propertyTestOptions = timeout => typeof timeout === \"number\" ? undefined : timeout;\nconst checkOptions = timeout => propertyTestOptions(timeout)?.arbitrary;\nconst compileArbitraryInput = input => Arbitrary.isArbitrary(input) ? input : Arbitrary.schema(input);\nconst makeArbitrary = arbitraries => Arbitrary.all(Array.isArray(arbitraries) ? arbitraries.map(compileArbitraryInput) : Object.fromEntries(Object.entries(arbitraries).map(([key, input]) => [key, compileArbitraryInput(input)])));\nconst normalizeProperty = (property, value) => Effect.catchCause(Effect.suspend(() => {\n const output = property(value);\n return Effect.isEffect(output) ? output : Effect.succeed(output);\n}), cause => Cause.hasInterrupts(cause) ? Effect.failCause(cause) : Effect.fail(cause));\nconst runCheck = (ctx, arbitrary, property, options) => runTest(ctx)(Effect.flatMapEager(Arbitrary.checkEffect(arbitrary, value => normalizeProperty(property, value), options), result => {\n const failure = Arbitrary.formatCheckFailure(result);\n return failure === undefined ? Effect.void : Effect.die(new Error(failure));\n}));\n// Vitest decides which fixtures to set up by parsing the source of a test\n// function's context parameter, and there is no public API to supply the names\n// for a wrapper, so wrappers expose the source of the function they call.\nconst withFixturesOf = (source, f) => Object.defineProperty(f, \"toString\", {\n value: () => source.toString()\n});\nconst runHook = (fn, run) => withFixturesOf(fn, (...args) => {\n const result = fn(...args);\n if (!Effect.isEffect(result)) {\n return result;\n }\n const scope = Scope.makeUnsafe();\n // Everything the hook leaves behind lives in the scope: the resources it\n // acquired and, ahead of them, a cleanup function it returned. On failure\n // the scope closes inside the fiber, so interrupting it awaits the release.\n const effect = Scope.provide(result, scope).pipe(Effect.flatMap(cleanup => typeof cleanup === \"function\" ? Scope.addFinalizer(scope, Effect.promise(async () => await cleanup())) : Effect.void), Effect.onError(cause => Scope.close(scope, Exit.failCause(cause))));\n return run(args, effect, scope);\n});\n// Closing must outlive an already-aborted signal, so it runs without one.\nconst closeHookScope = scope => runPromise(Scope.close(scope, Exit.void));\n/** @internal */\nexport const beforeAll = (fn, timeout) => {\n let dispose = () => Promise.resolve();\n // Vitest drops the cleanup of a setup that outlives its timeout, so the\n // scope is disposed by the cleanup of a hook registered just before this\n // one. It runs in the same cleanup phase, in the slot next to this hook's,\n // with this hook's timeout.\n V.beforeAll(() => () => dispose(), timeout);\n V.beforeAll(runHook(fn, (_, effect, scope) => {\n const fiber = Effect.runFork(effect);\n // Interrupting a setup that Vitest stopped waiting for awaits its release.\n dispose = () => runPromise(Effect.andThen(Fiber.interrupt(fiber), Scope.close(scope, Exit.void)));\n return runPromise(Fiber.join(fiber));\n }), timeout);\n};\n/** @internal */\nexport const beforeEach = (fn, timeout) => V.beforeEach(runHook(fn, ([ctx], effect, scope) =>\n// The scope closes when Vitest runs the hook's cleanup after the test,\n// and the next test waits for it even if that cleanup times out.\nrunTest(ctx)(effect).then(() => () => settleOnAbort(ctx, closeHookScope(scope)))), timeout);\nconst makeItProxy = (it, overrides) => new Proxy(it, {\n apply(target, thisArg, argArray) {\n return Reflect.apply(target, thisArg, argArray);\n },\n get(target, property, receiver) {\n if (Object.hasOwn(overrides, property)) {\n return Reflect.get(overrides, property);\n }\n // do not bind: binding would strip vitest's static helpers (e.g. `describe.each`)\n return Reflect.get(target, property, receiver);\n }\n});\nconst collectTasks = (tasks, acc = []) => {\n for (let i = 0; i < tasks.length; i++) {\n const task = tasks[i];\n if (task.type === \"test\" && task.mode !== \"skip\" && task.mode !== \"todo\") {\n acc.push(task);\n } else if (task.tasks !== undefined) {\n collectTasks(task.tasks, acc);\n }\n }\n return acc;\n};\nconst runsMoreThanOnce = task => {\n const retry = typeof task.retry === \"number\" ? task.retry : task.retry?.count;\n return (retry ?? 0) > 0 || (task.repeats ?? 0) > 0;\n};\nconst registerProp = (it, name, arbitraries, property, timeout) => {\n const arbitrary = makeArbitrary(arbitraries);\n // Property callbacks receive only the base context; the empty source requests no fixtures.\n it(name, testOptions(timeout), withFixturesOf(() => {}, ctx => runCheck(ctx, arbitrary, values => property(values, ctx), checkOptions(timeout))));\n};\nconst makeTester = (mapEffect, it) => {\n const run = (ctx, args, self) => pipe(Effect.suspend(() => self(...args)), mapEffect, runTest(ctx));\n const register = test => (name, self, timeout) => test(name, testOptions(timeout), withFixturesOf(self, ctx => run(ctx, [ctx], self)));\n const each = cases => (name, self, timeout) => it.for(cases)(name, testOptions(timeout), withFixturesOf(self, (args, ctx) => run(ctx, [args, ctx], self).then(constVoid)));\n const prop = (name, arbitraries, self, timeout) => registerProp(it, name, arbitraries, (values, ctx) => Effect.mapEager(mapEffect(Effect.suspend(() => self(values, ctx))), value => value !== false), timeout);\n return Object.assign(register(it), {\n skip: register(it.skip),\n skipIf: condition => register(it.skipIf(condition)),\n runIf: condition => register(it.runIf(condition)),\n only: register(it.only),\n each,\n fails: register(it.fails),\n prop\n });\n};\nconst makeProp = it => (name, arbitraries, self, timeout) => registerProp(it, name, arbitraries, (values, ctx) => {\n const result = self(values, ctx);\n if (result !== undefined && typeof result !== \"boolean\") {\n throw new TypeError(\"it.prop callbacks must return boolean or void. Use it.effect.prop for Effect callbacks.\");\n }\n return result !== false;\n}, timeout);\nconst makeLayer = it => (layer_, options) => (...args) => {\n const excludeTestServices = options?.excludeTestServices ?? false;\n const withTestEnv = excludeTestServices ? layer_ : Layer.provideMerge(layer_, TestEnv);\n const memoMap = options?.memoMap ?? Effect.runSync(Layer.makeMemoMap);\n const buildPerTest = options?.buildPerTest ?? false;\n const suiteOptions = options?.concurrent === undefined ? {} : {\n concurrent: options.concurrent\n };\n const makeBlockMethods = provide => makeItProxy(it, {\n effect: makeTester(effect => provide(Effect.scoped(effect)), it),\n prop: makeProp(it),\n flakyTest,\n layer(nestedLayer, nestedOptions) {\n return makeLayer(it)(Layer.provideMerge(nestedLayer, withTestEnv), {\n ...nestedOptions,\n memoMap: Layer.forkMemoMapUnsafe(memoMap),\n excludeTestServices,\n // The services of a per-test block only exist during a test, so\n // blocks nested in it are built per test as well.\n buildPerTest: buildPerTest || nestedOptions?.buildPerTest === true\n });\n }\n });\n if (buildPerTest) {\n // Each test builds into its own fork of the memo map, so it reuses the\n // services of enclosing blocks and releases the rest when it finishes.\n const methods = makeBlockMethods(effect => Effect.scopedWith(scope => Layer.buildWithMemoMap(withTestEnv, Layer.forkMemoMapUnsafe(memoMap), scope).pipe(Effect.orDie, Effect.flatMap(context => Effect.provide(effect, context)))));\n if (args.length === 1) {\n return args[0](methods);\n }\n return V.describe(args[0], suiteOptions, () => args[1](methods));\n }\n const scope = Effect.runSync(Scope.make());\n const contextEffect = Layer.buildWithMemoMap(withTestEnv, memoMap, scope).pipe(Effect.orDie, Effect.cached, Effect.runSync);\n let closed = false;\n const closeScope = () => {\n if (closed) {\n return Promise.resolve();\n }\n closed = true;\n // Layer cleanup must outlive the last test's already-aborted signal.\n return runPromise(Scope.close(scope, Exit.void));\n };\n const methods = makeBlockMethods(effect => Effect.flatMap(contextEffect, context => Effect.provide(effect, context)));\n if (args.length === 1) {\n const currentSuite = getCurrentSuite();\n const previousTasks = new Set(currentSuite.tasks);\n args[0](methods);\n const blockTasks = collectTasks(currentSuite.tasks.filter(task => !previousTasks.has(task)));\n if (blockTasks.length === 0) {\n V.afterAll(() => closeScope(), hookTimeout(options?.timeout));\n return;\n }\n const blockTaskSet = new Set(blockTasks);\n // Vitest runs hooks once per retry and repeat attempt, so a test's last\n // attempt cannot be counted. Blocks with such tests are released by `afterAll`.\n const releaseAfterLastTest = !blockTasks.some(runsMoreThanOnce);\n let remaining = blockTasks.length;\n V.beforeEach(\n // Destructured so Vitest can parse the hook once the suite defines fixtures.\n ({\n onTestFinished,\n signal,\n task\n }) => {\n if (!blockTaskSet.has(task)) {\n return;\n }\n if (releaseAfterLastTest) {\n onTestFinished(() => {\n remaining--;\n if (remaining === 0) {\n return closeScope();\n }\n });\n }\n return runPromise(Effect.asVoid(contextEffect), {\n signal\n });\n }, hookTimeout(options?.timeout));\n V.afterAll(() => closeScope(), hookTimeout(options?.timeout));\n return;\n }\n return V.describe(args[0], suiteOptions, () => {\n V.beforeAll(() => runPromise(Effect.asVoid(contextEffect)), hookTimeout(options?.timeout));\n V.afterAll(() => closeScope(), hookTimeout(options?.timeout));\n return args[1](methods);\n });\n};\n/** @internal */\nexport const flakyTest = (self, timeout = Duration.seconds(30)) => pipe(self, Effect.scoped, Effect.sandbox, Effect.retry(pipe(Schedule.recurs(10), Schedule.while(_ => Effect.succeed(Duration.isLessThanOrEqualTo(Duration.fromInputUnsafe(_.elapsed), Duration.fromInputUnsafe(timeout)))))), Effect.orDie);\n/** @internal */\nexport const makeMethods = it => makeItProxy(it, {\n effect: makeTester(flow(Effect.scoped, Effect.provide(TestEnv)), it),\n live: makeTester(Effect.scoped, it),\n flakyTest,\n layer: makeLayer(it),\n prop: makeProp(it)\n});\n/** @internal */\nexport const it = /*#__PURE__*/makeMethods(V.it);\n/** @internal */\nexport const {\n /** @internal */\n effect,\n /** @internal */\n layer,\n /** @internal */\n live,\n /** @internal */\n prop\n} = it;\n/** @internal */\nexport const describeWrapped = (name, f) => V.describe(name, () => f(it));\n//# sourceMappingURL=internal.js.map","import * as internal from \"./internal/internal.js\";\n/**\n * Re-exports the `vitest` API unchanged.\n *\n * @stability unstable\n * @since 4.0.0\n */\nexport * from \"vitest\";\n/**\n * Invokes the Effect Vitest equality-tester registration hook.\n *\n * @stability unstable\n * @category utils\n * @since 4.0.0\n */\nexport const addEqualityTesters = internal.addEqualityTesters;\n/**\n * Registers a callback to run once before all tests in the current suite. If\n * the callback returns an `Effect`, it is run and awaited with a `Scope` that\n * closes in a cleanup after the suite's `afterAll` hooks, within the hook's\n * timeout. The `Effect` must not require any other services.\n *\n * **Details**\n *\n * If Vitest stops waiting for the setup, the setup is interrupted before the\n * `Scope` closes. As with any `beforeAll` cleanup, Vitest reports a closing\n * that exceeds the hook's timeout and does not wait for it.\n *\n * @stability unstable\n * @category hooks\n * @since 4.0.0\n */\nexport const beforeAll = internal.beforeAll;\n/**\n * Registers a callback to run before each test in the current suite. If the\n * callback returns an `Effect`, it is run and awaited with a `Scope` that\n * closes when the test finishes, and interrupted if the hook times out. The\n * `Effect` must not require any other services.\n *\n * @stability unstable\n * @category hooks\n * @since 4.0.0\n */\nexport const beforeEach = internal.beforeEach;\n/**\n * Runs a scoped Effect test with test clock and console services.\n *\n * @stability unstable\n * @category testing\n * @since 4.0.0\n */\nexport const effect = internal.effect;\n/**\n * Runs a scoped Effect test with live services.\n *\n * @stability unstable\n * @category testing\n * @since 4.0.0\n */\nexport const live = internal.live;\n/**\n * Share a `Layer` between multiple tests, optionally wrapping\n * the tests in a `describe` block if a name is provided.\n *\n * **Details**\n *\n * Named layers accept `concurrent` to override inherited suite concurrency.\n * Anonymous layers always inherit the enclosing suite's concurrency.\n * Use `ctx.expect` in concurrent tests for test-local snapshots and assertion counts.\n *\n * Pass `buildPerTest: true` to build the layer once per test instead of once\n * per block. Each test gets new services, released when the test finishes,\n * while services from an enclosing `layer` block stay shared. A build failure\n * fails only that test. Blocks nested inside a per-test block are built per\n * test as well. `timeout` has no effect on a per-test block, since the test's\n * own timeout covers the build.\n *\n * **Example** (Sharing layers between tests)\n *\n * ```ts\n * import { assert, layer } from \"@effect/vitest\"\n * import { Effect, Layer, Context } from \"effect\"\n *\n * class Foo extends Context.Service<Foo, \"foo\">()(\"Foo\") {\n * static layer = Layer.succeed(Foo, \"foo\")\n * }\n *\n * class Bar extends Context.Service<Bar, \"bar\">()(\"Bar\") {\n * static layer = Layer.effect(\n * Bar,\n * Effect.map(Foo, () => \"bar\" as const)\n * )\n * }\n *\n * layer(Foo.layer)(\"layer\", (it) => {\n * it.effect(\"adds context\", () =>\n * Effect.gen(function*() {\n * const foo = yield* Foo\n * assert.strictEqual(foo, \"foo\")\n * }))\n *\n * it.layer(Bar.layer)(\"nested\", (it) => {\n * it.effect(\"adds context\", () =>\n * Effect.gen(function*() {\n * const foo = yield* Foo\n * const bar = yield* Bar\n * assert.strictEqual(foo, \"foo\")\n * assert.strictEqual(bar, \"bar\")\n * }))\n * })\n * })\n * ```\n *\n * **Example** (Building a layer for each test)\n *\n * ```ts\n * import { assert, layer } from \"@effect/vitest\"\n * import { Effect, Layer, Context, Ref } from \"effect\"\n *\n * class Database extends Context.Service<Database, \"database\">()(\"Database\") {\n * static layer = Layer.succeed(Database, \"database\")\n * }\n *\n * class Cache extends Context.Service<Cache, Ref.Ref<Array<string>>>()(\"Cache\") {\n * static layer = Layer.effect(\n * Cache,\n * Effect.andThen(Database, Ref.make<Array<string>>([]))\n * )\n * }\n *\n * layer(Database.layer)(\"repository\", (it) => {\n * // Database is shared, Cache is built for each test\n * it.layer(Cache.layer, { buildPerTest: true })((it) => {\n * it.effect(\"writes to the cache\", () =>\n * Effect.gen(function*() {\n * const cache = yield* Cache\n * yield* Ref.update(cache, (keys) => [...keys, \"a\"])\n * assert.deepStrictEqual(yield* Ref.get(cache), [\"a\"])\n * }))\n *\n * it.effect(\"starts with an empty cache\", () =>\n * Effect.gen(function*() {\n * const cache = yield* Cache\n * assert.deepStrictEqual(yield* Ref.get(cache), [])\n * }))\n * })\n * })\n * ```\n *\n * @stability unstable\n * @category testing\n * @since 4.0.0\n */\nexport const layer = internal.layer;\n/**\n * Retries a scoped Effect to tolerate intermittent test failures, dying on exhausted retries.\n *\n * @stability unstable\n * @category testing\n * @since 4.0.0\n */\nexport const flakyTest = internal.flakyTest;\n/**\n * Runs a synchronous property test using schemas or arbitraries.\n *\n * @stability unstable\n * @category testing\n * @since 4.0.0\n */\nexport const prop = internal.prop;\n/**\n * Vitest test API extended with Effect test helpers.\n *\n * @stability unstable\n * @category testing\n * @since 4.0.0\n */\nexport const it = internal.it;\n/**\n * Creates the Effect test helpers for a Vitest test API, such as one extended with fixtures.\n *\n * **Details**\n *\n * Tests receive the fixtures they destructure from their context. Vitest sets them up before the test and tears\n * them down after the test's scope closes, as it does for its own tests. `it.effect.each` passes the context\n * after the test case, and named and anonymous `it.layer` blocks keep the fixtures.\n *\n * **Gotchas**\n *\n * Vitest reads the destructured names to decide which fixtures to set up. Once any fixture is defined, a test that\n * takes the whole context as a plain parameter, such as `(ctx) =>`, fails with a `FixtureParseError`. Property\n * tests receive only the base test context and cannot request fixtures; auto fixtures still run.\n *\n * **Example** (Using a Vitest fixture in an Effect test)\n *\n * ```ts\n * import { assert, makeMethods, test } from \"@effect/vitest\"\n * import { Effect } from \"effect\"\n *\n * const it = makeMethods(\n * test.extend(\"config\", { scope: \"file\" }, () => ({ port: 3000 }))\n * )\n *\n * it.effect(\"reads the config fixture\", ({ config }) =>\n * Effect.sync(() => {\n * assert.strictEqual(config.port, 3000)\n * }))\n * ```\n *\n * @stability unstable\n * @category constructors\n * @since 4.0.0\n */\nexport const makeMethods = internal.makeMethods;\n/**\n * Creates a named Vitest suite whose callback receives Effect test helpers.\n *\n * @stability unstable\n * @category testing\n * @since 4.0.0\n */\nexport const describeWrapped = internal.describeWrapped;\n//# sourceMappingURL=index.js.map"],"x_google_ignoreList":[0,1],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { a as FileSourceJson, c as fileBytes, i as FileSource, l as fileUrl, n as FileBytesSource, o as FileUrlSource, r as FileMimeType, s as fileBase64, t as FileBase64Source } from "../File-B923KvZ9.mjs";
2
+ export { FileBase64Source, FileBytesSource, FileMimeType, FileSource, FileSourceJson, FileUrlSource, fileBase64, fileBytes, fileUrl };
@@ -0,0 +1,51 @@
1
+ import { Schema } from "effect";
2
+ //#region src/domain/File.ts
3
+ const FileMimeTypeSchema = Schema.String;
4
+ const FileUrlSource = Schema.TaggedStruct("url", {
5
+ url: Schema.String,
6
+ mimeType: Schema.optionalKey(FileMimeTypeSchema)
7
+ });
8
+ const FileBase64Source = Schema.TaggedStruct("base64", {
9
+ base64: Schema.String,
10
+ mimeType: FileMimeTypeSchema
11
+ });
12
+ const FileBytesSource = Schema.TaggedStruct("bytes", {
13
+ bytes: Schema.Uint8Array,
14
+ mimeType: FileMimeTypeSchema
15
+ });
16
+ const FileSource = Schema.Union([
17
+ FileUrlSource,
18
+ FileBase64Source,
19
+ FileBytesSource
20
+ ]);
21
+ /** `FileSource` as JSON: bytes encode as base64 (e.g. tool output on a UI wire). */
22
+ const FileSourceJson = Schema.Union([
23
+ FileUrlSource,
24
+ FileBase64Source,
25
+ Schema.TaggedStruct("bytes", {
26
+ bytes: Schema.Uint8ArrayFromBase64,
27
+ mimeType: FileMimeTypeSchema
28
+ })
29
+ ]);
30
+ const fileUrl = (url, mimeType) => mimeType !== void 0 ? {
31
+ _tag: "url",
32
+ url,
33
+ mimeType
34
+ } : {
35
+ _tag: "url",
36
+ url
37
+ };
38
+ const fileBase64 = (base64, mimeType) => ({
39
+ _tag: "base64",
40
+ base64,
41
+ mimeType
42
+ });
43
+ const fileBytes = (bytes, mimeType) => ({
44
+ _tag: "bytes",
45
+ bytes,
46
+ mimeType
47
+ });
48
+ //#endregion
49
+ export { FileBase64Source, FileBytesSource, FileSource, FileSourceJson, FileUrlSource, fileBase64, fileBytes, fileUrl };
50
+
51
+ //# sourceMappingURL=File.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"File.mjs","names":[],"sources":["../../src/domain/File.ts"],"sourcesContent":["import { Schema } from \"effect\"\nimport type { MediaBase64, MediaBytes, MediaSource, MediaUrl } from \"./Media.js\"\n\n/**\n * MIME types of files a user hands to a model: documents, audio, video. The\n * listed ones are common; the `(string & {})` tail accepts any other, so a\n * newly supported format works without an SDK update. Which types a model\n * reads is the provider's call: an unsupported one is rejected by the\n * provider, not converted here.\n */\nexport type FileMimeType =\n | \"application/pdf\"\n | \"text/plain\"\n | \"text/markdown\"\n | \"text/csv\"\n | \"text/html\"\n | \"application/json\"\n | \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\"\n | \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\"\n | \"audio/mpeg\"\n | \"audio/wav\"\n | \"video/mp4\"\n // eslint-disable-next-line @typescript-eslint/ban-types\n | (string & {})\n\nconst FileMimeTypeSchema: Schema.Codec<FileMimeType> = Schema.String\n\nexport type FileUrlSource = MediaUrl<FileMimeType>\nexport type FileBase64Source = MediaBase64<FileMimeType>\nexport type FileBytesSource = MediaBytes<FileMimeType>\n\n/** Where a file lives: a URL the model fetches, inline base64, or raw bytes. */\nexport type FileSource = MediaSource<FileMimeType>\n\nexport const FileUrlSource = Schema.TaggedStruct(\"url\", {\n url: Schema.String,\n mimeType: Schema.optionalKey(FileMimeTypeSchema),\n})\n\nexport const FileBase64Source = Schema.TaggedStruct(\"base64\", {\n base64: Schema.String,\n mimeType: FileMimeTypeSchema,\n})\n\nexport const FileBytesSource = Schema.TaggedStruct(\"bytes\", {\n bytes: Schema.Uint8Array,\n mimeType: FileMimeTypeSchema,\n})\n\nexport const FileSource: Schema.Codec<FileSource> = Schema.Union([\n FileUrlSource,\n FileBase64Source,\n FileBytesSource,\n])\n\n/** `FileSource` as JSON: bytes encode as base64 (e.g. tool output on a UI wire). */\nexport const FileSourceJson = Schema.Union([\n FileUrlSource,\n FileBase64Source,\n Schema.TaggedStruct(\"bytes\", {\n bytes: Schema.Uint8ArrayFromBase64,\n mimeType: FileMimeTypeSchema,\n }),\n])\n\nexport const fileUrl = (url: string, mimeType?: FileMimeType): FileUrlSource =>\n mimeType !== undefined ? { _tag: \"url\", url, mimeType } : { _tag: \"url\", url }\n\nexport const fileBase64 = (base64: string, mimeType: FileMimeType): FileBase64Source => ({\n _tag: \"base64\",\n base64,\n mimeType,\n})\n\nexport const fileBytes = (bytes: Uint8Array, mimeType: FileMimeType): FileBytesSource => ({\n _tag: \"bytes\",\n bytes,\n mimeType,\n})\n"],"mappings":";;AAyBA,MAAM,qBAAiD,OAAO;AAS9D,MAAa,gBAAgB,OAAO,aAAa,OAAO;CACtD,KAAK,OAAO;CACZ,UAAU,OAAO,YAAY,kBAAkB;AACjD,CAAC;AAED,MAAa,mBAAmB,OAAO,aAAa,UAAU;CAC5D,QAAQ,OAAO;CACf,UAAU;AACZ,CAAC;AAED,MAAa,kBAAkB,OAAO,aAAa,SAAS;CAC1D,OAAO,OAAO;CACd,UAAU;AACZ,CAAC;AAED,MAAa,aAAuC,OAAO,MAAM;CAC/D;CACA;CACA;AACF,CAAC;;AAGD,MAAa,iBAAiB,OAAO,MAAM;CACzC;CACA;CACA,OAAO,aAAa,SAAS;EAC3B,OAAO,OAAO;EACd,UAAU;CACZ,CAAC;AACH,CAAC;AAED,MAAa,WAAW,KAAa,aACnC,aAAa,KAAA,IAAY;CAAE,MAAM;CAAO;CAAK;AAAS,IAAI;CAAE,MAAM;CAAO;AAAI;AAE/E,MAAa,cAAc,QAAgB,cAA8C;CACvF,MAAM;CACN;CACA;AACF;AAEA,MAAa,aAAa,OAAmB,cAA6C;CACxF,MAAM;CACN;CACA;AACF"}
@@ -1,3 +1,3 @@
1
1
  import { n as Dimensions, t as AspectRatio } from "../Media-BbX7BAaO.mjs";
2
- import { a as ImageResolution, d as imageBytes, f as imageUrl, g as pixelsOf, h as isImageUrl, i as ImageMimeType, l as ProviderData, m as isImageBytes, n as ImageBase64Source, o as ImageSource, p as isImageBase64, r as ImageBytesSource, s as ImageUrlSource, t as GeneratedImage, u as imageBase64 } from "../Image-Cv6iBLTy.mjs";
3
- export { type AspectRatio, type Dimensions, GeneratedImage, ImageBase64Source, ImageBytesSource, ImageMimeType, ImageResolution, ImageSource, ImageUrlSource, ProviderData, imageBase64, imageBytes, imageUrl, isImageBase64, isImageBytes, isImageUrl, pixelsOf };
2
+ import { _ as pixelsOf, a as ImageResolution, c as ImageUrlSource, d as imageBase64, f as imageBytes, g as isImageUrl, h as isImageBytes, i as ImageMimeType, m as isImageBase64, n as ImageBase64Source, o as ImageSource, p as imageUrl, r as ImageBytesSource, s as ImageSourceJson, t as GeneratedImage, u as ProviderData } from "../Image-Bzc1H_UK.mjs";
3
+ export { type AspectRatio, type Dimensions, GeneratedImage, ImageBase64Source, ImageBytesSource, ImageMimeType, ImageResolution, ImageSource, ImageSourceJson, ImageUrlSource, ProviderData, imageBase64, imageBytes, imageUrl, isImageBase64, isImageBytes, isImageUrl, pixelsOf };
@@ -6,6 +6,7 @@ var Image_exports = /* @__PURE__ */ __exportAll({
6
6
  ImageBase64Source: () => ImageBase64Source,
7
7
  ImageBytesSource: () => ImageBytesSource,
8
8
  ImageSource: () => ImageSource,
9
+ ImageSourceJson: () => ImageSourceJson,
9
10
  ImageUrlSource: () => ImageUrlSource,
10
11
  imageBase64: () => imageBase64,
11
12
  imageBytes: () => imageBytes,
@@ -18,7 +19,7 @@ var Image_exports = /* @__PURE__ */ __exportAll({
18
19
  const ImageMimeTypeSchema = Schema.String;
19
20
  const ImageUrlSource = Schema.TaggedStruct("url", {
20
21
  url: Schema.String,
21
- mimeType: Schema.optional(ImageMimeTypeSchema)
22
+ mimeType: Schema.optionalKey(ImageMimeTypeSchema)
22
23
  });
23
24
  const ImageBase64Source = Schema.TaggedStruct("base64", {
24
25
  base64: Schema.String,
@@ -33,6 +34,15 @@ const ImageSource = Schema.Union([
33
34
  ImageBase64Source,
34
35
  ImageBytesSource
35
36
  ]);
37
+ /** `ImageSource` as JSON: bytes encode as base64 (e.g. tool output on a UI wire). */
38
+ const ImageSourceJson = Schema.Union([
39
+ ImageUrlSource,
40
+ ImageBase64Source,
41
+ Schema.TaggedStruct("bytes", {
42
+ bytes: Schema.Uint8ArrayFromBase64,
43
+ mimeType: ImageMimeTypeSchema
44
+ })
45
+ ]);
36
46
  const imageUrl = (url, mimeType) => mimeType !== void 0 ? {
37
47
  _tag: "url",
38
48
  url,
@@ -79,6 +89,6 @@ const isImageUrl = Schema.is(ImageUrlSource);
79
89
  const isImageBase64 = Schema.is(ImageBase64Source);
80
90
  const isImageBytes = Schema.is(ImageBytesSource);
81
91
  //#endregion
82
- export { ImageBase64Source, ImageBytesSource, ImageSource, ImageUrlSource, imageBase64, imageBytes, imageUrl, isImageBase64, isImageBytes, isImageUrl, pixelsOf, Image_exports as t };
92
+ export { ImageBase64Source, ImageBytesSource, ImageSource, ImageSourceJson, ImageUrlSource, imageBase64, imageBytes, imageUrl, isImageBase64, isImageBytes, isImageUrl, pixelsOf, Image_exports as t };
83
93
 
84
94
  //# sourceMappingURL=Image.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Image.mjs","names":[],"sources":["../../src/domain/Image.ts"],"sourcesContent":["import { Result, Schema } from \"effect\"\nimport type {\n AspectRatio,\n Dimensions,\n MediaBase64,\n MediaBytes,\n MediaSource,\n MediaUrl,\n Watermark,\n} from \"./Media.js\"\nimport { parseAspectRatio, round16 } from \"./Media.js\"\n\n/**\n * Image MIME types AI providers typically accept. The first four are the\n * universal subset (Cohere v4, Voyage multimodal, Jina v4, Google\n * `gemini-embedding-2`); HEIC / HEIF are Google-specific. The\n * `(string & {})` tail keeps autocomplete on the literals while still\n * accepting any string, so a newly-supported format works without an\n * SDK update.\n */\nexport type ImageMimeType =\n | \"image/png\"\n | \"image/jpeg\"\n | \"image/webp\"\n | \"image/gif\"\n | \"image/heic\"\n | \"image/heif\"\n // eslint-disable-next-line @typescript-eslint/ban-types\n | (string & {})\n\nconst ImageMimeTypeSchema = Schema.String as unknown as Schema.Schema<ImageMimeType>\n\nexport type ImageUrlSource = MediaUrl<ImageMimeType>\nexport type ImageBase64Source = MediaBase64<ImageMimeType>\nexport type ImageBytesSource = MediaBytes<ImageMimeType>\n\n/**\n * Where an image lives. Provider layers normalize across these:\n * `bytes` becomes a base64 data URI for OpenAI / Anthropic, an\n * `inlineData` part for Gemini, and a separate field for Cohere /\n * Voyage. URL constraints (must be HTTPS, must be public, …) are\n * provider-specific and validated at the layer, not in the type.\n */\nexport type ImageSource = MediaSource<ImageMimeType>\n\nexport const ImageUrlSource = Schema.TaggedStruct(\"url\", {\n url: Schema.String,\n mimeType: Schema.optional(ImageMimeTypeSchema),\n})\n\nexport const ImageBase64Source = Schema.TaggedStruct(\"base64\", {\n base64: Schema.String,\n mimeType: ImageMimeTypeSchema,\n})\n\nexport const ImageBytesSource = Schema.TaggedStruct(\"bytes\", {\n bytes: Schema.Uint8Array,\n mimeType: ImageMimeTypeSchema,\n})\n\nexport const ImageSource: Schema.Schema<ImageSource> = Schema.Union([\n ImageUrlSource,\n ImageBase64Source,\n ImageBytesSource,\n]) as unknown as Schema.Schema<ImageSource>\n\nexport const imageUrl = (url: string, mimeType?: ImageMimeType): ImageUrlSource =>\n mimeType !== undefined ? { _tag: \"url\", url, mimeType } : { _tag: \"url\", url }\n\nexport const imageBase64 = (base64: string, mimeType: ImageMimeType): ImageBase64Source => ({\n _tag: \"base64\",\n base64,\n mimeType,\n})\n\nexport const imageBytes = (bytes: Uint8Array, mimeType: ImageMimeType): ImageBytesSource => ({\n _tag: \"bytes\",\n bytes,\n mimeType,\n})\n\n/** Cross-modality; lives in `Media.ts` because video generation shares it. */\nexport type { AspectRatio, Dimensions } from \"./Media.js\"\n\n/**\n * Resolution tier, roughly the short edge in pixels. A tier rather than\n * a pixel pair: adapters whose wire takes exact dimensions derive them\n * from the tier and the aspect ratio. Image-typed on purpose, video\n * models tier by scan height instead.\n */\nexport type ImageResolution = \"1K\" | \"2K\" | \"4K\"\n\nconst SHORT_EDGE: Record<ImageResolution, number> = { \"1K\": 1024, \"2K\": 2048, \"4K\": 4096 }\n\n/**\n * Turn the portable ratio and tier into pixels: the tier is the short\n * edge, the long edge follows the ratio. `undefined` when neither was\n * asked for, which the caller sends as \"no size\" so the endpoint picks.\n *\n * Adapters whose wire wants `\"WxH\"` format the pair; those wanting an\n * object send it as is. Whether the result is in range for a given model\n * is the server's call: per-model limits churn and we do not table them.\n */\nexport const pixelsOf = (request: {\n readonly aspectRatio?: AspectRatio\n readonly resolution?: ImageResolution\n}): Result.Result<Dimensions | undefined, string> =>\n request.aspectRatio === undefined && request.resolution === undefined\n ? Result.succeed(undefined)\n : Result.map(parseAspectRatio(request.aspectRatio ?? \"1:1\"), ([w, h]) => {\n const short = SHORT_EDGE[request.resolution ?? \"1K\"]\n return w >= h\n ? { width: round16((short * w) / h), height: short }\n : { width: short, height: round16((short * h) / w) }\n })\n\n/**\n * Per-image extras a provider reported and this type has no field for:\n * pixel dimensions, a file name, a revised prompt. Opaque here, and a\n * shared slot, so a provider keys its data under its own name\n * (`{ fal: … }`, `{ openai: … }`) and reads only that key. Each provider\n * package ships a typed reader; the framework never interprets it.\n *\n * Not promoted to real fields because the providers disagree on what\n * they report. Only some fal endpoints return dimensions, and neither\n * OpenAI's Images API nor Gemini returns them at all.\n */\nexport type ProviderData = unknown\n\n/** One image off a generation call, plus what the provider stamped into it. */\nexport type GeneratedImage = {\n readonly image: ImageSource\n /** Set only when the provider applies one. */\n readonly watermark?: Watermark\n /** {@link ProviderData}: per-image extras, keyed by provider name. */\n readonly providerData?: ProviderData\n}\n\nexport const isImageUrl = Schema.is(ImageUrlSource)\nexport const isImageBase64 = Schema.is(ImageBase64Source)\nexport const isImageBytes = Schema.is(ImageBytesSource)\n"],"mappings":";;;;;;;;;;;;;;;;;AA8BA,MAAM,sBAAsB,OAAO;AAenC,MAAa,iBAAiB,OAAO,aAAa,OAAO;CACvD,KAAK,OAAO;CACZ,UAAU,OAAO,SAAS,mBAAmB;AAC/C,CAAC;AAED,MAAa,oBAAoB,OAAO,aAAa,UAAU;CAC7D,QAAQ,OAAO;CACf,UAAU;AACZ,CAAC;AAED,MAAa,mBAAmB,OAAO,aAAa,SAAS;CAC3D,OAAO,OAAO;CACd,UAAU;AACZ,CAAC;AAED,MAAa,cAA0C,OAAO,MAAM;CAClE;CACA;CACA;AACF,CAAC;AAED,MAAa,YAAY,KAAa,aACpC,aAAa,KAAA,IAAY;CAAE,MAAM;CAAO;CAAK;AAAS,IAAI;CAAE,MAAM;CAAO;AAAI;AAE/E,MAAa,eAAe,QAAgB,cAAgD;CAC1F,MAAM;CACN;CACA;AACF;AAEA,MAAa,cAAc,OAAmB,cAA+C;CAC3F,MAAM;CACN;CACA;AACF;AAaA,MAAM,aAA8C;CAAE,MAAM;CAAM,MAAM;CAAM,MAAM;AAAK;;;;;;;;;;AAWzF,MAAa,YAAY,YAIvB,QAAQ,gBAAgB,KAAA,KAAa,QAAQ,eAAe,KAAA,IACxD,OAAO,QAAQ,KAAA,CAAS,IACxB,OAAO,IAAI,iBAAiB,QAAQ,eAAe,KAAK,IAAI,CAAC,GAAG,OAAO;CACrE,MAAM,QAAQ,WAAW,QAAQ,cAAc;CAC/C,OAAO,KAAK,IACR;EAAE,OAAO,QAAS,QAAQ,IAAK,CAAC;EAAG,QAAQ;CAAM,IACjD;EAAE,OAAO;EAAO,QAAQ,QAAS,QAAQ,IAAK,CAAC;CAAE;AACvD,CAAC;AAwBP,MAAa,aAAa,OAAO,GAAG,cAAc;AAClD,MAAa,gBAAgB,OAAO,GAAG,iBAAiB;AACxD,MAAa,eAAe,OAAO,GAAG,gBAAgB"}
1
+ {"version":3,"file":"Image.mjs","names":[],"sources":["../../src/domain/Image.ts"],"sourcesContent":["import { Result, Schema } from \"effect\"\nimport type {\n AspectRatio,\n Dimensions,\n MediaBase64,\n MediaBytes,\n MediaSource,\n MediaUrl,\n Watermark,\n} from \"./Media.js\"\nimport { parseAspectRatio, round16 } from \"./Media.js\"\n\n/**\n * Image MIME types AI providers typically accept. The first four are the\n * universal subset (Cohere v4, Voyage multimodal, Jina v4, Google\n * `gemini-embedding-2`); HEIC / HEIF are Google-specific. The\n * `(string & {})` tail keeps autocomplete on the literals while still\n * accepting any string, so a newly-supported format works without an\n * SDK update.\n */\nexport type ImageMimeType =\n | \"image/png\"\n | \"image/jpeg\"\n | \"image/webp\"\n | \"image/gif\"\n | \"image/heic\"\n | \"image/heif\"\n // eslint-disable-next-line @typescript-eslint/ban-types\n | (string & {})\n\nconst ImageMimeTypeSchema: Schema.Codec<ImageMimeType> = Schema.String\n\nexport type ImageUrlSource = MediaUrl<ImageMimeType>\nexport type ImageBase64Source = MediaBase64<ImageMimeType>\nexport type ImageBytesSource = MediaBytes<ImageMimeType>\n\n/**\n * Where an image lives. Provider layers normalize across these:\n * `bytes` becomes a base64 data URI for OpenAI / Anthropic, an\n * `inlineData` part for Gemini, and a separate field for Cohere /\n * Voyage. URL constraints (must be HTTPS, must be public, …) are\n * provider-specific and validated at the layer, not in the type.\n */\nexport type ImageSource = MediaSource<ImageMimeType>\n\nexport const ImageUrlSource = Schema.TaggedStruct(\"url\", {\n url: Schema.String,\n mimeType: Schema.optionalKey(ImageMimeTypeSchema),\n})\n\nexport const ImageBase64Source = Schema.TaggedStruct(\"base64\", {\n base64: Schema.String,\n mimeType: ImageMimeTypeSchema,\n})\n\nexport const ImageBytesSource = Schema.TaggedStruct(\"bytes\", {\n bytes: Schema.Uint8Array,\n mimeType: ImageMimeTypeSchema,\n})\n\nexport const ImageSource: Schema.Codec<ImageSource> = Schema.Union([\n ImageUrlSource,\n ImageBase64Source,\n ImageBytesSource,\n])\n\n/** `ImageSource` as JSON: bytes encode as base64 (e.g. tool output on a UI wire). */\nexport const ImageSourceJson = Schema.Union([\n ImageUrlSource,\n ImageBase64Source,\n Schema.TaggedStruct(\"bytes\", {\n bytes: Schema.Uint8ArrayFromBase64,\n mimeType: ImageMimeTypeSchema,\n }),\n])\n\nexport const imageUrl = (url: string, mimeType?: ImageMimeType): ImageUrlSource =>\n mimeType !== undefined ? { _tag: \"url\", url, mimeType } : { _tag: \"url\", url }\n\nexport const imageBase64 = (base64: string, mimeType: ImageMimeType): ImageBase64Source => ({\n _tag: \"base64\",\n base64,\n mimeType,\n})\n\nexport const imageBytes = (bytes: Uint8Array, mimeType: ImageMimeType): ImageBytesSource => ({\n _tag: \"bytes\",\n bytes,\n mimeType,\n})\n\n/** Cross-modality; lives in `Media.ts` because video generation shares it. */\nexport type { AspectRatio, Dimensions } from \"./Media.js\"\n\n/**\n * Resolution tier, roughly the short edge in pixels. A tier rather than\n * a pixel pair: adapters whose wire takes exact dimensions derive them\n * from the tier and the aspect ratio. Image-typed on purpose, video\n * models tier by scan height instead.\n */\nexport type ImageResolution = \"1K\" | \"2K\" | \"4K\"\n\nconst SHORT_EDGE: Record<ImageResolution, number> = { \"1K\": 1024, \"2K\": 2048, \"4K\": 4096 }\n\n/**\n * Turn the portable ratio and tier into pixels: the tier is the short\n * edge, the long edge follows the ratio. `undefined` when neither was\n * asked for, which the caller sends as \"no size\" so the endpoint picks.\n *\n * Adapters whose wire wants `\"WxH\"` format the pair; those wanting an\n * object send it as is. Whether the result is in range for a given model\n * is the server's call: per-model limits churn and we do not table them.\n */\nexport const pixelsOf = (request: {\n readonly aspectRatio?: AspectRatio\n readonly resolution?: ImageResolution\n}): Result.Result<Dimensions | undefined, string> =>\n request.aspectRatio === undefined && request.resolution === undefined\n ? Result.succeed(undefined)\n : Result.map(parseAspectRatio(request.aspectRatio ?? \"1:1\"), ([w, h]) => {\n const short = SHORT_EDGE[request.resolution ?? \"1K\"]\n return w >= h\n ? { width: round16((short * w) / h), height: short }\n : { width: short, height: round16((short * h) / w) }\n })\n\n/**\n * Per-image extras a provider reported and this type has no field for:\n * pixel dimensions, a file name, a revised prompt. Opaque here, and a\n * shared slot, so a provider keys its data under its own name\n * (`{ fal: … }`, `{ openai: … }`) and reads only that key. Each provider\n * package ships a typed reader; the framework never interprets it.\n *\n * Not promoted to real fields because the providers disagree on what\n * they report. Only some fal endpoints return dimensions, and neither\n * OpenAI's Images API nor Gemini returns them at all.\n */\nexport type ProviderData = unknown\n\n/** One image off a generation call, plus what the provider stamped into it. */\nexport type GeneratedImage = {\n readonly image: ImageSource\n /** Set only when the provider applies one. */\n readonly watermark?: Watermark\n /** {@link ProviderData}: per-image extras, keyed by provider name. */\n readonly providerData?: ProviderData\n}\n\nexport const isImageUrl = Schema.is(ImageUrlSource)\nexport const isImageBase64 = Schema.is(ImageBase64Source)\nexport const isImageBytes = Schema.is(ImageBytesSource)\n"],"mappings":";;;;;;;;;;;;;;;;;;AA8BA,MAAM,sBAAmD,OAAO;AAehE,MAAa,iBAAiB,OAAO,aAAa,OAAO;CACvD,KAAK,OAAO;CACZ,UAAU,OAAO,YAAY,mBAAmB;AAClD,CAAC;AAED,MAAa,oBAAoB,OAAO,aAAa,UAAU;CAC7D,QAAQ,OAAO;CACf,UAAU;AACZ,CAAC;AAED,MAAa,mBAAmB,OAAO,aAAa,SAAS;CAC3D,OAAO,OAAO;CACd,UAAU;AACZ,CAAC;AAED,MAAa,cAAyC,OAAO,MAAM;CACjE;CACA;CACA;AACF,CAAC;;AAGD,MAAa,kBAAkB,OAAO,MAAM;CAC1C;CACA;CACA,OAAO,aAAa,SAAS;EAC3B,OAAO,OAAO;EACd,UAAU;CACZ,CAAC;AACH,CAAC;AAED,MAAa,YAAY,KAAa,aACpC,aAAa,KAAA,IAAY;CAAE,MAAM;CAAO;CAAK;AAAS,IAAI;CAAE,MAAM;CAAO;AAAI;AAE/E,MAAa,eAAe,QAAgB,cAAgD;CAC1F,MAAM;CACN;CACA;AACF;AAEA,MAAa,cAAc,OAAmB,cAA+C;CAC3F,MAAM;CACN;CACA;AACF;AAaA,MAAM,aAA8C;CAAE,MAAM;CAAM,MAAM;CAAM,MAAM;AAAK;;;;;;;;;;AAWzF,MAAa,YAAY,YAIvB,QAAQ,gBAAgB,KAAA,KAAa,QAAQ,eAAe,KAAA,IACxD,OAAO,QAAQ,KAAA,CAAS,IACxB,OAAO,IAAI,iBAAiB,QAAQ,eAAe,KAAK,IAAI,CAAC,GAAG,OAAO;CACrE,MAAM,QAAQ,WAAW,QAAQ,cAAc;CAC/C,OAAO,KAAK,IACR;EAAE,OAAO,QAAS,QAAQ,IAAK,CAAC;EAAG,QAAQ;CAAM,IACjD;EAAE,OAAO;EAAO,QAAQ,QAAS,QAAQ,IAAK,CAAC;CAAE;AACvD,CAAC;AAwBP,MAAa,aAAa,OAAO,GAAG,cAAc;AAClD,MAAa,gBAAgB,OAAO,GAAG,iBAAiB;AACxD,MAAa,eAAe,OAAO,GAAG,gBAAgB"}