@effect-uai/core 0.13.0 → 0.14.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 (82) hide show
  1. package/dist/{Audio-60lKKHxS.d.mts → Audio-_nGR4V0X.d.mts} +2 -2
  2. package/dist/{Audio-60lKKHxS.d.mts.map → Audio-_nGR4V0X.d.mts.map} +1 -1
  3. package/dist/Image-Cv6iBLTy.d.mts +99 -0
  4. package/dist/Image-Cv6iBLTy.d.mts.map +1 -0
  5. package/dist/{Items-SfUabNuB.d.mts → Items-C7MyrYPX.d.mts} +35 -4
  6. package/dist/Items-C7MyrYPX.d.mts.map +1 -0
  7. package/dist/Media-BbX7BAaO.d.mts +60 -0
  8. package/dist/Media-BbX7BAaO.d.mts.map +1 -0
  9. package/dist/{Tool-DE-rnvkw.d.mts → Tool-BF78QWtn.d.mts} +2 -2
  10. package/dist/{Tool-DE-rnvkw.d.mts.map → Tool-BF78QWtn.d.mts.map} +1 -1
  11. package/dist/{ToolEvent-D99MGQYH.d.mts → ToolEvent-Di4a723B.d.mts} +2 -2
  12. package/dist/{ToolEvent-D99MGQYH.d.mts.map → ToolEvent-Di4a723B.d.mts.map} +1 -1
  13. package/dist/{ToolResult-Cj8ChodL.d.mts → ToolResult-BsYQRjmW.d.mts} +2 -2
  14. package/dist/{ToolResult-Cj8ChodL.d.mts.map → ToolResult-BsYQRjmW.d.mts.map} +1 -1
  15. package/dist/{Toolkit-BEZrNPTI.d.mts → Toolkit-DAjJ9Tvl.d.mts} +5 -5
  16. package/dist/{Toolkit-BEZrNPTI.d.mts.map → Toolkit-DAjJ9Tvl.d.mts.map} +1 -1
  17. package/dist/browser/BrowserTool.d.mts +1 -1
  18. package/dist/capabilities/Capabilities.d.mts +26 -2
  19. package/dist/capabilities/Capabilities.d.mts.map +1 -1
  20. package/dist/capabilities/Capabilities.mjs +32 -1
  21. package/dist/capabilities/Capabilities.mjs.map +1 -1
  22. package/dist/domain/Audio.d.mts +1 -1
  23. package/dist/domain/Image.d.mts +3 -2
  24. package/dist/domain/Image.mjs +29 -3
  25. package/dist/domain/Image.mjs.map +1 -1
  26. package/dist/domain/Items.d.mts +2 -2
  27. package/dist/domain/Items.mjs +19 -1
  28. package/dist/domain/Items.mjs.map +1 -1
  29. package/dist/domain/Media.d.mts +2 -2
  30. package/dist/domain/Media.mjs +51 -2
  31. package/dist/domain/Media.mjs.map +1 -1
  32. package/dist/domain/Music.d.mts +3 -8
  33. package/dist/domain/Music.d.mts.map +1 -1
  34. package/dist/domain/Music.mjs.map +1 -1
  35. package/dist/domain/Research.d.mts +1 -1
  36. package/dist/domain/Turn.d.mts +73 -9
  37. package/dist/domain/Turn.d.mts.map +1 -1
  38. package/dist/domain/Turn.mjs +38 -2
  39. package/dist/domain/Turn.mjs.map +1 -1
  40. package/dist/embedding-model/Embedding.d.mts +1 -1
  41. package/dist/image-generator/ImageGenerator.d.mts +188 -0
  42. package/dist/image-generator/ImageGenerator.d.mts.map +1 -0
  43. package/dist/image-generator/ImageGenerator.mjs +50 -0
  44. package/dist/image-generator/ImageGenerator.mjs.map +1 -0
  45. package/dist/index.d.mts +11 -9
  46. package/dist/index.mjs +4 -2
  47. package/dist/language-model/LanguageModel.d.mts +2 -2
  48. package/dist/music-generator/MusicGenerator.d.mts +3 -2
  49. package/dist/music-generator/MusicGenerator.d.mts.map +1 -1
  50. package/dist/observability/Metrics.d.mts +1 -1
  51. package/dist/speech-synthesizer/SpeechSynthesizer.d.mts +1 -1
  52. package/dist/streaming/Multipart.d.mts +21 -0
  53. package/dist/streaming/Multipart.d.mts.map +1 -0
  54. package/dist/streaming/Multipart.mjs +26 -0
  55. package/dist/streaming/Multipart.mjs.map +1 -0
  56. package/dist/testing/MockMusicGenerator.d.mts +1 -1
  57. package/dist/testing/MockProvider.d.mts +1 -1
  58. package/dist/testing/MockSpeechSynthesizer.d.mts +1 -1
  59. package/dist/tool/Approval.d.mts +3 -3
  60. package/dist/tool/HistoryCheck.d.mts +2 -2
  61. package/dist/tool/Tool.d.mts +1 -1
  62. package/dist/tool/ToolEvent.d.mts +1 -1
  63. package/dist/tool/ToolResult.d.mts +1 -1
  64. package/dist/tool/Toolkit.d.mts +1 -1
  65. package/dist/transcriber/Transcriber.d.mts +1 -1
  66. package/dist/web-read/WebReadTool.d.mts +1 -1
  67. package/dist/web-search/WebSearchTool.d.mts +1 -1
  68. package/package.json +9 -1
  69. package/src/capabilities/Capabilities.ts +38 -0
  70. package/src/domain/Image.ts +68 -2
  71. package/src/domain/Items.ts +18 -1
  72. package/src/domain/Media.ts +66 -0
  73. package/src/domain/Music.ts +4 -3
  74. package/src/domain/Turn.ts +56 -0
  75. package/src/image-generator/ImageGenerator.ts +165 -0
  76. package/src/index.ts +2 -0
  77. package/src/streaming/Multipart.ts +29 -0
  78. package/dist/Image-BK8-4H6s.d.mts +0 -59
  79. package/dist/Image-BK8-4H6s.d.mts.map +0 -1
  80. package/dist/Items-SfUabNuB.d.mts.map +0 -1
  81. package/dist/Media-DwgpifPD.d.mts +0 -57
  82. package/dist/Media-DwgpifPD.d.mts.map +0 -1
@@ -1,2 +1,2 @@
1
- import { A as isReasoning, C as isContainerFileCitation, D as isInputText, E as isInputImage, F as systemText, I as toolCallOutput, L as userText, M as isToolCall, N as isToolCallOutput, O as isMessage, P as isUrlCitation, S as assistantText, T as isFilePath, _ as StopReason, a as FilePath, b as UrlCitation, c as InputText, d as Message, f as OutputText, g as Role, h as Refusal, i as FileCitation, j as isRefusal, k as isOutputText, l as InputTokensDetails, m as Reasoning, n as ContainerFileCitation, o as HistoryItem, p as OutputTokensDetails, r as ContentBlock, s as InputImage, t as Annotation, v as ToolCall, w as isFileCitation, x as Usage, y as ToolCallOutput } from "../Items-SfUabNuB.mjs";
2
- export { Annotation, ContainerFileCitation, ContentBlock, FileCitation, FilePath, HistoryItem, InputImage, InputText, InputTokensDetails, Message, OutputText, OutputTokensDetails, Reasoning, Refusal, Role, StopReason, ToolCall, ToolCallOutput, UrlCitation, Usage, assistantText, isContainerFileCitation, isFileCitation, isFilePath, isInputImage, isInputText, isMessage, isOutputText, isReasoning, isRefusal, isToolCall, isToolCallOutput, isUrlCitation, systemText, toolCallOutput, userText };
1
+ import { A as isOutputImage, C as assistantText, D as isInputImage, E as isFilePath, F as isToolCallOutput, I as isUrlCitation, L as systemText, M as isReasoning, N as isRefusal, O as isInputText, P as isToolCall, R as toolCallOutput, S as Usage, T as isFileCitation, _ as Role, a as FilePath, b as ToolCallOutput, c as InputText, d as Message, f as OutputImage, g as Refusal, h as Reasoning, i as FileCitation, j as isOutputText, k as isMessage, l as InputTokensDetails, m as OutputTokensDetails, n as ContainerFileCitation, o as HistoryItem, p as OutputText, r as ContentBlock, s as InputImage, t as Annotation, v as StopReason, w as isContainerFileCitation, x as UrlCitation, y as ToolCall, z as userText } from "../Items-C7MyrYPX.mjs";
2
+ export { Annotation, ContainerFileCitation, ContentBlock, FileCitation, FilePath, HistoryItem, InputImage, InputText, InputTokensDetails, Message, OutputImage, OutputText, OutputTokensDetails, Reasoning, Refusal, Role, StopReason, ToolCall, ToolCallOutput, UrlCitation, Usage, assistantText, isContainerFileCitation, isFileCitation, isFilePath, isInputImage, isInputText, isMessage, isOutputImage, isOutputText, isReasoning, isRefusal, isToolCall, isToolCallOutput, isUrlCitation, systemText, toolCallOutput, userText };
@@ -13,6 +13,7 @@ var Items_exports = /* @__PURE__ */ __exportAll({
13
13
  InputText: () => InputText,
14
14
  InputTokensDetails: () => InputTokensDetails,
15
15
  Message: () => Message,
16
+ OutputImage: () => OutputImage,
16
17
  OutputText: () => OutputText,
17
18
  OutputTokensDetails: () => OutputTokensDetails,
18
19
  Reasoning: () => Reasoning,
@@ -30,6 +31,7 @@ var Items_exports = /* @__PURE__ */ __exportAll({
30
31
  isInputImage: () => isInputImage,
31
32
  isInputText: () => isInputText,
32
33
  isMessage: () => isMessage,
34
+ isOutputImage: () => isOutputImage,
33
35
  isOutputText: () => isOutputText,
34
36
  isReasoning: () => isReasoning,
35
37
  isRefusal: () => isRefusal,
@@ -106,6 +108,20 @@ const OutputText = Schema.Struct({
106
108
  annotations: Schema.optional(Schema.Array(Annotation))
107
109
  });
108
110
  /**
111
+ * Model-emitted image. The counterpart to {@link InputImage}: same
112
+ * `ImageSource`, so an image the model drew goes straight back into the
113
+ * next turn with no conversion.
114
+ *
115
+ * How the pixels were produced is not modelled here. A provider may draw
116
+ * them itself, as an image part of the turn, or reach a hosted tool that
117
+ * draws them; either way the fact is the same, and enabling it is
118
+ * provider-specific.
119
+ */
120
+ const OutputImage = Schema.Struct({
121
+ type: Schema.Literal("output_image"),
122
+ source: ImageSource
123
+ });
124
+ /**
109
125
  * Model-emitted refusal. Distinct from `output_text`: the model declined
110
126
  * to answer rather than producing normal output. Pair with
111
127
  * `stop_reason: "refusal"` on the surrounding `Turn`. Streamed via the
@@ -119,6 +135,7 @@ const ContentBlock = Schema.Union([
119
135
  InputText,
120
136
  InputImage,
121
137
  OutputText,
138
+ OutputImage,
122
139
  Refusal
123
140
  ]);
124
141
  const Role = Schema.Literals([
@@ -168,6 +185,7 @@ const HistoryItem = Schema.Union([
168
185
  const isInputText = Schema.is(InputText);
169
186
  const isInputImage = Schema.is(InputImage);
170
187
  const isOutputText = Schema.is(OutputText);
188
+ const isOutputImage = Schema.is(OutputImage);
171
189
  const isRefusal = Schema.is(Refusal);
172
190
  const isMessage = Schema.is(Message);
173
191
  const isToolCall = Schema.is(ToolCall);
@@ -234,6 +252,6 @@ const toolCallOutput = (call_id, output) => ({
234
252
  output
235
253
  });
236
254
  //#endregion
237
- export { Annotation, ContainerFileCitation, ContentBlock, FileCitation, FilePath, HistoryItem, InputImage, InputText, InputTokensDetails, Message, OutputText, OutputTokensDetails, Reasoning, Refusal, Role, StopReason, ToolCall, ToolCallOutput, UrlCitation, Usage, assistantText, isContainerFileCitation, isFileCitation, isFilePath, isInputImage, isInputText, isMessage, isOutputText, isReasoning, isRefusal, isToolCall, isToolCallOutput, isUrlCitation, systemText, Items_exports as t, toolCallOutput, userText };
255
+ export { Annotation, ContainerFileCitation, ContentBlock, FileCitation, FilePath, HistoryItem, InputImage, InputText, InputTokensDetails, Message, OutputImage, OutputText, OutputTokensDetails, Reasoning, Refusal, Role, StopReason, ToolCall, ToolCallOutput, UrlCitation, Usage, assistantText, isContainerFileCitation, isFileCitation, isFilePath, isInputImage, isInputText, isMessage, isOutputImage, isOutputText, isReasoning, isRefusal, isToolCall, isToolCallOutput, isUrlCitation, systemText, Items_exports as t, toolCallOutput, userText };
238
256
 
239
257
  //# sourceMappingURL=Items.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Items.mjs","names":[],"sources":["../../src/domain/Items.ts"],"sourcesContent":["import { Schema } from \"effect\"\nimport { ImageSource } from \"./Image.js\"\n\n// ---------------------------------------------------------------------------\n// Content blocks (inside Message.content)\n// ---------------------------------------------------------------------------\n\nexport const InputText = Schema.Struct({\n type: Schema.Literal(\"input_text\"),\n text: Schema.String,\n})\nexport type InputText = typeof InputText.Type\n\n/**\n * User-provided image content block. Pair with `InputText` inside a\n * `Message.content` array to ask \"what's in this image?\" style questions.\n *\n * `source` is the cross-modality `ImageSource` from `domain/Image.ts` -\n * url, base64, or raw bytes. Provider codecs encode bytes to whatever\n * wire format the provider wants.\n */\nexport const InputImage = Schema.Struct({\n type: Schema.Literal(\"input_image\"),\n source: ImageSource,\n})\nexport type InputImage = typeof InputImage.Type\n\n// ---------------------------------------------------------------------------\n// Annotations - source / citation pointers attached to `output_text` blocks.\n// Provider-agnostic: each provider populates the fields it has (character\n// span, quote, or positional marker) and omits the rest.\n// ---------------------------------------------------------------------------\n\n/**\n * A cited source. `url` + `title` are the only near-universal fields; the\n * link from a source to the answer text varies by provider, so it is optional\n * and expressed three ways: `start_index`/`end_index` (a character span into\n * the answer), `cited_text` (an exact quote of the source, when no offsets are\n * given), or `marker` (a positional `[n]` reference into an ordered list). A\n * provider populates whichever it has; a bare source list sets none.\n */\nexport const UrlCitation = Schema.Struct({\n type: Schema.Literal(\"url_citation\"),\n url: Schema.String,\n title: Schema.String,\n start_index: Schema.optional(Schema.Number),\n end_index: Schema.optional(Schema.Number),\n cited_text: Schema.optional(Schema.String),\n marker: Schema.optional(Schema.Number),\n})\nexport type UrlCitation = typeof UrlCitation.Type\n\nexport const FileCitation = Schema.Struct({\n type: Schema.Literal(\"file_citation\"),\n file_id: Schema.String,\n index: Schema.Number,\n})\nexport type FileCitation = typeof FileCitation.Type\n\nexport const ContainerFileCitation = Schema.Struct({\n type: Schema.Literal(\"container_file_citation\"),\n container_id: Schema.String,\n file_id: Schema.String,\n start_index: Schema.Number,\n end_index: Schema.Number,\n})\nexport type ContainerFileCitation = typeof ContainerFileCitation.Type\n\nexport const FilePath = Schema.Struct({\n type: Schema.Literal(\"file_path\"),\n file_id: Schema.String,\n index: Schema.Number,\n})\nexport type FilePath = typeof FilePath.Type\n\nexport const Annotation = Schema.Union([UrlCitation, FileCitation, ContainerFileCitation, FilePath])\nexport type Annotation = typeof Annotation.Type\n\nexport const isUrlCitation = Schema.is(UrlCitation)\nexport const isFileCitation = Schema.is(FileCitation)\nexport const isContainerFileCitation = Schema.is(ContainerFileCitation)\nexport const isFilePath = Schema.is(FilePath)\n\nexport const OutputText = Schema.Struct({\n type: Schema.Literal(\"output_text\"),\n text: Schema.String,\n annotations: Schema.optional(Schema.Array(Annotation)),\n})\nexport type OutputText = typeof OutputText.Type\n\n/**\n * Model-emitted refusal. Distinct from `output_text`: the model declined\n * to answer rather than producing normal output. Pair with\n * `stop_reason: \"refusal\"` on the surrounding `Turn`. Streamed via the\n * `RefusalDelta` `TurnEvent`.\n */\nexport const Refusal = Schema.Struct({\n type: Schema.Literal(\"refusal\"),\n text: Schema.String,\n})\nexport type Refusal = typeof Refusal.Type\n\nexport const ContentBlock = Schema.Union([InputText, InputImage, OutputText, Refusal])\nexport type ContentBlock = typeof ContentBlock.Type\n\nexport const Role = Schema.Literals([\"user\", \"assistant\", \"system\"])\nexport type Role = typeof Role.Type\n\n// ---------------------------------------------------------------------------\n// Provider passthrough - every Item type carries this opaque slot.\n// The framework never reads or interprets it; provider modules decode\n// their own data via their own typed readers (see e.g.\n// the `@effect-uai/responses` package).\n//\n// The slot is shared, so a provider keys its data under its own name\n// (`{ responses: ... }`, `{ gemini: ... }`) and reads only that key. One item\n// can pass through several providers - falling back from one to another\n// leaves both keys on it - and a provider that finds no key of its own must\n// encode the item normally rather than assume the slot is its own.\n// ---------------------------------------------------------------------------\n\nconst ProviderData = Schema.optional(Schema.Unknown)\n\n// ---------------------------------------------------------------------------\n// Items\n// ---------------------------------------------------------------------------\n\nexport const Message = Schema.Struct({\n type: Schema.Literal(\"message\"),\n role: Role,\n content: Schema.Array(ContentBlock),\n providerData: ProviderData,\n})\nexport type Message = typeof Message.Type\n\nexport const ToolCall = Schema.Struct({\n type: Schema.Literal(\"function_call\"),\n call_id: Schema.String,\n name: Schema.String,\n // JSON-encoded arguments string, mirroring OpenAI Responses API\n arguments: Schema.String,\n providerData: ProviderData,\n})\nexport type ToolCall = typeof ToolCall.Type\n\nexport const ToolCallOutput = Schema.Struct({\n type: Schema.Literal(\"function_call_output\"),\n call_id: Schema.String,\n output: Schema.String,\n providerData: ProviderData,\n})\nexport type ToolCallOutput = typeof ToolCallOutput.Type\n\n/**\n * Reasoning item - top-level, mirrors OpenAI Responses API. Common shape\n * across providers covers `summary` (human-readable text) and `signature`\n * (opaque round-trip blob - Anthropic's signed thinking, OpenAI's\n * encrypted_content, etc.). Provider-specific fields go in `providerData`.\n */\nexport const Reasoning = Schema.Struct({\n type: Schema.Literal(\"reasoning\"),\n id: Schema.optional(Schema.String),\n summary: Schema.optional(Schema.String),\n signature: Schema.optional(Schema.String),\n providerData: ProviderData,\n})\nexport type Reasoning = typeof Reasoning.Type\n\nexport const HistoryItem = Schema.Union([Message, ToolCall, ToolCallOutput, Reasoning])\nexport type HistoryItem = typeof HistoryItem.Type\n\n// ---------------------------------------------------------------------------\n// Type guards\n// ---------------------------------------------------------------------------\n\nexport const isInputText = Schema.is(InputText)\nexport const isInputImage = Schema.is(InputImage)\nexport const isOutputText = Schema.is(OutputText)\nexport const isRefusal = Schema.is(Refusal)\n\nexport const isMessage = Schema.is(Message)\nexport const isToolCall = Schema.is(ToolCall)\nexport const isToolCallOutput = Schema.is(ToolCallOutput)\nexport const isReasoning = Schema.is(Reasoning)\n\n// ---------------------------------------------------------------------------\n// Usage and stop reason\n// ---------------------------------------------------------------------------\n\n/**\n * Prompt-cache token breakdown. `cached_tokens` is cache reads;\n * `cache_write_tokens` is tokens written to the cache this turn (billed at a\n * premium). Field names mirror the OpenAI Responses usage shape.\n *\n * Whether these are a subset of `input_tokens` or a separate bucket is\n * provider-specific: OpenAI counts cache reads inside `input_tokens`, while\n * Anthropic reports `input_tokens` as post-breakpoint tokens only, with reads\n * and writes as separate additive buckets. Read a provider's usage in its own\n * terms; do not assume one relationship holds everywhere.\n */\nexport const InputTokensDetails = Schema.Struct({\n cached_tokens: Schema.optional(Schema.Number),\n cache_write_tokens: Schema.optional(Schema.Number),\n})\nexport type InputTokensDetails = typeof InputTokensDetails.Type\n\nexport const OutputTokensDetails = Schema.Struct({\n reasoning_tokens: Schema.optional(Schema.Number),\n})\nexport type OutputTokensDetails = typeof OutputTokensDetails.Type\n\nexport const Usage = Schema.Struct({\n input_tokens: Schema.optional(Schema.Number),\n output_tokens: Schema.optional(Schema.Number),\n total_tokens: Schema.optional(Schema.Number),\n input_tokens_details: Schema.optional(InputTokensDetails),\n output_tokens_details: Schema.optional(OutputTokensDetails),\n})\nexport type Usage = typeof Usage.Type\n\nexport const StopReason = Schema.Literals([\n \"stop\",\n \"tool_calls\",\n \"max_tokens\",\n \"refusal\",\n /** Provider-side safety classifier flagged the output. */\n \"content_filter\",\n /** Server-enforced cap on tool calls per turn was hit. */\n \"max_tool_calls\",\n])\nexport type StopReason = typeof StopReason.Type\n\n// ---------------------------------------------------------------------------\n// Helper constructors\n// ---------------------------------------------------------------------------\n\nexport const userText = (text: string): Message => ({\n type: \"message\",\n role: \"user\",\n content: [{ type: \"input_text\", text }],\n})\n\nexport const systemText = (text: string): Message => ({\n type: \"message\",\n role: \"system\",\n content: [{ type: \"input_text\", text }],\n})\n\nexport const assistantText = (text: string): Message => ({\n type: \"message\",\n role: \"assistant\",\n content: [{ type: \"output_text\", text }],\n})\n\nexport const toolCallOutput = (call_id: string, output: string): ToolCallOutput => ({\n type: \"function_call_output\",\n call_id,\n output,\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"Items.mjs","names":[],"sources":["../../src/domain/Items.ts"],"sourcesContent":["import { Schema } from \"effect\"\nimport { ImageSource } from \"./Image.js\"\n\n// ---------------------------------------------------------------------------\n// Content blocks (inside Message.content)\n// ---------------------------------------------------------------------------\n\nexport const InputText = Schema.Struct({\n type: Schema.Literal(\"input_text\"),\n text: Schema.String,\n})\nexport type InputText = typeof InputText.Type\n\n/**\n * User-provided image content block. Pair with `InputText` inside a\n * `Message.content` array to ask \"what's in this image?\" style questions.\n *\n * `source` is the cross-modality `ImageSource` from `domain/Image.ts` -\n * url, base64, or raw bytes. Provider codecs encode bytes to whatever\n * wire format the provider wants.\n */\nexport const InputImage = Schema.Struct({\n type: Schema.Literal(\"input_image\"),\n source: ImageSource,\n})\nexport type InputImage = typeof InputImage.Type\n\n// ---------------------------------------------------------------------------\n// Annotations - source / citation pointers attached to `output_text` blocks.\n// Provider-agnostic: each provider populates the fields it has (character\n// span, quote, or positional marker) and omits the rest.\n// ---------------------------------------------------------------------------\n\n/**\n * A cited source. `url` + `title` are the only near-universal fields; the\n * link from a source to the answer text varies by provider, so it is optional\n * and expressed three ways: `start_index`/`end_index` (a character span into\n * the answer), `cited_text` (an exact quote of the source, when no offsets are\n * given), or `marker` (a positional `[n]` reference into an ordered list). A\n * provider populates whichever it has; a bare source list sets none.\n */\nexport const UrlCitation = Schema.Struct({\n type: Schema.Literal(\"url_citation\"),\n url: Schema.String,\n title: Schema.String,\n start_index: Schema.optional(Schema.Number),\n end_index: Schema.optional(Schema.Number),\n cited_text: Schema.optional(Schema.String),\n marker: Schema.optional(Schema.Number),\n})\nexport type UrlCitation = typeof UrlCitation.Type\n\nexport const FileCitation = Schema.Struct({\n type: Schema.Literal(\"file_citation\"),\n file_id: Schema.String,\n index: Schema.Number,\n})\nexport type FileCitation = typeof FileCitation.Type\n\nexport const ContainerFileCitation = Schema.Struct({\n type: Schema.Literal(\"container_file_citation\"),\n container_id: Schema.String,\n file_id: Schema.String,\n start_index: Schema.Number,\n end_index: Schema.Number,\n})\nexport type ContainerFileCitation = typeof ContainerFileCitation.Type\n\nexport const FilePath = Schema.Struct({\n type: Schema.Literal(\"file_path\"),\n file_id: Schema.String,\n index: Schema.Number,\n})\nexport type FilePath = typeof FilePath.Type\n\nexport const Annotation = Schema.Union([UrlCitation, FileCitation, ContainerFileCitation, FilePath])\nexport type Annotation = typeof Annotation.Type\n\nexport const isUrlCitation = Schema.is(UrlCitation)\nexport const isFileCitation = Schema.is(FileCitation)\nexport const isContainerFileCitation = Schema.is(ContainerFileCitation)\nexport const isFilePath = Schema.is(FilePath)\n\nexport const OutputText = Schema.Struct({\n type: Schema.Literal(\"output_text\"),\n text: Schema.String,\n annotations: Schema.optional(Schema.Array(Annotation)),\n})\nexport type OutputText = typeof OutputText.Type\n\n/**\n * Model-emitted image. The counterpart to {@link InputImage}: same\n * `ImageSource`, so an image the model drew goes straight back into the\n * next turn with no conversion.\n *\n * How the pixels were produced is not modelled here. A provider may draw\n * them itself, as an image part of the turn, or reach a hosted tool that\n * draws them; either way the fact is the same, and enabling it is\n * provider-specific.\n */\nexport const OutputImage = Schema.Struct({\n type: Schema.Literal(\"output_image\"),\n source: ImageSource,\n})\nexport type OutputImage = typeof OutputImage.Type\n\n/**\n * Model-emitted refusal. Distinct from `output_text`: the model declined\n * to answer rather than producing normal output. Pair with\n * `stop_reason: \"refusal\"` on the surrounding `Turn`. Streamed via the\n * `RefusalDelta` `TurnEvent`.\n */\nexport const Refusal = Schema.Struct({\n type: Schema.Literal(\"refusal\"),\n text: Schema.String,\n})\nexport type Refusal = typeof Refusal.Type\n\nexport const ContentBlock = Schema.Union([InputText, InputImage, OutputText, OutputImage, Refusal])\nexport type ContentBlock = typeof ContentBlock.Type\n\nexport const Role = Schema.Literals([\"user\", \"assistant\", \"system\"])\nexport type Role = typeof Role.Type\n\n// ---------------------------------------------------------------------------\n// Provider passthrough - every Item type carries this opaque slot.\n// The framework never reads or interprets it; provider modules decode\n// their own data via their own typed readers (see e.g.\n// the `@effect-uai/responses` package).\n//\n// The slot is shared, so a provider keys its data under its own name\n// (`{ responses: ... }`, `{ gemini: ... }`) and reads only that key. One item\n// can pass through several providers - falling back from one to another\n// leaves both keys on it - and a provider that finds no key of its own must\n// encode the item normally rather than assume the slot is its own.\n// ---------------------------------------------------------------------------\n\nconst ProviderData = Schema.optional(Schema.Unknown)\n\n// ---------------------------------------------------------------------------\n// Items\n// ---------------------------------------------------------------------------\n\nexport const Message = Schema.Struct({\n type: Schema.Literal(\"message\"),\n role: Role,\n content: Schema.Array(ContentBlock),\n providerData: ProviderData,\n})\nexport type Message = typeof Message.Type\n\nexport const ToolCall = Schema.Struct({\n type: Schema.Literal(\"function_call\"),\n call_id: Schema.String,\n name: Schema.String,\n // JSON-encoded arguments string, mirroring OpenAI Responses API\n arguments: Schema.String,\n providerData: ProviderData,\n})\nexport type ToolCall = typeof ToolCall.Type\n\nexport const ToolCallOutput = Schema.Struct({\n type: Schema.Literal(\"function_call_output\"),\n call_id: Schema.String,\n output: Schema.String,\n providerData: ProviderData,\n})\nexport type ToolCallOutput = typeof ToolCallOutput.Type\n\n/**\n * Reasoning item - top-level, mirrors OpenAI Responses API. Common shape\n * across providers covers `summary` (human-readable text) and `signature`\n * (opaque round-trip blob - Anthropic's signed thinking, OpenAI's\n * encrypted_content, etc.). Provider-specific fields go in `providerData`.\n */\nexport const Reasoning = Schema.Struct({\n type: Schema.Literal(\"reasoning\"),\n id: Schema.optional(Schema.String),\n summary: Schema.optional(Schema.String),\n signature: Schema.optional(Schema.String),\n providerData: ProviderData,\n})\nexport type Reasoning = typeof Reasoning.Type\n\nexport const HistoryItem = Schema.Union([Message, ToolCall, ToolCallOutput, Reasoning])\nexport type HistoryItem = typeof HistoryItem.Type\n\n// ---------------------------------------------------------------------------\n// Type guards\n// ---------------------------------------------------------------------------\n\nexport const isInputText = Schema.is(InputText)\nexport const isInputImage = Schema.is(InputImage)\nexport const isOutputText = Schema.is(OutputText)\nexport const isOutputImage = Schema.is(OutputImage)\nexport const isRefusal = Schema.is(Refusal)\n\nexport const isMessage = Schema.is(Message)\nexport const isToolCall = Schema.is(ToolCall)\nexport const isToolCallOutput = Schema.is(ToolCallOutput)\nexport const isReasoning = Schema.is(Reasoning)\n\n// ---------------------------------------------------------------------------\n// Usage and stop reason\n// ---------------------------------------------------------------------------\n\n/**\n * Prompt-cache token breakdown. `cached_tokens` is cache reads;\n * `cache_write_tokens` is tokens written to the cache this turn (billed at a\n * premium). Field names mirror the OpenAI Responses usage shape.\n *\n * Whether these are a subset of `input_tokens` or a separate bucket is\n * provider-specific: OpenAI counts cache reads inside `input_tokens`, while\n * Anthropic reports `input_tokens` as post-breakpoint tokens only, with reads\n * and writes as separate additive buckets. Read a provider's usage in its own\n * terms; do not assume one relationship holds everywhere.\n */\nexport const InputTokensDetails = Schema.Struct({\n cached_tokens: Schema.optional(Schema.Number),\n cache_write_tokens: Schema.optional(Schema.Number),\n})\nexport type InputTokensDetails = typeof InputTokensDetails.Type\n\nexport const OutputTokensDetails = Schema.Struct({\n reasoning_tokens: Schema.optional(Schema.Number),\n})\nexport type OutputTokensDetails = typeof OutputTokensDetails.Type\n\nexport const Usage = Schema.Struct({\n input_tokens: Schema.optional(Schema.Number),\n output_tokens: Schema.optional(Schema.Number),\n total_tokens: Schema.optional(Schema.Number),\n input_tokens_details: Schema.optional(InputTokensDetails),\n output_tokens_details: Schema.optional(OutputTokensDetails),\n})\nexport type Usage = typeof Usage.Type\n\nexport const StopReason = Schema.Literals([\n \"stop\",\n \"tool_calls\",\n \"max_tokens\",\n \"refusal\",\n /** Provider-side safety classifier flagged the output. */\n \"content_filter\",\n /** Server-enforced cap on tool calls per turn was hit. */\n \"max_tool_calls\",\n])\nexport type StopReason = typeof StopReason.Type\n\n// ---------------------------------------------------------------------------\n// Helper constructors\n// ---------------------------------------------------------------------------\n\nexport const userText = (text: string): Message => ({\n type: \"message\",\n role: \"user\",\n content: [{ type: \"input_text\", text }],\n})\n\nexport const systemText = (text: string): Message => ({\n type: \"message\",\n role: \"system\",\n content: [{ type: \"input_text\", text }],\n})\n\nexport const assistantText = (text: string): Message => ({\n type: \"message\",\n role: \"assistant\",\n content: [{ type: \"output_text\", text }],\n})\n\nexport const toolCallOutput = (call_id: string, output: string): ToolCallOutput => ({\n type: \"function_call_output\",\n call_id,\n output,\n})\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { c as isMediaUrl, i as MediaUrl, n as MediaBytes, o as isMediaBase64, r as MediaSource, s as isMediaBytes, t as MediaBase64 } from "../Media-DwgpifPD.mjs";
2
- export { MediaBase64, MediaBytes, MediaSource, MediaUrl, isMediaBase64, isMediaBytes, isMediaUrl };
1
+ import { a as MediaSource, c as Watermark, d as isMediaUrl, f as parseAspectRatio, i as MediaBytes, l as isMediaBase64, n as Dimensions, o as MediaUrl, p as round16, r as MediaBase64, t as AspectRatio, u as isMediaBytes } from "../Media-BbX7BAaO.mjs";
2
+ export { AspectRatio, Dimensions, MediaBase64, MediaBytes, MediaSource, MediaUrl, Watermark, isMediaBase64, isMediaBytes, isMediaUrl, parseAspectRatio, round16 };
@@ -1,14 +1,63 @@
1
1
  import { n as __exportAll } from "../rolldown-runtime-EAsCxrDo.mjs";
2
+ import { Result } from "effect";
2
3
  //#region src/domain/Media.ts
4
+ /**
5
+ * Cross-modality media reference shape.
6
+ *
7
+ * Every "media at rest" reference - image, audio, video, document - is one
8
+ * of three variants:
9
+ *
10
+ * - `url` : a remote address (HTTP, GCS, etc.). The model fetches it.
11
+ * `mimeType` is optional - servers usually set Content-Type.
12
+ * Some providers (Gemini `fileData`) want it explicit.
13
+ *
14
+ * - `base64` : an inline base64-encoded payload. Always carries a
15
+ * `mimeType` so the consumer knows how to decode.
16
+ *
17
+ * - `bytes` : raw `Uint8Array`. Provider layers normalize to base64 or
18
+ * multipart upload at the wire boundary - users don't need
19
+ * to encode themselves.
20
+ *
21
+ * Per-modality files (`Image.ts`, future `Audio.ts` / `Video.ts` /
22
+ * `Document.ts`) instantiate this shape with their typed MIME union to
23
+ * get autocomplete on common formats while keeping the structural type
24
+ * uniform across modalities.
25
+ *
26
+ * Streaming media (live mic feed, streaming TTS playback) is *not*
27
+ * modeled here. Streams carry effect parameters (`Stream<A, E, R>`) and
28
+ * lifecycle (Scope, cancellation) that don't apply to media at rest. The
29
+ * complementary type lives alongside this one as `*Stream` in each
30
+ * per-modality file when those modalities land.
31
+ *
32
+ * Provider-uploaded asset references (OpenAI Files `file_id`, Gemini
33
+ * Files API URIs, Anthropic file IDs) are also out of scope here -
34
+ * they're a separate union (`FileRef`) added when needed.
35
+ */
3
36
  var Media_exports = /* @__PURE__ */ __exportAll({
4
37
  isMediaBase64: () => isMediaBase64,
5
38
  isMediaBytes: () => isMediaBytes,
6
- isMediaUrl: () => isMediaUrl
39
+ isMediaUrl: () => isMediaUrl,
40
+ parseAspectRatio: () => parseAspectRatio,
41
+ round16: () => round16
7
42
  });
43
+ const positive = (n) => n !== void 0 && Number.isFinite(n) && n > 0;
44
+ /**
45
+ * Read `"W:H"` as a pair. Fails when the ratio is not arithmetic, which
46
+ * the `(string & {})` tail on {@link AspectRatio} lets through: a caller
47
+ * asking for `"cinematic"` gets a message rather than NaN pixels. The
48
+ * failure is a plain string so this file stays free of provider
49
+ * vocabulary; each adapter wraps it in its own error.
50
+ */
51
+ const parseAspectRatio = (ratio) => {
52
+ const [w, h, ...rest] = ratio.split(":").map(Number);
53
+ return positive(w) && positive(h) && rest.length === 0 ? Result.succeed([w, h]) : Result.fail(`aspectRatio "${ratio}" must read "W:H" with positive numbers.`);
54
+ };
55
+ /** Several image endpoints require both edges to be multiples of 16. */
56
+ const round16 = (n) => Math.max(16, Math.round(n / 16) * 16);
8
57
  const isMediaUrl = (s) => s._tag === "url";
9
58
  const isMediaBase64 = (s) => s._tag === "base64";
10
59
  const isMediaBytes = (s) => s._tag === "bytes";
11
60
  //#endregion
12
- export { isMediaBase64, isMediaBytes, isMediaUrl, Media_exports as t };
61
+ export { isMediaBase64, isMediaBytes, isMediaUrl, parseAspectRatio, round16, Media_exports as t };
13
62
 
14
63
  //# sourceMappingURL=Media.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Media.mjs","names":[],"sources":["../../src/domain/Media.ts"],"sourcesContent":["/**\n * Cross-modality media reference shape.\n *\n * Every \"media at rest\" reference - image, audio, video, document - is one\n * of three variants:\n *\n * - `url` : a remote address (HTTP, GCS, etc.). The model fetches it.\n * `mimeType` is optional - servers usually set Content-Type.\n * Some providers (Gemini `fileData`) want it explicit.\n *\n * - `base64` : an inline base64-encoded payload. Always carries a\n * `mimeType` so the consumer knows how to decode.\n *\n * - `bytes` : raw `Uint8Array`. Provider layers normalize to base64 or\n * multipart upload at the wire boundary - users don't need\n * to encode themselves.\n *\n * Per-modality files (`Image.ts`, future `Audio.ts` / `Video.ts` /\n * `Document.ts`) instantiate this shape with their typed MIME union to\n * get autocomplete on common formats while keeping the structural type\n * uniform across modalities.\n *\n * Streaming media (live mic feed, streaming TTS playback) is *not*\n * modeled here. Streams carry effect parameters (`Stream<A, E, R>`) and\n * lifecycle (Scope, cancellation) that don't apply to media at rest. The\n * complementary type lives alongside this one as `*Stream` in each\n * per-modality file when those modalities land.\n *\n * Provider-uploaded asset references (OpenAI Files `file_id`, Gemini\n * Files API URIs, Anthropic file IDs) are also out of scope here -\n * they're a separate union (`FileRef`) added when needed.\n */\n\nexport type MediaUrl<M extends string = string> = {\n readonly _tag: \"url\"\n readonly url: string\n readonly mimeType?: M\n}\n\nexport type MediaBase64<M extends string = string> = {\n readonly _tag: \"base64\"\n readonly base64: string\n readonly mimeType: M\n}\n\nexport type MediaBytes<M extends string = string> = {\n readonly _tag: \"bytes\"\n readonly bytes: Uint8Array\n readonly mimeType: M\n}\n\nexport type MediaSource<M extends string = string> = MediaUrl<M> | MediaBase64<M> | MediaBytes<M>\n\nexport const isMediaUrl = <M extends string>(s: MediaSource<M>): s is MediaUrl<M> =>\n s._tag === \"url\"\n\nexport const isMediaBase64 = <M extends string>(s: MediaSource<M>): s is MediaBase64<M> =>\n s._tag === \"base64\"\n\nexport const isMediaBytes = <M extends string>(s: MediaSource<M>): s is MediaBytes<M> =>\n s._tag === \"bytes\"\n"],"mappings":";;;;;;;AAqDA,MAAa,cAAgC,MAC3C,EAAE,SAAS;AAEb,MAAa,iBAAmC,MAC9C,EAAE,SAAS;AAEb,MAAa,gBAAkC,MAC7C,EAAE,SAAS"}
1
+ {"version":3,"file":"Media.mjs","names":[],"sources":["../../src/domain/Media.ts"],"sourcesContent":["/**\n * Cross-modality media reference shape.\n *\n * Every \"media at rest\" reference - image, audio, video, document - is one\n * of three variants:\n *\n * - `url` : a remote address (HTTP, GCS, etc.). The model fetches it.\n * `mimeType` is optional - servers usually set Content-Type.\n * Some providers (Gemini `fileData`) want it explicit.\n *\n * - `base64` : an inline base64-encoded payload. Always carries a\n * `mimeType` so the consumer knows how to decode.\n *\n * - `bytes` : raw `Uint8Array`. Provider layers normalize to base64 or\n * multipart upload at the wire boundary - users don't need\n * to encode themselves.\n *\n * Per-modality files (`Image.ts`, future `Audio.ts` / `Video.ts` /\n * `Document.ts`) instantiate this shape with their typed MIME union to\n * get autocomplete on common formats while keeping the structural type\n * uniform across modalities.\n *\n * Streaming media (live mic feed, streaming TTS playback) is *not*\n * modeled here. Streams carry effect parameters (`Stream<A, E, R>`) and\n * lifecycle (Scope, cancellation) that don't apply to media at rest. The\n * complementary type lives alongside this one as `*Stream` in each\n * per-modality file when those modalities land.\n *\n * Provider-uploaded asset references (OpenAI Files `file_id`, Gemini\n * Files API URIs, Anthropic file IDs) are also out of scope here -\n * they're a separate union (`FileRef`) added when needed.\n */\n\nimport { Result } from \"effect\"\n\n/**\n * Watermark kind a provider embedded in generated media. Shared across\n * modalities (audio, image). No provider exposes metadata beyond the\n * kind, so a bare literal union is enough.\n */\nexport type Watermark = \"synthid\" | \"c2pa\" | (string & {})\n\n/**\n * Requested shape of generated visual media, width to height. Shared by\n * image and video generation: the listed ratios are the ones providers\n * accept as literals, and the `(string & {})` tail keeps a\n * newly-supported ratio working without an SDK update. Which ratios a\n * given model accepts is not checked here; the provider rejects what it\n * cannot render and the adapter translates that error.\n *\n * Resolution is NOT shared: image models tier by short edge\n * (`ImageResolution`), video models by scan height. Each modality types\n * its own.\n */\nexport type AspectRatio =\n | \"1:1\"\n | \"2:3\"\n | \"3:2\"\n | \"3:4\"\n | \"4:3\"\n | \"4:5\"\n | \"5:4\"\n | \"9:16\"\n | \"16:9\"\n | \"21:9\"\n | \"1:4\"\n | \"4:1\"\n | \"1:8\"\n | \"8:1\"\n | (string & {})\n\n/** Exact pixels, for adapters whose wire takes dimensions rather than a ratio. */\nexport type Dimensions = {\n readonly width: number\n readonly height: number\n}\n\nconst positive = (n: number | undefined): n is number =>\n n !== undefined && Number.isFinite(n) && n > 0\n\n/**\n * Read `\"W:H\"` as a pair. Fails when the ratio is not arithmetic, which\n * the `(string & {})` tail on {@link AspectRatio} lets through: a caller\n * asking for `\"cinematic\"` gets a message rather than NaN pixels. The\n * failure is a plain string so this file stays free of provider\n * vocabulary; each adapter wraps it in its own error.\n */\nexport const parseAspectRatio = (\n ratio: AspectRatio,\n): Result.Result<readonly [number, number], string> => {\n const [w, h, ...rest] = ratio.split(\":\").map(Number)\n return positive(w) && positive(h) && rest.length === 0\n ? Result.succeed([w, h] as const)\n : Result.fail(`aspectRatio \"${ratio}\" must read \"W:H\" with positive numbers.`)\n}\n\n/** Several image endpoints require both edges to be multiples of 16. */\nexport const round16 = (n: number): number => Math.max(16, Math.round(n / 16) * 16)\n\nexport type MediaUrl<M extends string = string> = {\n readonly _tag: \"url\"\n readonly url: string\n readonly mimeType?: M\n}\n\nexport type MediaBase64<M extends string = string> = {\n readonly _tag: \"base64\"\n readonly base64: string\n readonly mimeType: M\n}\n\nexport type MediaBytes<M extends string = string> = {\n readonly _tag: \"bytes\"\n readonly bytes: Uint8Array\n readonly mimeType: M\n}\n\nexport type MediaSource<M extends string = string> = MediaUrl<M> | MediaBase64<M> | MediaBytes<M>\n\nexport const isMediaUrl = <M extends string>(s: MediaSource<M>): s is MediaUrl<M> =>\n s._tag === \"url\"\n\nexport const isMediaBase64 = <M extends string>(s: MediaSource<M>): s is MediaBase64<M> =>\n s._tag === \"base64\"\n\nexport const isMediaBytes = <M extends string>(s: MediaSource<M>): s is MediaBytes<M> =>\n s._tag === \"bytes\"\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6EA,MAAM,YAAY,MAChB,MAAM,KAAA,KAAa,OAAO,SAAS,CAAC,KAAK,IAAI;;;;;;;;AAS/C,MAAa,oBACX,UACqD;CACrD,MAAM,CAAC,GAAG,GAAG,GAAG,QAAQ,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,MAAM;CACnD,OAAO,SAAS,CAAC,KAAK,SAAS,CAAC,KAAK,KAAK,WAAW,IACjD,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAU,IAC9B,OAAO,KAAK,gBAAgB,MAAM,yCAAyC;AACjF;;AAGA,MAAa,WAAW,MAAsB,KAAK,IAAI,IAAI,KAAK,MAAM,IAAI,EAAE,IAAI,EAAE;AAsBlF,MAAa,cAAgC,MAC3C,EAAE,SAAS;AAEb,MAAa,iBAAmC,MAC9C,EAAE,SAAS;AAEb,MAAa,gBAAkC,MAC7C,EAAE,SAAS"}
@@ -1,4 +1,5 @@
1
- import { n as AudioChunk, r as AudioFormat, t as AudioBlob } from "../Audio-60lKKHxS.mjs";
1
+ import { c as Watermark } from "../Media-BbX7BAaO.mjs";
2
+ import { n as AudioChunk, r as AudioFormat, t as AudioBlob } from "../Audio-_nGR4V0X.mjs";
2
3
  import { Duration } from "effect";
3
4
  declare namespace Music_d_exports {
4
5
  export { CommonGenerateMusicRequest, CommonStreamGenerateMusicRequest, GenerateResult, MusicResult, MusicSection, MusicSessionControl, MusicSessionInput, MusicStreamEvent, Watermark, WeightedPrompt, audioEvent, controlInput, filteredPromptEvent, isAudioEvent, isControlInput, isFilteredPromptEvent, isPromptsInput, isWarningEvent, promptsInput, singleVariant, warningEvent };
@@ -86,12 +87,6 @@ type MusicSessionInput = {
86
87
  };
87
88
  declare const promptsInput: (prompts: ReadonlyArray<WeightedPrompt>) => MusicSessionInput;
88
89
  declare const controlInput: (action: MusicSessionControl) => MusicSessionInput;
89
- /**
90
- * Watermark kind on the response. SynthID is mandatory on Lyria; C2PA
91
- * is opt-in on ElevenLabs. No provider exposes additional metadata
92
- * about the watermark itself, so a bare literal-union is enough.
93
- */
94
- type Watermark = "synthid" | "c2pa" | (string & {});
95
90
  /**
96
91
  * Labelled section with absolute timing. Populated when the provider
97
92
  * returns structured section metadata (Lyria text part, ElevenLabs
@@ -178,5 +173,5 @@ declare const isFilteredPromptEvent: (e: MusicStreamEvent) => e is MusicStreamEv
178
173
  */
179
174
  declare const singleVariant: (result: MusicResult) => GenerateResult;
180
175
  //#endregion
181
- export { CommonGenerateMusicRequest, CommonStreamGenerateMusicRequest, GenerateResult, MusicResult, MusicSection, MusicSessionControl, MusicSessionInput, MusicStreamEvent, Watermark, WeightedPrompt, audioEvent, controlInput, filteredPromptEvent, isAudioEvent, isControlInput, isFilteredPromptEvent, isPromptsInput, isWarningEvent, promptsInput, singleVariant, Music_d_exports as t, warningEvent };
176
+ export { CommonGenerateMusicRequest, CommonStreamGenerateMusicRequest, GenerateResult, MusicResult, MusicSection, MusicSessionControl, MusicSessionInput, MusicStreamEvent, type Watermark, WeightedPrompt, audioEvent, controlInput, filteredPromptEvent, isAudioEvent, isControlInput, isFilteredPromptEvent, isPromptsInput, isWarningEvent, promptsInput, singleVariant, Music_d_exports as t, warningEvent };
182
177
  //# sourceMappingURL=Music.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Music.d.mts","names":[],"sources":["../../src/domain/Music.ts"],"mappings":";;;;;;;;;;;KASY;WACD;;WAEA;;;;;;;;;;;;;KAcC;;WAED;;WAEA;;;;;;;;;WASA;;WAEA,WAAW,SAAS;;;;;;;WAOpB;;WAEA,eAAe;;;;;;KAOd,mCAAmC;;;;;;;;KASnC;;;;;;;;;;;;;;KAeA;WACG;WAA0B,SAAS,cAAc;;WACjD;WAA0B,QAAQ;;cAEpC,eAAY,SAAa,cAAc,oBAAkB;cAKzD,eAAY,QAAY,wBAAsB;;;;;;KAU/C;;;;;;KAOA;WACD;WACA;WACA;;;;;;;KAQC;WACD,OAAO;;;;;;WAMP;;WAEA;;WAEA;;WAEA,WAAW,cAAc;;WAEzB,YAAY;;;;;;;;KASX;WACD,SAAS;WACT,UAAU,cAAc;;;;;;;;KASvB;WACG;WAAwB,OAAO;;WAC/B;WAA0B;;WAC1B;WAAiC;WAAyB;;cAE5D,iBAAc,GACtB,sBACF,KAAK;EAAsB;;cACjB,iBAAc,GACtB,sBACF,KAAK;EAAsB;;cAEjB,aAAU,OAAW,eAAa;cAClC,eAAY,oBAAsB;cAIlC,sBAAmB,gBAAkB,mBAAmB;cAMxD,eAAY,GAAO,qBAAmB,KAAK;EAAqB;;cAEhE,iBAAc,GAAO,qBAAmB,KAAK;EAAqB;;cAElE,wBAAqB,GAC7B,qBACF,KAAK;EAAqB;;;;;;;;;cAShB,gBAAa,QAAY,gBAAc"}
1
+ {"version":3,"file":"Music.d.mts","names":[],"sources":["../../src/domain/Music.ts"],"mappings":";;;;;;;;;;;;KAUY;WACD;;WAEA;;;;;;;;;;;;;KAcC;;WAED;;WAEA;;;;;;;;;WASA;;WAEA,WAAW,SAAS;;;;;;;WAOpB;;WAEA,eAAe;;;;;;KAOd,mCAAmC;;;;;;;;KASnC;;;;;;;;;;;;;;KAeA;WACG;WAA0B,SAAS,cAAc;;WACjD;WAA0B,QAAQ;;cAEpC,eAAY,SAAa,cAAc,oBAAkB;cAKzD,eAAY,QAAY,wBAAsB;;;;;;KAiB/C;WACD;WACA;WACA;;;;;;;KAQC;WACD,OAAO;;;;;;WAMP;;WAEA;;WAEA;;WAEA,WAAW,cAAc;;WAEzB,YAAY;;;;;;;;KASX;WACD,SAAS;WACT,UAAU,cAAc;;;;;;;;KASvB;WACG;WAAwB,OAAO;;WAC/B;WAA0B;;WAC1B;WAAiC;WAAyB;;cAE5D,iBAAc,GACtB,sBACF,KAAK;EAAsB;;cACjB,iBAAc,GACtB,sBACF,KAAK;EAAsB;;cAEjB,aAAU,OAAW,eAAa;cAClC,eAAY,oBAAsB;cAIlC,sBAAmB,gBAAkB,mBAAmB;cAMxD,eAAY,GAAO,qBAAmB,KAAK;EAAqB;;cAEhE,iBAAc,GAAO,qBAAmB,KAAK;EAAqB;;cAElE,wBAAqB,GAC7B,qBACF,KAAK;EAAqB;;;;;;;;;cAShB,gBAAa,QAAY,gBAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"Music.mjs","names":[],"sources":["../../src/domain/Music.ts"],"sourcesContent":["import type { Duration } from \"effect\"\nimport type { AudioBlob, AudioChunk, AudioFormat } from \"./Audio.js\"\n\n/**\n * Prompt fragment with a relative weight. Native to Lyria RealTime\n * (`{ text, weight }` pairs blended in the model) and Riffusion compose.\n * Single-prompt providers (the majority) treat a 1-element array with\n * `weight: 1` as a plain prompt.\n */\nexport type WeightedPrompt = {\n readonly text: string\n /** Default `1.0`. Range typically `[0, 1]`; provider-dependent. */\n readonly weight?: number\n}\n\n/**\n * Cross-provider music-generation request. Trimmed to fields the\n * majority of music providers honor structurally; provider-specific\n * extras (Lyria `bpm` / `scale`, ElevenLabs `compositionPlan` /\n * `signWithC2pa`, Suno `style` / `personaId`, MiniMax `lyricsOptimizer`,\n * `instrumental` on providers that ship a wire toggle) live on each\n * provider's typed request which extends this and narrows `model`.\n *\n * Music providers are one-shot text-to-audio, not conversational. No\n * `messages[]` shape applies.\n */\nexport type CommonGenerateMusicRequest = {\n /** Model identifier. Each provider narrows. */\n readonly model: string\n /** Single prompt string. Weighted blends are provider-typed extras. */\n readonly prompt: string\n /**\n * Lyrics text, optionally with section tags like `[Verse]` /\n * `[Chorus]` / `[Bridge]` / `[Outro]`. Routed to a structured wire\n * field on providers that have one (ElevenLabs `lines`, MiniMax\n * `lyrics`, Mureka `lyrics`, Suno custom-mode `prompt`); embedded in\n * the prompt with a warning on providers without one (Lyria 3,\n * Riffusion).\n */\n readonly lyrics?: string\n /** Target duration. Provider may treat as a hint or hard limit. */\n readonly duration?: Duration.Duration\n /**\n * Reproducibility seed. Tuning hint (bucket 3): honored where the\n * provider takes one (Lyria 2 Vertex, Lyria RealTime, ElevenLabs\n * with `compositionPlan`, Stable Audio, MusicGen); silently ignored\n * elsewhere.\n */\n readonly seed?: number\n /** Preferred output format. Provider may override. */\n readonly outputFormat?: AudioFormat\n}\n\n/**\n * Streamed-output request. Same shape as the sync request: the\n * streaming variant only differs in how the response is delivered.\n */\nexport type CommonStreamGenerateMusicRequest = CommonGenerateMusicRequest\n\n/**\n * Playback-control vocabulary that converges across interactive-media\n * protocols (Web Audio, MIDI sequencer control, music SDK surfaces).\n * Provider-specific control actions (Lyria's `reset_context` and any\n * future provider's extras) live on the provider-typed session-input\n * union.\n */\nexport type MusicSessionControl = \"play\" | \"pause\" | \"stop\" | \"reset\"\n\n/**\n * Bidirectional-session input on the cross-provider surface. Two\n * load-bearing actions every interactive music session needs:\n *\n * - `prompts` — steer the active generation with a (single or\n * weighted) prompt blend.\n * - `control` — play / pause / stop / reset.\n *\n * Provider-typed services extend this union with their own `config`\n * variant for model-specific knobs (Lyria RealTime exposes density /\n * brightness / mute-stems / BPM / scale / etc. via its own\n * `LyriaRealtimeSessionInput`).\n */\nexport type MusicSessionInput =\n | { readonly _tag: \"prompts\"; readonly prompts: ReadonlyArray<WeightedPrompt> }\n | { readonly _tag: \"control\"; readonly action: MusicSessionControl }\n\nexport const promptsInput = (prompts: ReadonlyArray<WeightedPrompt>): MusicSessionInput => ({\n _tag: \"prompts\",\n prompts,\n})\n\nexport const controlInput = (action: MusicSessionControl): MusicSessionInput => ({\n _tag: \"control\",\n action,\n})\n\n/**\n * Watermark kind on the response. SynthID is mandatory on Lyria; C2PA\n * is opt-in on ElevenLabs. No provider exposes additional metadata\n * about the watermark itself, so a bare literal-union is enough.\n */\nexport type Watermark = \"synthid\" | \"c2pa\" | (string & {})\n\n/**\n * Labelled section with absolute timing. Populated when the provider\n * returns structured section metadata (Lyria text part, ElevenLabs\n * `/v1/music/detailed` with `with_timestamps`).\n */\nexport type MusicSection = {\n readonly label: string\n readonly startSeconds: number\n readonly endSeconds: number\n}\n\n/**\n * Single generated track. Composes `AudioBlob` rather than extending\n * it — `result.audio` is the raw blob, `result.songId` / `lyrics` /\n * `sections` / `watermark` are provider-side metadata when returned.\n */\nexport type MusicResult = {\n readonly audio: AudioBlob\n /**\n * Provider identifier, useful when routing through multiple\n * providers in a single pipeline (`\"lyria\"`, `\"elevenlabs-music\"`,\n * etc.).\n */\n readonly provider?: string\n /** Provider-side ID for back-reference (re-download, extension, stems). */\n readonly songId?: string\n /** Generated or transcribed lyrics when the provider returned them. */\n readonly lyrics?: string\n /** Structured section markers when the provider returned them. */\n readonly sections?: ReadonlyArray<MusicSection>\n /** Watermark presence indicator when the provider applied one. */\n readonly watermark?: Watermark\n}\n\n/**\n * Result of a `generate` call. Suno and Mureka always return 2 tracks\n * per request; every other provider returns 1. `primary` is the\n * caller-friendly convenience; `variants` carries every track the\n * provider produced (length ≥ 1; `primary === variants[0]`).\n */\nexport type GenerateResult = {\n readonly primary: MusicResult\n readonly variants: ReadonlyArray<MusicResult>\n}\n\n/**\n * In-band event on the bidirectional `streamGenerationFrom` output\n * stream. Audio chunks flow as `audio`; server-side warnings\n * (`warning`) and prompt-filter rejections (`filteredPrompt`) flow\n * alongside rather than going to a side-channel log.\n */\nexport type MusicStreamEvent =\n | { readonly _tag: \"audio\"; readonly chunk: AudioChunk }\n | { readonly _tag: \"warning\"; readonly message: string }\n | { readonly _tag: \"filteredPrompt\"; readonly prompt: string; readonly reason: string }\n\nexport const isPromptsInput = (\n i: MusicSessionInput,\n): i is MusicSessionInput & { _tag: \"prompts\" } => i._tag === \"prompts\"\nexport const isControlInput = (\n i: MusicSessionInput,\n): i is MusicSessionInput & { _tag: \"control\" } => i._tag === \"control\"\n\nexport const audioEvent = (chunk: AudioChunk): MusicStreamEvent => ({ _tag: \"audio\", chunk })\nexport const warningEvent = (message: string): MusicStreamEvent => ({\n _tag: \"warning\",\n message,\n})\nexport const filteredPromptEvent = (prompt: string, reason: string): MusicStreamEvent => ({\n _tag: \"filteredPrompt\",\n prompt,\n reason,\n})\n\nexport const isAudioEvent = (e: MusicStreamEvent): e is MusicStreamEvent & { _tag: \"audio\" } =>\n e._tag === \"audio\"\nexport const isWarningEvent = (e: MusicStreamEvent): e is MusicStreamEvent & { _tag: \"warning\" } =>\n e._tag === \"warning\"\nexport const isFilteredPromptEvent = (\n e: MusicStreamEvent,\n): e is MusicStreamEvent & { _tag: \"filteredPrompt\" } => e._tag === \"filteredPrompt\"\n\n/**\n * Build a single-variant `GenerateResult` from a `MusicResult`.\n * Convenience for providers that always return exactly one track\n * (Lyria, ElevenLabs, MiniMax, Stable Audio, MusicGen, Riffusion,\n * Tencent). Providers that return multiple tracks (Suno, Mureka)\n * construct the `GenerateResult` directly.\n */\nexport const singleVariant = (result: MusicResult): GenerateResult => ({\n primary: result,\n variants: [result],\n})\n"],"mappings":";;;;;;;;;;;;;;;AAqFA,MAAa,gBAAgB,aAA+D;CAC1F,MAAM;CACN;AACF;AAEA,MAAa,gBAAgB,YAAoD;CAC/E,MAAM;CACN;AACF;AAiEA,MAAa,kBACX,MACiD,EAAE,SAAS;AAC9D,MAAa,kBACX,MACiD,EAAE,SAAS;AAE9D,MAAa,cAAc,WAAyC;CAAE,MAAM;CAAS;AAAM;AAC3F,MAAa,gBAAgB,aAAuC;CAClE,MAAM;CACN;AACF;AACA,MAAa,uBAAuB,QAAgB,YAAsC;CACxF,MAAM;CACN;CACA;AACF;AAEA,MAAa,gBAAgB,MAC3B,EAAE,SAAS;AACb,MAAa,kBAAkB,MAC7B,EAAE,SAAS;AACb,MAAa,yBACX,MACuD,EAAE,SAAS;;;;;;;;AASpE,MAAa,iBAAiB,YAAyC;CACrE,SAAS;CACT,UAAU,CAAC,MAAM;AACnB"}
1
+ {"version":3,"file":"Music.mjs","names":[],"sources":["../../src/domain/Music.ts"],"sourcesContent":["import type { Duration } from \"effect\"\nimport type { AudioBlob, AudioChunk, AudioFormat } from \"./Audio.js\"\nimport type { Watermark } from \"./Media.js\"\n\n/**\n * Prompt fragment with a relative weight. Native to Lyria RealTime\n * (`{ text, weight }` pairs blended in the model) and Riffusion compose.\n * Single-prompt providers (the majority) treat a 1-element array with\n * `weight: 1` as a plain prompt.\n */\nexport type WeightedPrompt = {\n readonly text: string\n /** Default `1.0`. Range typically `[0, 1]`; provider-dependent. */\n readonly weight?: number\n}\n\n/**\n * Cross-provider music-generation request. Trimmed to fields the\n * majority of music providers honor structurally; provider-specific\n * extras (Lyria `bpm` / `scale`, ElevenLabs `compositionPlan` /\n * `signWithC2pa`, Suno `style` / `personaId`, MiniMax `lyricsOptimizer`,\n * `instrumental` on providers that ship a wire toggle) live on each\n * provider's typed request which extends this and narrows `model`.\n *\n * Music providers are one-shot text-to-audio, not conversational. No\n * `messages[]` shape applies.\n */\nexport type CommonGenerateMusicRequest = {\n /** Model identifier. Each provider narrows. */\n readonly model: string\n /** Single prompt string. Weighted blends are provider-typed extras. */\n readonly prompt: string\n /**\n * Lyrics text, optionally with section tags like `[Verse]` /\n * `[Chorus]` / `[Bridge]` / `[Outro]`. Routed to a structured wire\n * field on providers that have one (ElevenLabs `lines`, MiniMax\n * `lyrics`, Mureka `lyrics`, Suno custom-mode `prompt`); embedded in\n * the prompt with a warning on providers without one (Lyria 3,\n * Riffusion).\n */\n readonly lyrics?: string\n /** Target duration. Provider may treat as a hint or hard limit. */\n readonly duration?: Duration.Duration\n /**\n * Reproducibility seed. Tuning hint (bucket 3): honored where the\n * provider takes one (Lyria 2 Vertex, Lyria RealTime, ElevenLabs\n * with `compositionPlan`, Stable Audio, MusicGen); silently ignored\n * elsewhere.\n */\n readonly seed?: number\n /** Preferred output format. Provider may override. */\n readonly outputFormat?: AudioFormat\n}\n\n/**\n * Streamed-output request. Same shape as the sync request: the\n * streaming variant only differs in how the response is delivered.\n */\nexport type CommonStreamGenerateMusicRequest = CommonGenerateMusicRequest\n\n/**\n * Playback-control vocabulary that converges across interactive-media\n * protocols (Web Audio, MIDI sequencer control, music SDK surfaces).\n * Provider-specific control actions (Lyria's `reset_context` and any\n * future provider's extras) live on the provider-typed session-input\n * union.\n */\nexport type MusicSessionControl = \"play\" | \"pause\" | \"stop\" | \"reset\"\n\n/**\n * Bidirectional-session input on the cross-provider surface. Two\n * load-bearing actions every interactive music session needs:\n *\n * - `prompts` — steer the active generation with a (single or\n * weighted) prompt blend.\n * - `control` — play / pause / stop / reset.\n *\n * Provider-typed services extend this union with their own `config`\n * variant for model-specific knobs (Lyria RealTime exposes density /\n * brightness / mute-stems / BPM / scale / etc. via its own\n * `LyriaRealtimeSessionInput`).\n */\nexport type MusicSessionInput =\n | { readonly _tag: \"prompts\"; readonly prompts: ReadonlyArray<WeightedPrompt> }\n | { readonly _tag: \"control\"; readonly action: MusicSessionControl }\n\nexport const promptsInput = (prompts: ReadonlyArray<WeightedPrompt>): MusicSessionInput => ({\n _tag: \"prompts\",\n prompts,\n})\n\nexport const controlInput = (action: MusicSessionControl): MusicSessionInput => ({\n _tag: \"control\",\n action,\n})\n\n/**\n * Watermark kind on the response. SynthID is mandatory on Lyria; C2PA\n * is opt-in on ElevenLabs. Lives in `Media.ts` since image providers\n * report the same kinds; re-exported here unchanged.\n */\nexport type { Watermark } from \"./Media.js\"\n\n/**\n * Labelled section with absolute timing. Populated when the provider\n * returns structured section metadata (Lyria text part, ElevenLabs\n * `/v1/music/detailed` with `with_timestamps`).\n */\nexport type MusicSection = {\n readonly label: string\n readonly startSeconds: number\n readonly endSeconds: number\n}\n\n/**\n * Single generated track. Composes `AudioBlob` rather than extending\n * it — `result.audio` is the raw blob, `result.songId` / `lyrics` /\n * `sections` / `watermark` are provider-side metadata when returned.\n */\nexport type MusicResult = {\n readonly audio: AudioBlob\n /**\n * Provider identifier, useful when routing through multiple\n * providers in a single pipeline (`\"lyria\"`, `\"elevenlabs-music\"`,\n * etc.).\n */\n readonly provider?: string\n /** Provider-side ID for back-reference (re-download, extension, stems). */\n readonly songId?: string\n /** Generated or transcribed lyrics when the provider returned them. */\n readonly lyrics?: string\n /** Structured section markers when the provider returned them. */\n readonly sections?: ReadonlyArray<MusicSection>\n /** Watermark presence indicator when the provider applied one. */\n readonly watermark?: Watermark\n}\n\n/**\n * Result of a `generate` call. Suno and Mureka always return 2 tracks\n * per request; every other provider returns 1. `primary` is the\n * caller-friendly convenience; `variants` carries every track the\n * provider produced (length ≥ 1; `primary === variants[0]`).\n */\nexport type GenerateResult = {\n readonly primary: MusicResult\n readonly variants: ReadonlyArray<MusicResult>\n}\n\n/**\n * In-band event on the bidirectional `streamGenerationFrom` output\n * stream. Audio chunks flow as `audio`; server-side warnings\n * (`warning`) and prompt-filter rejections (`filteredPrompt`) flow\n * alongside rather than going to a side-channel log.\n */\nexport type MusicStreamEvent =\n | { readonly _tag: \"audio\"; readonly chunk: AudioChunk }\n | { readonly _tag: \"warning\"; readonly message: string }\n | { readonly _tag: \"filteredPrompt\"; readonly prompt: string; readonly reason: string }\n\nexport const isPromptsInput = (\n i: MusicSessionInput,\n): i is MusicSessionInput & { _tag: \"prompts\" } => i._tag === \"prompts\"\nexport const isControlInput = (\n i: MusicSessionInput,\n): i is MusicSessionInput & { _tag: \"control\" } => i._tag === \"control\"\n\nexport const audioEvent = (chunk: AudioChunk): MusicStreamEvent => ({ _tag: \"audio\", chunk })\nexport const warningEvent = (message: string): MusicStreamEvent => ({\n _tag: \"warning\",\n message,\n})\nexport const filteredPromptEvent = (prompt: string, reason: string): MusicStreamEvent => ({\n _tag: \"filteredPrompt\",\n prompt,\n reason,\n})\n\nexport const isAudioEvent = (e: MusicStreamEvent): e is MusicStreamEvent & { _tag: \"audio\" } =>\n e._tag === \"audio\"\nexport const isWarningEvent = (e: MusicStreamEvent): e is MusicStreamEvent & { _tag: \"warning\" } =>\n e._tag === \"warning\"\nexport const isFilteredPromptEvent = (\n e: MusicStreamEvent,\n): e is MusicStreamEvent & { _tag: \"filteredPrompt\" } => e._tag === \"filteredPrompt\"\n\n/**\n * Build a single-variant `GenerateResult` from a `MusicResult`.\n * Convenience for providers that always return exactly one track\n * (Lyria, ElevenLabs, MiniMax, Stable Audio, MusicGen, Riffusion,\n * Tencent). Providers that return multiple tracks (Suno, Mureka)\n * construct the `GenerateResult` directly.\n */\nexport const singleVariant = (result: MusicResult): GenerateResult => ({\n primary: result,\n variants: [result],\n})\n"],"mappings":";;;;;;;;;;;;;;;AAsFA,MAAa,gBAAgB,aAA+D;CAC1F,MAAM;CACN;AACF;AAEA,MAAa,gBAAgB,YAAoD;CAC/E,MAAM;CACN;AACF;AAiEA,MAAa,kBACX,MACiD,EAAE,SAAS;AAC9D,MAAa,kBACX,MACiD,EAAE,SAAS;AAE9D,MAAa,cAAc,WAAyC;CAAE,MAAM;CAAS;AAAM;AAC3F,MAAa,gBAAgB,aAAuC;CAClE,MAAM;CACN;AACF;AACA,MAAa,uBAAuB,QAAgB,YAAsC;CACxF,MAAM;CACN;CACA;AACF;AAEA,MAAa,gBAAgB,MAC3B,EAAE,SAAS;AACb,MAAa,kBAAkB,MAC7B,EAAE,SAAS;AACb,MAAa,yBACX,MACuD,EAAE,SAAS;;;;;;;;AASpE,MAAa,iBAAiB,YAAyC;CACrE,SAAS;CACT,UAAU,CAAC,MAAM;AACnB"}
@@ -1,4 +1,4 @@
1
- import { o as HistoryItem } from "../Items-SfUabNuB.mjs";
1
+ import { o as HistoryItem } from "../Items-C7MyrYPX.mjs";
2
2
  import { JobRef, JobState } from "../job/Job.mjs";
3
3
  import { Turn } from "./Turn.mjs";
4
4
  declare namespace Research_d_exports {
@@ -1,9 +1,9 @@
1
- import { i as ImageSource } from "../Image-BK8-4H6s.mjs";
2
- import { d as Message, m as Reasoning, o as HistoryItem, t as Annotation, v as ToolCall, x as Usage, y as ToolCallOutput } from "../Items-SfUabNuB.mjs";
1
+ import { o as ImageSource } from "../Image-Cv6iBLTy.mjs";
2
+ import { S as Usage, b as ToolCallOutput, d as Message, h as Reasoning, o as HistoryItem, t as Annotation, y as ToolCall } from "../Items-C7MyrYPX.mjs";
3
3
  import { i as StructuredFormat, n as JsonParseError, r as StructuredDecodeError } from "../StructuredFormat-BlZhyOsi.mjs";
4
4
  import { Data, Effect, Schema, Stream } from "effect";
5
5
  declare namespace Turn_d_exports {
6
- export { InteractionEvent, RefusalRejected, Turn, TurnEvent, appendToHistory, assistantMessages, assistantText, assistantTexts, citations, decodeStructured, getToolCalls, isTurnComplete, reasonings, textDeltas };
6
+ export { InteractionEvent, RefusalRejected, Turn, TurnEvent, appendToHistory, assistantImages, assistantMessages, assistantText, assistantTexts, citations, decodeStructured, getToolCalls, imagesAsInput, isTurnComplete, reasonings, textDeltas };
7
7
  }
8
8
  /**
9
9
  * The result of a single LLM generation. A turn produces zero or more items
@@ -46,6 +46,9 @@ declare const Turn: Schema.Struct<{
46
46
  readonly file_id: Schema.String;
47
47
  readonly index: Schema.Number;
48
48
  }>]>>>;
49
+ }>, Schema.Struct<{
50
+ readonly type: Schema.Literal<"output_image">;
51
+ readonly source: Schema.Schema<ImageSource>;
49
52
  }>, Schema.Struct<{
50
53
  readonly type: Schema.Literal<"refusal">;
51
54
  readonly text: Schema.String;
@@ -106,6 +109,12 @@ type Turn = typeof Turn.Type;
106
109
  * `WebSearchCall`: lifecycle of a provider-executed web search within the
107
110
  * turn. Fires only when the turn grounds against search; absent otherwise.
108
111
  *
112
+ * `ImageOutput`: an image the model produced, whether it drew it as part
113
+ * of its turn or reached a hosted tool for it. `partialIndex` marks a
114
+ * preview frame from providers that stream them; the finished image
115
+ * arrives without one and is also on `TurnComplete.turn` as an
116
+ * `OutputImage` block.
117
+ *
109
118
  * `CitationAdded`: a citation attached to the answer, emitted incrementally
110
119
  * where the provider streams citations. Providers that bundle citations emit
111
120
  * none of these; their citations still arrive on `TurnComplete.turn`
@@ -138,6 +147,11 @@ type TurnEvent = Data.TaggedEnum<{
138
147
  readonly query?: string;
139
148
  readonly action?: "search" | "open_page" | "find_in_page";
140
149
  };
150
+ ImageOutput: {
151
+ readonly image: ImageSource;
152
+ /** Set only on a preview frame, counting from 0. Absent means finished. */
153
+ readonly partialIndex?: number;
154
+ };
141
155
  CitationAdded: {
142
156
  readonly annotation: Annotation;
143
157
  };
@@ -146,11 +160,17 @@ type TurnEvent = Data.TaggedEnum<{
146
160
  };
147
161
  }>;
148
162
  declare const TurnEvent: {
149
- readonly $is: <Tag extends "CitationAdded" | "ReasoningDelta" | "RefusalDelta" | "TextDelta" | "ToolCallArgsDelta" | "ToolCallStart" | "TurnComplete" | "UsageUpdate" | "WebSearchCall">(tag: Tag) => (u: unknown) => u is Extract<{
163
+ readonly $is: <Tag extends "CitationAdded" | "ImageOutput" | "ReasoningDelta" | "RefusalDelta" | "TextDelta" | "ToolCallArgsDelta" | "ToolCallStart" | "TurnComplete" | "UsageUpdate" | "WebSearchCall">(tag: Tag) => (u: unknown) => u is Extract<{
150
164
  readonly _tag: "CitationAdded";
151
165
  readonly annotation: Annotation;
152
166
  }, {
153
167
  readonly _tag: Tag;
168
+ }> | Extract<{
169
+ readonly _tag: "ImageOutput";
170
+ readonly image: ImageSource;
171
+ readonly partialIndex?: number;
172
+ }, {
173
+ readonly _tag: Tag;
154
174
  }> | Extract<{
155
175
  readonly _tag: "ReasoningDelta";
156
176
  readonly text: string;
@@ -198,9 +218,13 @@ declare const TurnEvent: {
198
218
  readonly _tag: Tag;
199
219
  }>;
200
220
  readonly $match: {
201
- <Cases extends { readonly [Tag in "CitationAdded" | "ReasoningDelta" | "RefusalDelta" | "TextDelta" | "ToolCallArgsDelta" | "ToolCallStart" | "TurnComplete" | "UsageUpdate" | "WebSearchCall"]: (args: Extract<{
221
+ <Cases extends { readonly [Tag in "CitationAdded" | "ImageOutput" | "ReasoningDelta" | "RefusalDelta" | "TextDelta" | "ToolCallArgsDelta" | "ToolCallStart" | "TurnComplete" | "UsageUpdate" | "WebSearchCall"]: (args: Extract<{
202
222
  readonly _tag: "CitationAdded";
203
223
  readonly annotation: Annotation;
224
+ } | {
225
+ readonly _tag: "ImageOutput";
226
+ readonly image: ImageSource;
227
+ readonly partialIndex?: number;
204
228
  } | {
205
229
  readonly _tag: "ReasoningDelta";
206
230
  readonly text: string;
@@ -235,6 +259,10 @@ declare const TurnEvent: {
235
259
  }>) => any; }>(cases: Cases): (value: {
236
260
  readonly _tag: "CitationAdded";
237
261
  readonly annotation: Annotation;
262
+ } | {
263
+ readonly _tag: "ImageOutput";
264
+ readonly image: ImageSource;
265
+ readonly partialIndex?: number;
238
266
  } | {
239
267
  readonly _tag: "ReasoningDelta";
240
268
  readonly text: string;
@@ -264,10 +292,14 @@ declare const TurnEvent: {
264
292
  readonly status: "started" | "searching" | "completed";
265
293
  readonly query?: string;
266
294
  readonly action?: "search" | "open_page" | "find_in_page";
267
- }) => import("effect/Unify").Unify<ReturnType<Cases["CitationAdded" | "ReasoningDelta" | "RefusalDelta" | "TextDelta" | "ToolCallArgsDelta" | "ToolCallStart" | "TurnComplete" | "UsageUpdate" | "WebSearchCall"]>>;
268
- <Cases extends { readonly [Tag in "CitationAdded" | "ReasoningDelta" | "RefusalDelta" | "TextDelta" | "ToolCallArgsDelta" | "ToolCallStart" | "TurnComplete" | "UsageUpdate" | "WebSearchCall"]: (args: Extract<{
295
+ }) => import("effect/Unify").Unify<ReturnType<Cases["CitationAdded" | "ImageOutput" | "ReasoningDelta" | "RefusalDelta" | "TextDelta" | "ToolCallArgsDelta" | "ToolCallStart" | "TurnComplete" | "UsageUpdate" | "WebSearchCall"]>>;
296
+ <Cases extends { readonly [Tag in "CitationAdded" | "ImageOutput" | "ReasoningDelta" | "RefusalDelta" | "TextDelta" | "ToolCallArgsDelta" | "ToolCallStart" | "TurnComplete" | "UsageUpdate" | "WebSearchCall"]: (args: Extract<{
269
297
  readonly _tag: "CitationAdded";
270
298
  readonly annotation: Annotation;
299
+ } | {
300
+ readonly _tag: "ImageOutput";
301
+ readonly image: ImageSource;
302
+ readonly partialIndex?: number;
271
303
  } | {
272
304
  readonly _tag: "ReasoningDelta";
273
305
  readonly text: string;
@@ -302,6 +334,10 @@ declare const TurnEvent: {
302
334
  }>) => any; }>(value: {
303
335
  readonly _tag: "CitationAdded";
304
336
  readonly annotation: Annotation;
337
+ } | {
338
+ readonly _tag: "ImageOutput";
339
+ readonly image: ImageSource;
340
+ readonly partialIndex?: number;
305
341
  } | {
306
342
  readonly _tag: "ReasoningDelta";
307
343
  readonly text: string;
@@ -331,12 +367,17 @@ declare const TurnEvent: {
331
367
  readonly status: "started" | "searching" | "completed";
332
368
  readonly query?: string;
333
369
  readonly action?: "search" | "open_page" | "find_in_page";
334
- }, cases: Cases): import("effect/Unify").Unify<ReturnType<Cases["CitationAdded" | "ReasoningDelta" | "RefusalDelta" | "TextDelta" | "ToolCallArgsDelta" | "ToolCallStart" | "TurnComplete" | "UsageUpdate" | "WebSearchCall"]>>;
370
+ }, cases: Cases): import("effect/Unify").Unify<ReturnType<Cases["CitationAdded" | "ImageOutput" | "ReasoningDelta" | "RefusalDelta" | "TextDelta" | "ToolCallArgsDelta" | "ToolCallStart" | "TurnComplete" | "UsageUpdate" | "WebSearchCall"]>>;
335
371
  };
336
372
  readonly CitationAdded: Data.TaggedEnum.ConstructorFrom<{
337
373
  readonly _tag: "CitationAdded";
338
374
  readonly annotation: Annotation;
339
375
  }, "_tag">;
376
+ readonly ImageOutput: Data.TaggedEnum.ConstructorFrom<{
377
+ readonly _tag: "ImageOutput";
378
+ readonly image: ImageSource;
379
+ readonly partialIndex?: number;
380
+ }, "_tag">;
340
381
  readonly ReasoningDelta: Data.TaggedEnum.ConstructorFrom<{
341
382
  readonly _tag: "ReasoningDelta";
342
383
  readonly text: string;
@@ -403,6 +444,29 @@ declare const assistantTexts: (turn: Turn) => ReadonlyArray<string>;
403
444
  * that want one concatenated string.
404
445
  */
405
446
  declare const assistantText: (turn: Turn) => string;
447
+ /**
448
+ * Every image the model produced this turn, in order. The counterpart to
449
+ * {@link assistantTexts}: each is an `ImageSource`, so it can be written
450
+ * to disk or passed straight back as an `input_image` on the next turn.
451
+ */
452
+ declare const assistantImages: (turn: Turn) => ReadonlyArray<ImageSource>;
453
+ /**
454
+ * Rewrite assistant `output_image` blocks into a user message carrying
455
+ * the same pictures as `input_image`, so another provider can look at
456
+ * what this one drew.
457
+ *
458
+ * Only Gemini's wire has an assistant-role image part; every other
459
+ * adapter omits an `output_image` on replay and says so. Moving it to a
460
+ * user message is the conversion that makes it portable, and it is
461
+ * yours to make rather than the adapter's: "the assistant drew this" and
462
+ * "here is an image, look at it" are different claims, and silently
463
+ * swapping one for the other behind your back would be the wrong kind of
464
+ * helpful.
465
+ *
466
+ * Items with no images pass through untouched, and the new user message
467
+ * follows the assistant message it came from.
468
+ */
469
+ declare const imagesAsInput: (history: ReadonlyArray<HistoryItem>) => ReadonlyArray<HistoryItem>;
406
470
  /**
407
471
  * Every citation annotation attached to the turn's assistant `output_text`
408
472
  * blocks, in order. The flat view of a grounded turn's sources, whether the
@@ -446,5 +510,5 @@ declare class RefusalRejected extends RefusalRejected_base<{
446
510
  */
447
511
  declare const decodeStructured: <A>(turn: Turn, format: StructuredFormat<A>) => Effect.Effect<A, RefusalRejected | JsonParseError | StructuredDecodeError>;
448
512
  //#endregion
449
- export { InteractionEvent, RefusalRejected, Turn, TurnEvent, appendToHistory, assistantMessages, assistantText, assistantTexts, citations, decodeStructured, getToolCalls, isTurnComplete, reasonings, Turn_d_exports as t, textDeltas };
513
+ export { InteractionEvent, RefusalRejected, Turn, TurnEvent, appendToHistory, assistantImages, assistantMessages, assistantText, assistantTexts, citations, decodeStructured, getToolCalls, imagesAsInput, isTurnComplete, reasonings, Turn_d_exports as t, textDeltas };
450
514
  //# sourceMappingURL=Turn.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Turn.d.mts","names":[],"sources":["../../src/domain/Turn.ts"],"mappings":";;;;;;;;;;;;cAsBa,MAAI,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAKL,cAAc,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA6BnB,YAAY,KAAK;EAC3B;aAAsB;;EACtB;aAA2B;aAAuB;;EAClD;aAAyB;;EACzB;aAA0B;aAA0B;;EACpD;aAA8B;aAA0B;;EACxD;aAAwB,OAAO;;EAC/B;aACW;aACA;aACA;;EAEX;aAA0B,YAAY;;EACtC;aAAyB,MAAM;;;cAGpB;;;aAJ2B,YAAA;;;;;aAVL;aAAuB;;;;;aACzB;;;;;aAFH;;;;;aAIW;aAAwB;;;;;aAD5B;aAAuB;;;;;aAS3B,MAAA;;;;;aAPA,OAAA;;;;;aAEZ;aACA;aACC;;;;;;;eAEkB,YAAA;;;eAVL;eAAuB;;;eACzB;;;eAFH;;;eAIW;eAAwB;;;eAD5B;eAAuB;;;eAS3B,MAAA;;;eAPA,OAAA;;;eAEZ;eACA;eACC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAEkB,YAAA;;;eAVL;eAAuB;;;eACzB;;;eAFH;;;eAIW;eAAwB;;;eAD5B;eAAuB;;;eAS3B,MAAA;;;eAPA,OAAA;;;eAEZ;eACA;eACC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAEkB,YAAA;;;;aAVL;aAAuB;;;;aACzB;;;;aAFH;;;;aAIW;aAAwB;;;;aAD5B;aAAuB;;;;aAS3B,MAAA;;;;aAPA,OAAA;;;;aAEZ;aACA;aACC;;;;;;;;;KAcV,mBAAmB,YAAY;cAE9B,iBAAc,eAAA;;WAbM,MAAA;;cAepB,eAAY,MAAU,SAAO,cAAc;cAE3C,aAAU,MAAU,SAAO,cAAc;cAEzC,oBAAiB,MAAU,SAAO,cAAc;;;;;;;;cAUhD,iBAAc,MAAU,SAAO;;;;;;cAW/B,gBAAa,MAAU;;;;;;cAOvB,YAAS,MAAU,SAAO,cAAc;;;;;;cAWxC,kBAAmB;WAAqB,SAAS,cAAc;GAAc,OACjF,GAAC,MACF,MAAI,QACH,cAAc,iBACpB;;;;;;cAcU,aAAc,GAAG,GAAC,MACvB,OAAO,OAAO,WAAW,GAAG,OACjC,OAAO,eAAe,GAAG;;;;;;;;;cAcf,wBAAwB;WAC1B,MAAM;;;;;;;;;;;;cAyBJ,mBAAoB,GAAC,MAC1B,MAAI,QACF,iBAAkC,OACzC,OAAO,OACR,GACA,kBAAkB,iBAAkC"}
1
+ {"version":3,"file":"Turn.d.mts","names":[],"sources":["../../src/domain/Turn.ts"],"mappings":";;;;;;;;;;;;cAwBa,MAAI,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAKL,cAAc,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAmCnB,YAAY,KAAK;EAC3B;aAAsB;;EACtB;aAA2B;aAAuB;;EAClD;aAAyB;;EACzB;aAA0B;aAA0B;;EACpD;aAA8B;aAA0B;;EACxD;aAAwB,OAAO;;EAC/B;aACW;aACA;aACA;;EAEX;aACW,OAAO;;aAEP;;EAEX;aAA0B,YAAY;;EACtC;aAAyB,MAAM;;;cAGpB;;;aAJ2B,YAAA;;;;;aAJpB,OAAA;aAEQ;;;;;aAbO;aAAuB;;;;;aACzB;;;;;aAFH;;;;;aAIW;aAAwB;;;;;aAD5B;aAAuB;;;;;aAc3B,MAAA;;;;;aAZA,OAAA;;;;;aAEZ;aACA;aACC;;;;;;;eAOkB,YAAA;;;eAJpB,OAAA;eAEQ;;;eAbO;eAAuB;;;eACzB;;;eAFH;;;eAIW;eAAwB;;;eAD5B;eAAuB;;;eAc3B,MAAA;;;eAZA,OAAA;;;eAEZ;eACA;eACC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAOkB,YAAA;;;eAJpB,OAAA;eAEQ;;;eAbO;eAAuB;;;eACzB;;;eAFH;;;eAIW;eAAwB;;;eAD5B;eAAuB;;;eAc3B,MAAA;;;eAZA,OAAA;;;eAEZ;eACA;eACC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAOkB,YAAA;;;;aAJpB,OAAA;aAEQ;;;;aAbO;aAAuB;;;;aACzB;;;;aAFH;;;;aAIW;aAAwB;;;;aAD5B;aAAuB;;;;aAc3B,MAAA;;;;aAZA,OAAA;;;;aAEZ;aACA;aACC;;;;;;;;;KAmBV,mBAAmB,YAAY;cAE9B,iBAAc,eAAA;;WAbM,MAAA;;cAepB,eAAY,MAAU,SAAO,cAAc;cAE3C,aAAU,MAAU,SAAO,cAAc;cAEzC,oBAAiB,MAAU,SAAO,cAAc;;;;;;;;cAUhD,iBAAc,MAAU,SAAO;;;;;;cAW/B,gBAAa,MAAU;;;;;;cAOvB,kBAAe,MAAU,SAAO,cAAc;;;;;;;;;;;;;;;;;cAsB9C,gBAAa,SAAa,cAAc,iBAAe,cAAc;;;;;;cAqBrE,YAAS,MAAU,SAAO,cAAc;;;;;;cAWxC,kBAAmB;WAAqB,SAAS,cAAc;GAAc,OACjF,GAAC,MACF,MAAI,QACH,cAAc,iBACpB;;;;;;cAcU,aAAc,GAAG,GAAC,MACvB,OAAO,OAAO,WAAW,GAAG,OACjC,OAAO,eAAe,GAAG;;;;;;;;;cAcf,wBAAwB;WAC1B,MAAM;;;;;;;;;;;;cAyBJ,mBAAoB,GAAC,MAC1B,MAAI,QACF,iBAAkC,OACzC,OAAO,OACR,GACA,kBAAkB,iBAAkC"}
@@ -1,5 +1,5 @@
1
1
  import { n as __exportAll } from "../rolldown-runtime-EAsCxrDo.mjs";
2
- import { HistoryItem, StopReason, Usage, isOutputText, isReasoning, isRefusal, isToolCall } from "./Items.mjs";
2
+ import { HistoryItem, StopReason, Usage, isOutputImage, isOutputText, isReasoning, isRefusal, isToolCall } from "./Items.mjs";
3
3
  import { parseJson } from "../structured-format/StructuredFormat.mjs";
4
4
  import { Data, Effect, Result, Schema, Stream, pipe } from "effect";
5
5
  //#region src/domain/Turn.ts
@@ -8,12 +8,14 @@ var Turn_exports = /* @__PURE__ */ __exportAll({
8
8
  Turn: () => Turn,
9
9
  TurnEvent: () => TurnEvent,
10
10
  appendToHistory: () => appendToHistory,
11
+ assistantImages: () => assistantImages,
11
12
  assistantMessages: () => assistantMessages,
12
13
  assistantText: () => assistantText,
13
14
  assistantTexts: () => assistantTexts,
14
15
  citations: () => citations,
15
16
  decodeStructured: () => decodeStructured,
16
17
  getToolCalls: () => getToolCalls,
18
+ imagesAsInput: () => imagesAsInput,
17
19
  isTurnComplete: () => isTurnComplete,
18
20
  reasonings: () => reasonings,
19
21
  textDeltas: () => textDeltas
@@ -48,6 +50,40 @@ const assistantTexts = (turn) => assistantMessages(turn).flatMap((m) => m.conten
48
50
  */
49
51
  const assistantText = (turn) => assistantTexts(turn).join("");
50
52
  /**
53
+ * Every image the model produced this turn, in order. The counterpart to
54
+ * {@link assistantTexts}: each is an `ImageSource`, so it can be written
55
+ * to disk or passed straight back as an `input_image` on the next turn.
56
+ */
57
+ const assistantImages = (turn) => assistantMessages(turn).flatMap((m) => m.content).filter(isOutputImage).map((b) => b.source);
58
+ /**
59
+ * Rewrite assistant `output_image` blocks into a user message carrying
60
+ * the same pictures as `input_image`, so another provider can look at
61
+ * what this one drew.
62
+ *
63
+ * Only Gemini's wire has an assistant-role image part; every other
64
+ * adapter omits an `output_image` on replay and says so. Moving it to a
65
+ * user message is the conversion that makes it portable, and it is
66
+ * yours to make rather than the adapter's: "the assistant drew this" and
67
+ * "here is an image, look at it" are different claims, and silently
68
+ * swapping one for the other behind your back would be the wrong kind of
69
+ * helpful.
70
+ *
71
+ * Items with no images pass through untouched, and the new user message
72
+ * follows the assistant message it came from.
73
+ */
74
+ const imagesAsInput = (history) => history.flatMap((item) => {
75
+ if (item.type !== "message" || item.role !== "assistant") return [item];
76
+ const images = item.content.filter(isOutputImage);
77
+ return images.length === 0 ? [item] : [item, {
78
+ type: "message",
79
+ role: "user",
80
+ content: images.map((b) => ({
81
+ type: "input_image",
82
+ source: b.source
83
+ }))
84
+ }];
85
+ });
86
+ /**
51
87
  * Every citation annotation attached to the turn's assistant `output_text`
52
88
  * blocks, in order. The flat view of a grounded turn's sources, whether the
53
89
  * turn came from a normal generation with native search or a deep-research job.
@@ -106,6 +142,6 @@ const lastAssistantContent = (turn) => {
106
142
  */
107
143
  const decodeStructured = (turn, format) => pipe(lastAssistantContent(turn), ({ text, refused }) => refused ? Effect.fail(new RefusalRejected({ turn })) : parseJson(format)(text));
108
144
  //#endregion
109
- export { RefusalRejected, Turn, TurnEvent, appendToHistory, assistantMessages, assistantText, assistantTexts, citations, decodeStructured, getToolCalls, isTurnComplete, reasonings, Turn_exports as t, textDeltas };
145
+ export { RefusalRejected, Turn, TurnEvent, appendToHistory, assistantImages, assistantMessages, assistantText, assistantTexts, citations, decodeStructured, getToolCalls, imagesAsInput, isTurnComplete, reasonings, Turn_exports as t, textDeltas };
110
146
 
111
147
  //# sourceMappingURL=Turn.mjs.map