@effect-uai/ai-sdk 0.19.0-dev-20261110065930 → 0.19.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"Messages.d.mts","names":[],"sources":["../src/Messages.ts"],"mappings":";;;;;cAqBM,UAAQ,OAAA;;;;KAIF,kBAAkB,SAAS;cAEjC,UAAQ,OAAA;;;;;KAKF,kBAAkB,SAAS;cAEjC,UAAQ,OAAA;;;;;;;;KAQF,kBAAkB,SAAS;KAS3B;WACD;YACC;;KAGA;WACD;WACA;WACA,OAAO,cAAc;;cAuEnB,iBAAc,UACf,cAAc,eACvB,cAAc,MAAM"}
1
+ {"version":3,"file":"Messages.d.mts","names":[],"sources":["../src/Messages.ts"],"mappings":";;;;;cAqBa,UAAQ,OAAA;;;;KAIT,kBAAkB,SAAS;cAE1B,UAAQ,OAAA;;;;;KAKT,kBAAkB,SAAS;cAE1B,UAAQ,OAAA;;;;;;;;KAQT,kBAAkB,SAAS;KAS3B;WACD;YACC;;KAGA;WACD;WACA;WACA,OAAO,cAAc;;cAuEnB,iBAAc,UACf,cAAc,eACvB,cAAc,MAAM"}
package/dist/Messages.mjs CHANGED
@@ -14,7 +14,12 @@ import { Match, Option, Predicate, Schema } from "effect";
14
14
  * (`file` with an `image/*` media type) parts fold into a message's content;
15
15
  * non-image files and unresolved tool states are dropped.
16
16
  */
17
- var Messages_exports = /* @__PURE__ */ __exportAll({ decodeMessages: () => decodeMessages });
17
+ var Messages_exports = /* @__PURE__ */ __exportAll({
18
+ FilePart: () => FilePart,
19
+ TextPart: () => TextPart,
20
+ ToolPart: () => ToolPart,
21
+ decodeMessages: () => decodeMessages
22
+ });
18
23
  const asJson = Schema.decodeUnknownOption(Schema.Json);
19
24
  const TextPart = Schema.Struct({
20
25
  type: Schema.Literal("text"),
@@ -79,6 +84,6 @@ const assistantItems = (message) => {
79
84
  const decodeMessage = (message) => Match.value(message.role).pipe(Match.when("user", () => [userMessage(message)]), Match.when("system", () => [Items.systemText(textOf(message))]), Match.when("assistant", () => assistantItems(message)), Match.exhaustive);
80
85
  const decodeMessages = (messages) => messages.flatMap(decodeMessage);
81
86
  //#endregion
82
- export { decodeMessages, Messages_exports as t };
87
+ export { FilePart, TextPart, ToolPart, decodeMessages, Messages_exports as t };
83
88
 
84
89
  //# sourceMappingURL=Messages.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Messages.mjs","names":[],"sources":["../src/Messages.ts"],"sourcesContent":["/**\n * Decode the `messages` array a `useChat` client POSTs (Vercel's `UIMessage`\n * shape) back into effect-uai `HistoryItem`s, so an existing loop can run\n * against an unchanged frontend.\n *\n * One `UIMessage` can expand to several history items: an assistant message\n * carrying tool calls becomes an assistant `Message` followed by the\n * `ToolCall` / `ToolCallOutput` items the model needs to see. Text and image\n * (`file` with an `image/*` media type) parts fold into a message's content;\n * non-image files and unresolved tool states are dropped.\n */\nimport * as Image from \"@effect-uai/core/Image\"\nimport * as Items from \"@effect-uai/core/Items\"\nimport { Match, Option, Predicate, Schema } from \"effect\"\n\nconst asJson = Schema.decodeUnknownOption(Schema.Json)\n\n// The inbound part variants we understand. Tool parts are identified\n// structurally by `toolCallId` - their wire `type` is a dynamic `tool-<name>`\n// (or `dynamic-tool`) rather than a fixed literal - so their schema keeps\n// `type` open and reads the name off it.\nconst TextPart = Schema.Struct({\n type: Schema.Literal(\"text\"),\n text: Schema.String,\n})\nexport type TextPart = typeof TextPart.Type\n\nconst FilePart = Schema.Struct({\n type: Schema.Literal(\"file\"),\n mediaType: Schema.String,\n url: Schema.String,\n})\nexport type FilePart = typeof FilePart.Type\n\nconst ToolPart = Schema.Struct({\n type: Schema.String,\n toolCallId: Schema.String,\n toolName: Schema.optional(Schema.String),\n state: Schema.optional(Schema.String),\n input: Schema.optional(Schema.Unknown),\n output: Schema.optional(Schema.Unknown),\n})\nexport type ToolPart = typeof ToolPart.Type\n\nconst isText = Schema.is(TextPart)\nconst isFile = Schema.is(FilePart)\nconst isTool = Schema.is(ToolPart)\nconst isImageFile = (part: FilePart): boolean => part.mediaType.startsWith(\"image\")\n\n// A raw inbound part: a discriminating `type` plus whatever else the client\n// attached. Kept open so the schema guards do the narrowing.\nexport type UIPart = {\n readonly type: string\n readonly [key: string]: unknown\n}\n\nexport type UIMessage = {\n readonly id?: string\n readonly role: \"user\" | \"assistant\" | \"system\"\n readonly parts: ReadonlyArray<UIPart>\n}\n\nconst textOf = (message: UIMessage): string =>\n message.parts\n .filter(isText)\n .map((part) => part.text)\n .join(\"\")\n\nconst imageBlocks = (message: UIMessage): ReadonlyArray<Items.InputImage> =>\n message.parts\n .filter(isFile)\n .filter(isImageFile)\n .map((part) => ({ type: \"input_image\", source: Image.imageUrl(part.url, part.mediaType) }))\n\n// A user turn: one joined text block (if any) followed by one image block per\n// image file, preserving the model's expectation of text-then-media.\nconst userMessage = (message: UIMessage): Items.Message => {\n const text = textOf(message)\n return {\n type: \"message\",\n role: \"user\",\n content: [\n ...(text.length > 0 ? [{ type: \"input_text\", text } as const] : []),\n ...imageBlocks(message),\n ],\n }\n}\n\nconst toolName = (part: ToolPart): string =>\n part.type === \"dynamic-tool\" ? (part.toolName ?? \"\") : part.type.slice(\"tool-\".length)\n\n// A resolved tool call becomes a `function_call` item, plus a\n// `function_call_output` once the client carries its output.\nconst toolItems = (part: ToolPart): ReadonlyArray<Items.HistoryItem> => {\n const call: Items.ToolCall = {\n type: \"function_call\",\n call_id: part.toolCallId,\n name: toolName(part),\n arguments: JSON.stringify(part.input ?? {}),\n }\n if (part.state !== \"output-available\") return [call]\n // Text stays text; any other JSON stays a value (the provider codec serializes it).\n const output: Items.ToolOutputContent = Match.value(part.output).pipe(\n Match.when(Predicate.isString, (text) => Items.text(text)),\n Match.orElse((value) =>\n Option.match(asJson(value), {\n onNone: () => Items.text(String(value)),\n onSome: (json) => Items.json(json),\n }),\n ),\n )\n return [call, { type: \"function_call_output\", call_id: part.toolCallId, output: [output] }]\n}\n\nconst assistantItems = (message: UIMessage): ReadonlyArray<Items.HistoryItem> => {\n const text = textOf(message)\n return [\n ...(text.length > 0 ? [Items.assistantText(text)] : []),\n ...message.parts.filter(isTool).flatMap(toolItems),\n ]\n}\n\nconst decodeMessage = (message: UIMessage): ReadonlyArray<Items.HistoryItem> =>\n Match.value(message.role).pipe(\n Match.when(\"user\", () => [userMessage(message)]),\n Match.when(\"system\", () => [Items.systemText(textOf(message))]),\n Match.when(\"assistant\", () => assistantItems(message)),\n Match.exhaustive,\n )\n\nexport const decodeMessages = (\n messages: ReadonlyArray<UIMessage>,\n): ReadonlyArray<Items.HistoryItem> => messages.flatMap(decodeMessage)\n"],"mappings":";;;;;;;;;;;;;;;;;AAeA,MAAM,SAAS,OAAO,oBAAoB,OAAO,IAAI;AAMrD,MAAM,WAAW,OAAO,OAAO;CAC7B,MAAM,OAAO,QAAQ,MAAM;CAC3B,MAAM,OAAO;AACf,CAAC;AAGD,MAAM,WAAW,OAAO,OAAO;CAC7B,MAAM,OAAO,QAAQ,MAAM;CAC3B,WAAW,OAAO;CAClB,KAAK,OAAO;AACd,CAAC;AAGD,MAAM,WAAW,OAAO,OAAO;CAC7B,MAAM,OAAO;CACb,YAAY,OAAO;CACnB,UAAU,OAAO,SAAS,OAAO,MAAM;CACvC,OAAO,OAAO,SAAS,OAAO,MAAM;CACpC,OAAO,OAAO,SAAS,OAAO,OAAO;CACrC,QAAQ,OAAO,SAAS,OAAO,OAAO;AACxC,CAAC;AAGD,MAAM,SAAS,OAAO,GAAG,QAAQ;AACjC,MAAM,SAAS,OAAO,GAAG,QAAQ;AACjC,MAAM,SAAS,OAAO,GAAG,QAAQ;AACjC,MAAM,eAAe,SAA4B,KAAK,UAAU,WAAW,OAAO;AAelF,MAAM,UAAU,YACd,QAAQ,MACL,OAAO,MAAM,CAAC,CACd,KAAK,SAAS,KAAK,IAAI,CAAC,CACxB,KAAK,EAAE;AAEZ,MAAM,eAAe,YACnB,QAAQ,MACL,OAAO,MAAM,CAAC,CACd,OAAO,WAAW,CAAC,CACnB,KAAK,UAAU;CAAE,MAAM;CAAe,QAAQ,MAAM,SAAS,KAAK,KAAK,KAAK,SAAS;AAAE,EAAE;AAI9F,MAAM,eAAe,YAAsC;CACzD,MAAM,OAAO,OAAO,OAAO;CAC3B,OAAO;EACL,MAAM;EACN,MAAM;EACN,SAAS,CACP,GAAI,KAAK,SAAS,IAAI,CAAC;GAAE,MAAM;GAAc;EAAK,CAAU,IAAI,CAAC,GACjE,GAAG,YAAY,OAAO,CACxB;CACF;AACF;AAEA,MAAM,YAAY,SAChB,KAAK,SAAS,iBAAkB,KAAK,YAAY,KAAM,KAAK,KAAK,MAAM,CAAc;AAIvF,MAAM,aAAa,SAAqD;CACtE,MAAM,OAAuB;EAC3B,MAAM;EACN,SAAS,KAAK;EACd,MAAM,SAAS,IAAI;EACnB,WAAW,KAAK,UAAU,KAAK,SAAS,CAAC,CAAC;CAC5C;CACA,IAAI,KAAK,UAAU,oBAAoB,OAAO,CAAC,IAAI;CAEnD,MAAM,SAAkC,MAAM,MAAM,KAAK,MAAM,CAAC,CAAC,KAC/D,MAAM,KAAK,UAAU,WAAW,SAAS,MAAM,KAAK,IAAI,CAAC,GACzD,MAAM,QAAQ,UACZ,OAAO,MAAM,OAAO,KAAK,GAAG;EAC1B,cAAc,MAAM,KAAK,OAAO,KAAK,CAAC;EACtC,SAAS,SAAS,MAAM,KAAK,IAAI;CACnC,CAAC,CACH,CACF;CACA,OAAO,CAAC,MAAM;EAAE,MAAM;EAAwB,SAAS,KAAK;EAAY,QAAQ,CAAC,MAAM;CAAE,CAAC;AAC5F;AAEA,MAAM,kBAAkB,YAAyD;CAC/E,MAAM,OAAO,OAAO,OAAO;CAC3B,OAAO,CACL,GAAI,KAAK,SAAS,IAAI,CAAC,MAAM,cAAc,IAAI,CAAC,IAAI,CAAC,GACrD,GAAG,QAAQ,MAAM,OAAO,MAAM,CAAC,CAAC,QAAQ,SAAS,CACnD;AACF;AAEA,MAAM,iBAAiB,YACrB,MAAM,MAAM,QAAQ,IAAI,CAAC,CAAC,KACxB,MAAM,KAAK,cAAc,CAAC,YAAY,OAAO,CAAC,CAAC,GAC/C,MAAM,KAAK,gBAAgB,CAAC,MAAM,WAAW,OAAO,OAAO,CAAC,CAAC,CAAC,GAC9D,MAAM,KAAK,mBAAmB,eAAe,OAAO,CAAC,GACrD,MAAM,UACR;AAEF,MAAa,kBACX,aACqC,SAAS,QAAQ,aAAa"}
1
+ {"version":3,"file":"Messages.mjs","names":[],"sources":["../src/Messages.ts"],"sourcesContent":["/**\n * Decode the `messages` array a `useChat` client POSTs (Vercel's `UIMessage`\n * shape) back into effect-uai `HistoryItem`s, so an existing loop can run\n * against an unchanged frontend.\n *\n * One `UIMessage` can expand to several history items: an assistant message\n * carrying tool calls becomes an assistant `Message` followed by the\n * `ToolCall` / `ToolCallOutput` items the model needs to see. Text and image\n * (`file` with an `image/*` media type) parts fold into a message's content;\n * non-image files and unresolved tool states are dropped.\n */\nimport * as Image from \"@effect-uai/core/Image\"\nimport * as Items from \"@effect-uai/core/Items\"\nimport { Match, Option, Predicate, Schema } from \"effect\"\n\nconst asJson = Schema.decodeUnknownOption(Schema.Json)\n\n// The inbound part variants we understand. Tool parts are identified\n// structurally by `toolCallId` - their wire `type` is a dynamic `tool-<name>`\n// (or `dynamic-tool`) rather than a fixed literal - so their schema keeps\n// `type` open and reads the name off it.\nexport const TextPart = Schema.Struct({\n type: Schema.Literal(\"text\"),\n text: Schema.String,\n})\nexport type TextPart = typeof TextPart.Type\n\nexport const FilePart = Schema.Struct({\n type: Schema.Literal(\"file\"),\n mediaType: Schema.String,\n url: Schema.String,\n})\nexport type FilePart = typeof FilePart.Type\n\nexport const ToolPart = Schema.Struct({\n type: Schema.String,\n toolCallId: Schema.String,\n toolName: Schema.optional(Schema.String),\n state: Schema.optional(Schema.String),\n input: Schema.optional(Schema.Unknown),\n output: Schema.optional(Schema.Unknown),\n})\nexport type ToolPart = typeof ToolPart.Type\n\nconst isText = Schema.is(TextPart)\nconst isFile = Schema.is(FilePart)\nconst isTool = Schema.is(ToolPart)\nconst isImageFile = (part: FilePart): boolean => part.mediaType.startsWith(\"image\")\n\n// A raw inbound part: a discriminating `type` plus whatever else the client\n// attached. Kept open so the schema guards do the narrowing.\nexport type UIPart = {\n readonly type: string\n readonly [key: string]: unknown\n}\n\nexport type UIMessage = {\n readonly id?: string\n readonly role: \"user\" | \"assistant\" | \"system\"\n readonly parts: ReadonlyArray<UIPart>\n}\n\nconst textOf = (message: UIMessage): string =>\n message.parts\n .filter(isText)\n .map((part) => part.text)\n .join(\"\")\n\nconst imageBlocks = (message: UIMessage): ReadonlyArray<Items.InputImage> =>\n message.parts\n .filter(isFile)\n .filter(isImageFile)\n .map((part) => ({ type: \"input_image\", source: Image.imageUrl(part.url, part.mediaType) }))\n\n// A user turn: one joined text block (if any) followed by one image block per\n// image file, preserving the model's expectation of text-then-media.\nconst userMessage = (message: UIMessage): Items.Message => {\n const text = textOf(message)\n return {\n type: \"message\",\n role: \"user\",\n content: [\n ...(text.length > 0 ? [{ type: \"input_text\", text } as const] : []),\n ...imageBlocks(message),\n ],\n }\n}\n\nconst toolName = (part: ToolPart): string =>\n part.type === \"dynamic-tool\" ? (part.toolName ?? \"\") : part.type.slice(\"tool-\".length)\n\n// A resolved tool call becomes a `function_call` item, plus a\n// `function_call_output` once the client carries its output.\nconst toolItems = (part: ToolPart): ReadonlyArray<Items.HistoryItem> => {\n const call: Items.ToolCall = {\n type: \"function_call\",\n call_id: part.toolCallId,\n name: toolName(part),\n arguments: JSON.stringify(part.input ?? {}),\n }\n if (part.state !== \"output-available\") return [call]\n // Text stays text; any other JSON stays a value (the provider codec serializes it).\n const output: Items.ToolOutputContent = Match.value(part.output).pipe(\n Match.when(Predicate.isString, (text) => Items.text(text)),\n Match.orElse((value) =>\n Option.match(asJson(value), {\n onNone: () => Items.text(String(value)),\n onSome: (json) => Items.json(json),\n }),\n ),\n )\n return [call, { type: \"function_call_output\", call_id: part.toolCallId, output: [output] }]\n}\n\nconst assistantItems = (message: UIMessage): ReadonlyArray<Items.HistoryItem> => {\n const text = textOf(message)\n return [\n ...(text.length > 0 ? [Items.assistantText(text)] : []),\n ...message.parts.filter(isTool).flatMap(toolItems),\n ]\n}\n\nconst decodeMessage = (message: UIMessage): ReadonlyArray<Items.HistoryItem> =>\n Match.value(message.role).pipe(\n Match.when(\"user\", () => [userMessage(message)]),\n Match.when(\"system\", () => [Items.systemText(textOf(message))]),\n Match.when(\"assistant\", () => assistantItems(message)),\n Match.exhaustive,\n )\n\nexport const decodeMessages = (\n messages: ReadonlyArray<UIMessage>,\n): ReadonlyArray<Items.HistoryItem> => messages.flatMap(decodeMessage)\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAeA,MAAM,SAAS,OAAO,oBAAoB,OAAO,IAAI;AAMrD,MAAa,WAAW,OAAO,OAAO;CACpC,MAAM,OAAO,QAAQ,MAAM;CAC3B,MAAM,OAAO;AACf,CAAC;AAGD,MAAa,WAAW,OAAO,OAAO;CACpC,MAAM,OAAO,QAAQ,MAAM;CAC3B,WAAW,OAAO;CAClB,KAAK,OAAO;AACd,CAAC;AAGD,MAAa,WAAW,OAAO,OAAO;CACpC,MAAM,OAAO;CACb,YAAY,OAAO;CACnB,UAAU,OAAO,SAAS,OAAO,MAAM;CACvC,OAAO,OAAO,SAAS,OAAO,MAAM;CACpC,OAAO,OAAO,SAAS,OAAO,OAAO;CACrC,QAAQ,OAAO,SAAS,OAAO,OAAO;AACxC,CAAC;AAGD,MAAM,SAAS,OAAO,GAAG,QAAQ;AACjC,MAAM,SAAS,OAAO,GAAG,QAAQ;AACjC,MAAM,SAAS,OAAO,GAAG,QAAQ;AACjC,MAAM,eAAe,SAA4B,KAAK,UAAU,WAAW,OAAO;AAelF,MAAM,UAAU,YACd,QAAQ,MACL,OAAO,MAAM,CAAC,CACd,KAAK,SAAS,KAAK,IAAI,CAAC,CACxB,KAAK,EAAE;AAEZ,MAAM,eAAe,YACnB,QAAQ,MACL,OAAO,MAAM,CAAC,CACd,OAAO,WAAW,CAAC,CACnB,KAAK,UAAU;CAAE,MAAM;CAAe,QAAQ,MAAM,SAAS,KAAK,KAAK,KAAK,SAAS;AAAE,EAAE;AAI9F,MAAM,eAAe,YAAsC;CACzD,MAAM,OAAO,OAAO,OAAO;CAC3B,OAAO;EACL,MAAM;EACN,MAAM;EACN,SAAS,CACP,GAAI,KAAK,SAAS,IAAI,CAAC;GAAE,MAAM;GAAc;EAAK,CAAU,IAAI,CAAC,GACjE,GAAG,YAAY,OAAO,CACxB;CACF;AACF;AAEA,MAAM,YAAY,SAChB,KAAK,SAAS,iBAAkB,KAAK,YAAY,KAAM,KAAK,KAAK,MAAM,CAAc;AAIvF,MAAM,aAAa,SAAqD;CACtE,MAAM,OAAuB;EAC3B,MAAM;EACN,SAAS,KAAK;EACd,MAAM,SAAS,IAAI;EACnB,WAAW,KAAK,UAAU,KAAK,SAAS,CAAC,CAAC;CAC5C;CACA,IAAI,KAAK,UAAU,oBAAoB,OAAO,CAAC,IAAI;CAEnD,MAAM,SAAkC,MAAM,MAAM,KAAK,MAAM,CAAC,CAAC,KAC/D,MAAM,KAAK,UAAU,WAAW,SAAS,MAAM,KAAK,IAAI,CAAC,GACzD,MAAM,QAAQ,UACZ,OAAO,MAAM,OAAO,KAAK,GAAG;EAC1B,cAAc,MAAM,KAAK,OAAO,KAAK,CAAC;EACtC,SAAS,SAAS,MAAM,KAAK,IAAI;CACnC,CAAC,CACH,CACF;CACA,OAAO,CAAC,MAAM;EAAE,MAAM;EAAwB,SAAS,KAAK;EAAY,QAAQ,CAAC,MAAM;CAAE,CAAC;AAC5F;AAEA,MAAM,kBAAkB,YAAyD;CAC/E,MAAM,OAAO,OAAO,OAAO;CAC3B,OAAO,CACL,GAAI,KAAK,SAAS,IAAI,CAAC,MAAM,cAAc,IAAI,CAAC,IAAI,CAAC,GACrD,GAAG,QAAQ,MAAM,OAAO,MAAM,CAAC,CAAC,QAAQ,SAAS,CACnD;AACF;AAEA,MAAM,iBAAiB,YACrB,MAAM,MAAM,QAAQ,IAAI,CAAC,CAAC,KACxB,MAAM,KAAK,cAAc,CAAC,YAAY,OAAO,CAAC,CAAC,GAC/C,MAAM,KAAK,gBAAgB,CAAC,MAAM,WAAW,OAAO,OAAO,CAAC,CAAC,CAAC,GAC9D,MAAM,KAAK,mBAAmB,eAAe,OAAO,CAAC,GACrD,MAAM,UACR;AAEF,MAAa,kBACX,aACqC,SAAS,QAAQ,aAAa"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-uai/ai-sdk",
3
- "version": "0.19.0-dev-20261110065930",
3
+ "version": "0.19.1",
4
4
  "description": "Vercel AI SDK (useChat) UI Message Stream compatibility for @effect-uai/core.",
5
5
  "keywords": [
6
6
  "agents",
@@ -53,10 +53,10 @@
53
53
  "ai": "^7.0.3",
54
54
  "effect": "4.1.2",
55
55
  "typescript": "^7.0.2",
56
- "@effect-uai/core": "0.19.0-dev-20261110065930"
56
+ "@effect-uai/core": "0.19.1"
57
57
  },
58
58
  "peerDependencies": {
59
- "@effect-uai/core": "0.19.0-dev-20261110065930",
59
+ "@effect-uai/core": ">=0.5.0 <1",
60
60
  "effect": ">=4.0.1 <5.0.0"
61
61
  },
62
62
  "scripts": {
package/src/Messages.ts CHANGED
@@ -19,20 +19,20 @@ const asJson = Schema.decodeUnknownOption(Schema.Json)
19
19
  // structurally by `toolCallId` - their wire `type` is a dynamic `tool-<name>`
20
20
  // (or `dynamic-tool`) rather than a fixed literal - so their schema keeps
21
21
  // `type` open and reads the name off it.
22
- const TextPart = Schema.Struct({
22
+ export const TextPart = Schema.Struct({
23
23
  type: Schema.Literal("text"),
24
24
  text: Schema.String,
25
25
  })
26
26
  export type TextPart = typeof TextPart.Type
27
27
 
28
- const FilePart = Schema.Struct({
28
+ export const FilePart = Schema.Struct({
29
29
  type: Schema.Literal("file"),
30
30
  mediaType: Schema.String,
31
31
  url: Schema.String,
32
32
  })
33
33
  export type FilePart = typeof FilePart.Type
34
34
 
35
- const ToolPart = Schema.Struct({
35
+ export const ToolPart = Schema.Struct({
36
36
  type: Schema.String,
37
37
  toolCallId: Schema.String,
38
38
  toolName: Schema.optional(Schema.String),