@effect-uai/ai-sdk 0.19.0 → 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.
- package/dist/Messages.d.mts.map +1 -1
- package/dist/Messages.mjs +7 -2
- package/dist/Messages.mjs.map +1 -1
- package/package.json +2 -2
- package/src/Messages.ts +3 -3
package/dist/Messages.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Messages.d.mts","names":[],"sources":["../src/Messages.ts"],"mappings":";;;;;
|
|
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({
|
|
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
|
package/dist/Messages.mjs.map
CHANGED
|
@@ -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.\
|
|
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.
|
|
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,7 +53,7 @@
|
|
|
53
53
|
"ai": "^7.0.3",
|
|
54
54
|
"effect": "4.1.2",
|
|
55
55
|
"typescript": "^7.0.2",
|
|
56
|
-
"@effect-uai/core": "0.19.
|
|
56
|
+
"@effect-uai/core": "0.19.1"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@effect-uai/core": ">=0.5.0 <1",
|
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),
|