@assistant-ui/core 0.3.7 → 0.3.8
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/LICENSE +21 -0
- package/dist/react/runtimes/cloud/auiV0.d.ts +1 -0
- package/dist/react/runtimes/cloud/auiV0.d.ts.map +1 -1
- package/dist/react/runtimes/cloud/auiV0.js +2 -1
- package/dist/react/runtimes/cloud/auiV0.js.map +1 -1
- package/dist/runtime/base/base-composer-runtime-core.d.ts +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.d.ts +0 -2
- package/dist/runtime/base/default-edit-composer-runtime-core.d.ts.map +1 -1
- package/dist/runtime/base/default-edit-composer-runtime-core.js +18 -25
- package/dist/runtime/base/default-edit-composer-runtime-core.js.map +1 -1
- package/dist/runtime/utils/thread-message-like.js +3 -1
- package/dist/runtime/utils/thread-message-like.js.map +1 -1
- package/dist/types/message.d.ts +1 -0
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/message.js.map +1 -1
- package/package.json +15 -15
- package/src/react/runtimes/cloud/auiV0.ts +8 -1
- package/src/runtime/base/default-edit-composer-runtime-core.ts +32 -50
- package/src/runtime/utils/thread-message-like.ts +5 -1
- package/src/store/runtime-clients/lookup-domains.test.ts +109 -0
- package/src/tests/auiV0Encode.test.ts +97 -0
- package/src/tests/default-edit-composer-runtime-core.test.ts +6 -2
- package/src/tests/thread-message-like.test.ts +43 -0
- package/src/types/message.ts +1 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 AgentbaseAI Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auiV0.d.ts","names":[],"sources":["../../../../src/react/runtimes/cloud/auiV0.ts"],"mappings":";;;;;;KAgBK;WACM;WACA;WACA;WACA;WACA,mBAAmB;WACnB;WACA;;KAGN;WAEU;WACA;;WAGA;WACA;;WAGA;WACA;WACA;WACA;WACA;WACA,mBAAmB;;WAGnB;WACA;WACA;WACA;WACA;WACA;WACA,mBAAmB;;WAGnB;WACA;WACA;WACA,MAAM;WACN,SAAS;WACT;WACA,WAAW;;WAGX;WACA;WACA;WACA;WACA,SAAS;WACT;WACA,WAAW;;WAGX;WACA;;WAGA;WACA;WACA;WACA;WACA;;KAGV;WAEU;WACA;;WAGA;WACA;WACA;;WAGA;WACA;WACA;WACA;WACA;;WAGA;WACA;aACE;aACA;;;WAIF;WACA;WACA,MAAM;;KAGhB;WACM;WACA,MAAM;WACN;WACA;WACA,QAAQ;WACR,kBAAkB;;KAGxB;WACM;WACA,SAAS;WACT,kBAAkB;WAClB,uBAAuB;WACvB;aACE,iBAAiB;aACjB,+BAA+B;aAC/B,wBAAwB;aACxB;eACE;iBACE;iBACA;;;aAGJ,QAAQ;;;iBA2EL,YAAY,SAAS,gBAAgB;
|
|
1
|
+
{"version":3,"file":"auiV0.d.ts","names":[],"sources":["../../../../src/react/runtimes/cloud/auiV0.ts"],"mappings":";;;;;;KAgBK;WACM;WACA;WACA;WACA;WACA,mBAAmB;WACnB;WACA;;KAGN;WAEU;WACA;;WAGA;WACA;WACA;;WAGA;WACA;WACA;WACA;WACA;WACA,mBAAmB;;WAGnB;WACA;WACA;WACA;WACA;WACA;WACA,mBAAmB;;WAGnB;WACA;WACA;WACA,MAAM;WACN,SAAS;WACT;WACA,WAAW;;WAGX;WACA;WACA;WACA;WACA,SAAS;WACT;WACA,WAAW;;WAGX;WACA;;WAGA;WACA;WACA;WACA;WACA;;KAGV;WAEU;WACA;;WAGA;WACA;WACA;;WAGA;WACA;WACA;WACA;WACA;;WAGA;WACA;aACE;aACA;;;WAIF;WACA;WACA,MAAM;;KAGhB;WACM;WACA,MAAM;WACN;WACA;WACA,QAAQ;WACR,kBAAkB;;KAGxB;WACM;WACA,SAAS;WACT,kBAAkB;WAClB,uBAAuB;WACvB;aACE,iBAAiB;aACjB,+BAA+B;aAC/B,wBAAwB;aACxB;eACE;iBACE;iBACA;;;aAGJ,QAAQ;;;iBA2EL,YAAY,SAAS,gBAAgB;iBAoGrC,YACd,cAAc;EAAiB;IAC9B"}
|
|
@@ -65,7 +65,8 @@ function auiV0Encode(message) {
|
|
|
65
65
|
};
|
|
66
66
|
case "reasoning": return {
|
|
67
67
|
type: "reasoning",
|
|
68
|
-
text: part.text
|
|
68
|
+
text: part.text,
|
|
69
|
+
...part.unstable_summary !== void 0 ? { unstable_summary: part.unstable_summary } : void 0
|
|
69
70
|
};
|
|
70
71
|
case "source":
|
|
71
72
|
if (part.sourceType === "url") return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auiV0.js","names":["MessageStatus","SourceProviderMetadata","ThreadMessage","ToolApprovalOption","CompleteAttachment","fromThreadMessageLike","CloudMessage","isJSONValue","ReadonlyJSONObject","ReadonlyJSONValue","ExportedMessageRepositoryItem","AuiV0ToolApproval","id","approved","reason","isAutomatic","options","optionId","resolution","AuiV0MessagePart","type","text","sourceType","url","title","providerMetadata","mediaType","filename","toolCallId","toolName","args","result","isError","approval","argsText","image","data","mimeType","AuiV0AttachmentPart","audio","format","name","AuiV0Attachment","contentType","status","content","AuiV0Message","role","attachments","metadata","unstable_state","unstable_annotations","unstable_data","steps","usage","inputTokens","outputTokens","custom","encodeAttachmentPart","part","undefined","console","warn","JSON","stringify","unhandledType","Error","encodeAttachments","message","length","map","auiV0Encode","auiV0Decode","cloudMessage","payload","createdAt","created_at","parentId","parent_id"],"sources":["../../../../src/react/runtimes/cloud/auiV0.ts"],"sourcesContent":["import type {\n MessageStatus,\n SourceProviderMetadata,\n ThreadMessage,\n ToolApprovalOption,\n} from \"../../../types/message\";\nimport type { CompleteAttachment } from \"../../../types/attachment\";\nimport { fromThreadMessageLike } from \"../../../runtime/utils/thread-message-like\";\nimport type { CloudMessage } from \"assistant-cloud\";\nimport { isJSONValue } from \"../../../utils/json/is-json\";\nimport type {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"assistant-stream/utils\";\nimport type { ExportedMessageRepositoryItem } from \"../../../runtime/utils/message-repository\";\n\ntype AuiV0ToolApproval = {\n readonly id: string;\n readonly approved?: boolean;\n readonly reason?: string;\n readonly isAutomatic?: boolean;\n readonly options?: readonly ToolApprovalOption[];\n readonly optionId?: string;\n readonly resolution?: \"cancelled\" | \"expired\";\n};\n\ntype AuiV0MessagePart =\n | {\n readonly type: \"text\";\n readonly text: string;\n }\n | {\n readonly type: \"reasoning\";\n readonly text: string;\n }\n | {\n readonly type: \"source\";\n readonly sourceType: \"url\";\n readonly id: string;\n readonly url: string;\n readonly title?: string;\n readonly providerMetadata?: SourceProviderMetadata;\n }\n | {\n readonly type: \"source\";\n readonly sourceType: \"document\";\n readonly id: string;\n readonly title: string;\n readonly mediaType: string;\n readonly filename?: string;\n readonly providerMetadata?: SourceProviderMetadata;\n }\n | {\n readonly type: \"tool-call\";\n readonly toolCallId: string;\n readonly toolName: string;\n readonly args: ReadonlyJSONObject;\n readonly result?: ReadonlyJSONValue;\n readonly isError?: true;\n readonly approval?: AuiV0ToolApproval;\n }\n | {\n readonly type: \"tool-call\";\n readonly toolCallId: string;\n readonly toolName: string;\n readonly argsText: string;\n readonly result?: ReadonlyJSONValue;\n readonly isError?: true;\n readonly approval?: AuiV0ToolApproval;\n }\n | {\n readonly type: \"image\";\n readonly image: string;\n }\n | {\n readonly type: \"file\";\n readonly data: string;\n readonly mimeType: string;\n readonly filename?: string;\n readonly sourceType?: \"url\" | \"id\";\n };\n\ntype AuiV0AttachmentPart =\n | {\n readonly type: \"text\";\n readonly text: string;\n }\n | {\n readonly type: \"image\";\n readonly image: string;\n readonly filename?: string;\n }\n | {\n readonly type: \"file\";\n readonly data: string;\n readonly mimeType: string;\n readonly filename?: string;\n readonly sourceType?: \"url\" | \"id\";\n }\n | {\n readonly type: \"audio\";\n readonly audio: {\n readonly data: string;\n readonly format: \"mp3\" | \"wav\";\n };\n }\n | {\n readonly type: \"data\";\n readonly name: string;\n readonly data: ReadonlyJSONValue;\n };\n\ntype AuiV0Attachment = {\n readonly id: string;\n readonly type: CompleteAttachment[\"type\"];\n readonly name: string;\n readonly contentType?: string;\n readonly status: CompleteAttachment[\"status\"];\n readonly content: readonly AuiV0AttachmentPart[];\n};\n\ntype AuiV0Message = {\n readonly role: \"assistant\" | \"user\" | \"system\";\n readonly status?: MessageStatus;\n readonly content: readonly AuiV0MessagePart[];\n readonly attachments?: readonly AuiV0Attachment[];\n readonly metadata: {\n readonly unstable_state?: ReadonlyJSONValue;\n readonly unstable_annotations: readonly ReadonlyJSONValue[];\n readonly unstable_data: readonly ReadonlyJSONValue[];\n readonly steps: readonly {\n readonly usage?: {\n readonly inputTokens: number;\n readonly outputTokens: number;\n };\n }[];\n readonly custom: ReadonlyJSONObject;\n };\n};\n\nconst encodeAttachmentPart = (\n part: CompleteAttachment[\"content\"][number],\n): AuiV0AttachmentPart => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\", text: part.text };\n\n case \"image\":\n return {\n type: \"image\",\n image: part.image,\n ...(part.filename != null ? { filename: part.filename } : undefined),\n };\n\n case \"file\":\n return {\n type: \"file\",\n data: part.data,\n mimeType: part.mimeType,\n ...(part.filename != null ? { filename: part.filename } : undefined),\n ...(part.sourceType != null\n ? { sourceType: part.sourceType }\n : undefined),\n };\n\n case \"audio\":\n return {\n type: \"audio\",\n audio: { data: part.audio.data, format: part.audio.format },\n };\n\n case \"data\": {\n if (!isJSONValue(part.data)) {\n console.warn(`attachment data is not JSON! ${JSON.stringify(part)}`);\n }\n return {\n type: \"data\",\n name: part.name,\n data: part.data as ReadonlyJSONValue,\n };\n }\n\n default: {\n const unhandledType: never = type;\n throw new Error(\n `Attachment part type not supported by aui/v0: ${unhandledType}`,\n );\n }\n }\n};\n\nconst encodeAttachments = (\n message: ThreadMessage,\n): readonly AuiV0Attachment[] | undefined => {\n if (message.role !== \"user\" || message.attachments.length === 0) {\n return undefined;\n }\n\n return message.attachments.map(\n ({ id, type, name, contentType, status, content }) => ({\n id,\n type,\n name,\n status,\n ...(contentType != null ? { contentType } : undefined),\n content: content.map(encodeAttachmentPart),\n }),\n );\n};\n\nexport function auiV0Encode(message: ThreadMessage): AuiV0Message {\n // info: ID and createdAt are ignored (we use the server value instead)\n const status: MessageStatus | undefined =\n message.status?.type === \"running\"\n ? { type: \"incomplete\", reason: \"cancelled\" }\n : message.status;\n const attachments = encodeAttachments(message);\n\n return {\n role: message.role,\n content: message.content.map((part) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\", text: part.text };\n\n case \"reasoning\":\n return { type: \"reasoning\", text: part.text };\n\n case \"source\":\n if (part.sourceType === \"url\") {\n return {\n type: \"source\",\n sourceType: \"url\",\n id: part.id,\n url: part.url,\n ...(part.title != null ? { title: part.title } : undefined),\n ...(part.providerMetadata != null\n ? { providerMetadata: part.providerMetadata }\n : undefined),\n };\n }\n\n return {\n type: \"source\",\n sourceType: \"document\",\n id: part.id,\n title: part.title,\n mediaType: part.mediaType,\n ...(part.filename != null\n ? { filename: part.filename }\n : undefined),\n ...(part.providerMetadata != null\n ? { providerMetadata: part.providerMetadata }\n : undefined),\n };\n\n case \"tool-call\": {\n if (part.result !== undefined && !isJSONValue(part.result)) {\n console.warn(\n `tool-call result is not JSON! ${JSON.stringify(part)}`,\n );\n }\n return {\n type: \"tool-call\",\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n ...(JSON.stringify(part.args) === part.argsText\n ? { args: part.args }\n : { argsText: part.argsText }),\n ...(part.result !== undefined\n ? { result: part.result as ReadonlyJSONValue }\n : undefined),\n ...(part.isError ? { isError: true } : undefined),\n ...(part.approval ? { approval: part.approval } : undefined),\n };\n }\n\n case \"image\":\n return { type: \"image\", image: part.image };\n\n case \"file\":\n return {\n type: \"file\",\n data: part.data,\n mimeType: part.mimeType,\n ...(part.filename ? { filename: part.filename } : undefined),\n ...(part.sourceType ? { sourceType: part.sourceType } : undefined),\n };\n\n default: {\n const unhandledType: \"audio\" | \"data\" | \"generative-ui\" = type;\n throw new Error(\n `Message part type not supported by aui/v0: ${unhandledType}`,\n );\n }\n }\n }),\n metadata: message.metadata as AuiV0Message[\"metadata\"],\n ...(status ? { status } : undefined),\n ...(attachments ? { attachments } : undefined),\n };\n}\n\nexport function auiV0Decode(\n cloudMessage: CloudMessage & { format: \"aui/v0\" },\n): ExportedMessageRepositoryItem {\n const payload = cloudMessage.content as unknown as AuiV0Message;\n const message = fromThreadMessageLike(\n {\n id: cloudMessage.id,\n createdAt: cloudMessage.created_at,\n ...payload,\n },\n cloudMessage.id,\n { type: \"complete\", reason: \"unknown\" },\n );\n\n return {\n parentId: cloudMessage.parent_id,\n message,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auiV0.js","names":["MessageStatus","SourceProviderMetadata","ThreadMessage","ToolApprovalOption","CompleteAttachment","fromThreadMessageLike","CloudMessage","isJSONValue","ReadonlyJSONObject","ReadonlyJSONValue","ExportedMessageRepositoryItem","AuiV0ToolApproval","id","approved","reason","isAutomatic","options","optionId","resolution","AuiV0MessagePart","type","text","unstable_summary","sourceType","url","title","providerMetadata","mediaType","filename","toolCallId","toolName","args","result","isError","approval","argsText","image","data","mimeType","AuiV0AttachmentPart","audio","format","name","AuiV0Attachment","contentType","status","content","AuiV0Message","role","attachments","metadata","unstable_state","unstable_annotations","unstable_data","steps","usage","inputTokens","outputTokens","custom","encodeAttachmentPart","part","undefined","console","warn","JSON","stringify","unhandledType","Error","encodeAttachments","message","length","map","auiV0Encode","auiV0Decode","cloudMessage","payload","createdAt","created_at","parentId","parent_id"],"sources":["../../../../src/react/runtimes/cloud/auiV0.ts"],"sourcesContent":["import type {\n MessageStatus,\n SourceProviderMetadata,\n ThreadMessage,\n ToolApprovalOption,\n} from \"../../../types/message\";\nimport type { CompleteAttachment } from \"../../../types/attachment\";\nimport { fromThreadMessageLike } from \"../../../runtime/utils/thread-message-like\";\nimport type { CloudMessage } from \"assistant-cloud\";\nimport { isJSONValue } from \"../../../utils/json/is-json\";\nimport type {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"assistant-stream/utils\";\nimport type { ExportedMessageRepositoryItem } from \"../../../runtime/utils/message-repository\";\n\ntype AuiV0ToolApproval = {\n readonly id: string;\n readonly approved?: boolean;\n readonly reason?: string;\n readonly isAutomatic?: boolean;\n readonly options?: readonly ToolApprovalOption[];\n readonly optionId?: string;\n readonly resolution?: \"cancelled\" | \"expired\";\n};\n\ntype AuiV0MessagePart =\n | {\n readonly type: \"text\";\n readonly text: string;\n }\n | {\n readonly type: \"reasoning\";\n readonly text: string;\n readonly unstable_summary?: string;\n }\n | {\n readonly type: \"source\";\n readonly sourceType: \"url\";\n readonly id: string;\n readonly url: string;\n readonly title?: string;\n readonly providerMetadata?: SourceProviderMetadata;\n }\n | {\n readonly type: \"source\";\n readonly sourceType: \"document\";\n readonly id: string;\n readonly title: string;\n readonly mediaType: string;\n readonly filename?: string;\n readonly providerMetadata?: SourceProviderMetadata;\n }\n | {\n readonly type: \"tool-call\";\n readonly toolCallId: string;\n readonly toolName: string;\n readonly args: ReadonlyJSONObject;\n readonly result?: ReadonlyJSONValue;\n readonly isError?: true;\n readonly approval?: AuiV0ToolApproval;\n }\n | {\n readonly type: \"tool-call\";\n readonly toolCallId: string;\n readonly toolName: string;\n readonly argsText: string;\n readonly result?: ReadonlyJSONValue;\n readonly isError?: true;\n readonly approval?: AuiV0ToolApproval;\n }\n | {\n readonly type: \"image\";\n readonly image: string;\n }\n | {\n readonly type: \"file\";\n readonly data: string;\n readonly mimeType: string;\n readonly filename?: string;\n readonly sourceType?: \"url\" | \"id\";\n };\n\ntype AuiV0AttachmentPart =\n | {\n readonly type: \"text\";\n readonly text: string;\n }\n | {\n readonly type: \"image\";\n readonly image: string;\n readonly filename?: string;\n }\n | {\n readonly type: \"file\";\n readonly data: string;\n readonly mimeType: string;\n readonly filename?: string;\n readonly sourceType?: \"url\" | \"id\";\n }\n | {\n readonly type: \"audio\";\n readonly audio: {\n readonly data: string;\n readonly format: \"mp3\" | \"wav\";\n };\n }\n | {\n readonly type: \"data\";\n readonly name: string;\n readonly data: ReadonlyJSONValue;\n };\n\ntype AuiV0Attachment = {\n readonly id: string;\n readonly type: CompleteAttachment[\"type\"];\n readonly name: string;\n readonly contentType?: string;\n readonly status: CompleteAttachment[\"status\"];\n readonly content: readonly AuiV0AttachmentPart[];\n};\n\ntype AuiV0Message = {\n readonly role: \"assistant\" | \"user\" | \"system\";\n readonly status?: MessageStatus;\n readonly content: readonly AuiV0MessagePart[];\n readonly attachments?: readonly AuiV0Attachment[];\n readonly metadata: {\n readonly unstable_state?: ReadonlyJSONValue;\n readonly unstable_annotations: readonly ReadonlyJSONValue[];\n readonly unstable_data: readonly ReadonlyJSONValue[];\n readonly steps: readonly {\n readonly usage?: {\n readonly inputTokens: number;\n readonly outputTokens: number;\n };\n }[];\n readonly custom: ReadonlyJSONObject;\n };\n};\n\nconst encodeAttachmentPart = (\n part: CompleteAttachment[\"content\"][number],\n): AuiV0AttachmentPart => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\", text: part.text };\n\n case \"image\":\n return {\n type: \"image\",\n image: part.image,\n ...(part.filename != null ? { filename: part.filename } : undefined),\n };\n\n case \"file\":\n return {\n type: \"file\",\n data: part.data,\n mimeType: part.mimeType,\n ...(part.filename != null ? { filename: part.filename } : undefined),\n ...(part.sourceType != null\n ? { sourceType: part.sourceType }\n : undefined),\n };\n\n case \"audio\":\n return {\n type: \"audio\",\n audio: { data: part.audio.data, format: part.audio.format },\n };\n\n case \"data\": {\n if (!isJSONValue(part.data)) {\n console.warn(`attachment data is not JSON! ${JSON.stringify(part)}`);\n }\n return {\n type: \"data\",\n name: part.name,\n data: part.data as ReadonlyJSONValue,\n };\n }\n\n default: {\n const unhandledType: never = type;\n throw new Error(\n `Attachment part type not supported by aui/v0: ${unhandledType}`,\n );\n }\n }\n};\n\nconst encodeAttachments = (\n message: ThreadMessage,\n): readonly AuiV0Attachment[] | undefined => {\n if (message.role !== \"user\" || message.attachments.length === 0) {\n return undefined;\n }\n\n return message.attachments.map(\n ({ id, type, name, contentType, status, content }) => ({\n id,\n type,\n name,\n status,\n ...(contentType != null ? { contentType } : undefined),\n content: content.map(encodeAttachmentPart),\n }),\n );\n};\n\nexport function auiV0Encode(message: ThreadMessage): AuiV0Message {\n // info: ID and createdAt are ignored (we use the server value instead)\n const status: MessageStatus | undefined =\n message.status?.type === \"running\"\n ? { type: \"incomplete\", reason: \"cancelled\" }\n : message.status;\n const attachments = encodeAttachments(message);\n\n return {\n role: message.role,\n content: message.content.map((part) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\", text: part.text };\n\n case \"reasoning\":\n return {\n type: \"reasoning\",\n text: part.text,\n ...(part.unstable_summary !== undefined\n ? { unstable_summary: part.unstable_summary }\n : undefined),\n };\n\n case \"source\":\n if (part.sourceType === \"url\") {\n return {\n type: \"source\",\n sourceType: \"url\",\n id: part.id,\n url: part.url,\n ...(part.title != null ? { title: part.title } : undefined),\n ...(part.providerMetadata != null\n ? { providerMetadata: part.providerMetadata }\n : undefined),\n };\n }\n\n return {\n type: \"source\",\n sourceType: \"document\",\n id: part.id,\n title: part.title,\n mediaType: part.mediaType,\n ...(part.filename != null\n ? { filename: part.filename }\n : undefined),\n ...(part.providerMetadata != null\n ? { providerMetadata: part.providerMetadata }\n : undefined),\n };\n\n case \"tool-call\": {\n if (part.result !== undefined && !isJSONValue(part.result)) {\n console.warn(\n `tool-call result is not JSON! ${JSON.stringify(part)}`,\n );\n }\n return {\n type: \"tool-call\",\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n ...(JSON.stringify(part.args) === part.argsText\n ? { args: part.args }\n : { argsText: part.argsText }),\n ...(part.result !== undefined\n ? { result: part.result as ReadonlyJSONValue }\n : undefined),\n ...(part.isError ? { isError: true } : undefined),\n ...(part.approval ? { approval: part.approval } : undefined),\n };\n }\n\n case \"image\":\n return { type: \"image\", image: part.image };\n\n case \"file\":\n return {\n type: \"file\",\n data: part.data,\n mimeType: part.mimeType,\n ...(part.filename ? { filename: part.filename } : undefined),\n ...(part.sourceType ? { sourceType: part.sourceType } : undefined),\n };\n\n default: {\n const unhandledType: \"audio\" | \"data\" | \"generative-ui\" = type;\n throw new Error(\n `Message part type not supported by aui/v0: ${unhandledType}`,\n );\n }\n }\n }),\n metadata: message.metadata as AuiV0Message[\"metadata\"],\n ...(status ? { status } : undefined),\n ...(attachments ? { attachments } : undefined),\n };\n}\n\nexport function auiV0Decode(\n cloudMessage: CloudMessage & { format: \"aui/v0\" },\n): ExportedMessageRepositoryItem {\n const payload = cloudMessage.content as unknown as AuiV0Message;\n const message = fromThreadMessageLike(\n {\n id: cloudMessage.id,\n createdAt: cloudMessage.created_at,\n ...payload,\n },\n cloudMessage.id,\n { type: \"complete\", reason: \"unknown\" },\n );\n\n return {\n parentId: cloudMessage.parent_id,\n message,\n };\n}\n"],"mappings":"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"}
|
|
@@ -27,7 +27,7 @@ declare abstract class BaseComposerRuntimeCore extends BaseSubscribable implemen
|
|
|
27
27
|
private _text;
|
|
28
28
|
get text(): string;
|
|
29
29
|
private _role;
|
|
30
|
-
get role(): "
|
|
30
|
+
get role(): "assistant" | "system" | "user";
|
|
31
31
|
private _runConfig;
|
|
32
32
|
get runConfig(): RunConfig;
|
|
33
33
|
private _quote;
|
|
@@ -10,8 +10,6 @@ declare class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {
|
|
|
10
10
|
get canSend(): boolean;
|
|
11
11
|
protected getAttachmentAdapter(): AttachmentAdapter | undefined;
|
|
12
12
|
protected getDictationAdapter(): DictationAdapter | undefined;
|
|
13
|
-
private _previousText;
|
|
14
|
-
private _previousAttachments;
|
|
15
13
|
private _nonTextPassthrough;
|
|
16
14
|
private _parentId;
|
|
17
15
|
private _sourceId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-edit-composer-runtime-core.d.ts","names":[],"sources":["../../../src/runtime/base/default-edit-composer-runtime-core.ts"],"mappings":";;;;;;;cAWa,uCAAuC;MACvC;MAIA;YAID,wBAAoB;YAIpB,uBAAmB;UAIrB;UACA;UACA;UACA;
|
|
1
|
+
{"version":3,"file":"default-edit-composer-runtime-core.d.ts","names":[],"sources":["../../../src/runtime/base/default-edit-composer-runtime-core.ts"],"mappings":";;;;;;;cAWa,uCAAuC;MACvC;MAIA;YAID,wBAAoB;YAIpB,uBAAmB;UAIrB;UACA;UACA;UACA;UAQA;EAGN,YAAA,SAAS;IACP;MAEM,cAAc;MACd,YAAY;;KAIpB,+BACE,UAAU;IAAa;IAAyB,SAAS;;MA6BlD;MAIA;EAIE,WACX,SAAS,KAAK,yCACd,UAAU,cAAW;EAkChB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { gateInteractableComposerMetadata } from "../../model-context/interactable-composer-metadata.js";
|
|
2
|
-
import {
|
|
2
|
+
import { liftNonTextParts } from "../../adapters/attachment.js";
|
|
3
3
|
import { getThreadMessageText } from "../../utils/text.js";
|
|
4
4
|
import { BaseComposerRuntimeCore } from "./base-composer-runtime-core.js";
|
|
5
5
|
//#region src/runtime/base/default-edit-composer-runtime-core.ts
|
|
@@ -16,8 +16,6 @@ var DefaultEditComposerRuntimeCore = class extends BaseComposerRuntimeCore {
|
|
|
16
16
|
getDictationAdapter() {
|
|
17
17
|
return this.runtime.adapters?.dictation;
|
|
18
18
|
}
|
|
19
|
-
_previousText;
|
|
20
|
-
_previousAttachments;
|
|
21
19
|
_nonTextPassthrough;
|
|
22
20
|
_parentId;
|
|
23
21
|
_sourceId;
|
|
@@ -29,17 +27,17 @@ var DefaultEditComposerRuntimeCore = class extends BaseComposerRuntimeCore {
|
|
|
29
27
|
this.endEditCallback = endEditCallback;
|
|
30
28
|
this._parentId = parentId;
|
|
31
29
|
this._sourceId = message.id;
|
|
32
|
-
this.
|
|
33
|
-
this.setText(this._previousText);
|
|
30
|
+
this.setText(getThreadMessageText(message));
|
|
34
31
|
this.setRole(message.role);
|
|
32
|
+
let attachments;
|
|
35
33
|
if (message.role === "user") {
|
|
36
|
-
|
|
34
|
+
attachments = [...message.attachments ?? [], ...liftNonTextParts(message.content)];
|
|
37
35
|
this._nonTextPassthrough = [];
|
|
38
36
|
} else {
|
|
39
|
-
|
|
37
|
+
attachments = message.attachments ?? [];
|
|
40
38
|
this._nonTextPassthrough = message.content.filter((p) => p.type !== "text");
|
|
41
39
|
}
|
|
42
|
-
this.setAttachments(
|
|
40
|
+
this.setAttachments(attachments);
|
|
43
41
|
this.setRunConfig({ ...runtime.composer.runConfig });
|
|
44
42
|
}
|
|
45
43
|
get parentId() {
|
|
@@ -49,23 +47,18 @@ var DefaultEditComposerRuntimeCore = class extends BaseComposerRuntimeCore {
|
|
|
49
47
|
return this._sourceId;
|
|
50
48
|
}
|
|
51
49
|
async handleSend(message, options) {
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
parentId: this._parentId,
|
|
65
|
-
sourceId: this._sourceId,
|
|
66
|
-
startRun: options?.startRun
|
|
67
|
-
});
|
|
68
|
-
}
|
|
50
|
+
const content = this._nonTextPassthrough.length > 0 ? [...message.content, ...this._nonTextPassthrough] : message.content;
|
|
51
|
+
const messages = this.runtime.messages;
|
|
52
|
+
const parentIndex = this._parentId === null ? -1 : messages.findIndex((m) => m.id === this._parentId);
|
|
53
|
+
const composerMetadata = gateInteractableComposerMetadata(this.runtime.getModelContext().unstable_composerMetadata, messages.slice(0, parentIndex + 1));
|
|
54
|
+
const enriched = this.enrichWithComposerMetadata(message, composerMetadata);
|
|
55
|
+
const appendTask = this.runtime.append({
|
|
56
|
+
...enriched,
|
|
57
|
+
content,
|
|
58
|
+
parentId: this._parentId,
|
|
59
|
+
sourceId: this._sourceId,
|
|
60
|
+
startRun: options?.startRun
|
|
61
|
+
});
|
|
69
62
|
this.handleCancel();
|
|
70
63
|
return appendTask;
|
|
71
64
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-edit-composer-runtime-core.js","names":["AppendMessage","ThreadMessage","CompleteAttachment","getThreadMessageText","
|
|
1
|
+
{"version":3,"file":"default-edit-composer-runtime-core.js","names":["AppendMessage","ThreadMessage","CompleteAttachment","getThreadMessageText","liftNonTextParts","AttachmentAdapter","DictationAdapter","SendOptions","ThreadRuntimeCore","BaseComposerRuntimeCore","gateInteractableComposerMetadata","DefaultEditComposerRuntimeCore","canCancel","canSend","isEmpty","_isSending","getAttachmentAdapter","runtime","adapters","attachments","getDictationAdapter","dictation","_nonTextPassthrough","_parentId","_sourceId","endEditCallback","constructor","parentId","message","id","setText","setRole","role","content","filter","p","type","setAttachments","setRunConfig","composer","runConfig","sourceId","handleSend","Omit","options","length","messages","parentIndex","findIndex","m","composerMetadata","getModelContext","unstable_composerMetadata","slice","enriched","enrichWithComposerMetadata","appendTask","append","startRun","handleCancel","_notifySubscribers"],"sources":["../../../src/runtime/base/default-edit-composer-runtime-core.ts"],"sourcesContent":["import type { AppendMessage, ThreadMessage } from \"../../types/message\";\nimport type { CompleteAttachment } from \"../../types/attachment\";\nimport { getThreadMessageText } from \"../../utils/text\";\nimport { liftNonTextParts } from \"../../adapters/attachment\";\nimport type { AttachmentAdapter } from \"../../adapters/attachment\";\nimport type { DictationAdapter } from \"../../adapters/speech\";\nimport type { SendOptions } from \"../interfaces/composer-runtime-core\";\nimport type { ThreadRuntimeCore } from \"../interfaces/thread-runtime-core\";\nimport { BaseComposerRuntimeCore } from \"./base-composer-runtime-core\";\nimport { gateInteractableComposerMetadata } from \"../../model-context/interactable-composer-metadata\";\n\nexport class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {\n public get canCancel() {\n return true;\n }\n\n public get canSend() {\n return !this.isEmpty && !this._isSending;\n }\n\n protected getAttachmentAdapter() {\n return this.runtime.adapters?.attachments;\n }\n\n protected getDictationAdapter() {\n return this.runtime.adapters?.dictation;\n }\n\n private _nonTextPassthrough: readonly ThreadMessage[\"content\"][number][];\n private _parentId: string | null;\n private _sourceId: string | null;\n private runtime: ThreadRuntimeCore & {\n adapters?:\n | {\n attachments?: AttachmentAdapter | undefined;\n dictation?: DictationAdapter | undefined;\n }\n | undefined;\n };\n private endEditCallback: () => void;\n\n constructor(\n runtime: ThreadRuntimeCore & {\n adapters?:\n | {\n attachments?: AttachmentAdapter | undefined;\n dictation?: DictationAdapter | undefined;\n }\n | undefined;\n },\n endEditCallback: () => void,\n { parentId, message }: { parentId: string | null; message: ThreadMessage },\n ) {\n super();\n this.runtime = runtime;\n this.endEditCallback = endEditCallback;\n this._parentId = parentId;\n this._sourceId = message.id;\n this.setText(getThreadMessageText(message));\n\n this.setRole(message.role);\n\n let attachments: readonly CompleteAttachment[];\n if (message.role === \"user\") {\n attachments = [\n ...(message.attachments ?? []),\n ...liftNonTextParts(message.content),\n ];\n this._nonTextPassthrough = [];\n } else {\n attachments = message.attachments ?? [];\n this._nonTextPassthrough = message.content.filter(\n (p) => p.type !== \"text\",\n );\n }\n this.setAttachments(attachments);\n\n this.setRunConfig({ ...runtime.composer.runConfig });\n }\n\n public get parentId() {\n return this._parentId;\n }\n\n public get sourceId() {\n return this._sourceId;\n }\n\n public async handleSend(\n message: Omit<AppendMessage, \"parentId\" | \"sourceId\">,\n options?: SendOptions,\n ) {\n const content =\n this._nonTextPassthrough.length > 0\n ? ([\n ...message.content,\n ...this._nonTextPassthrough,\n ] as AppendMessage[\"content\"])\n : message.content;\n // Gate live state against the new branch's prefix (messages up to the\n // parent): an unchanged interactable re-stamps the prior baseline, an\n // interactable edited since the original message stamps its newest state.\n const messages = this.runtime.messages;\n const parentIndex =\n this._parentId === null\n ? -1\n : messages.findIndex((m) => m.id === this._parentId);\n const composerMetadata = gateInteractableComposerMetadata(\n this.runtime.getModelContext().unstable_composerMetadata,\n messages.slice(0, parentIndex + 1),\n );\n const enriched = this.enrichWithComposerMetadata(message, composerMetadata);\n const appendTask = this.runtime.append({\n ...enriched,\n content,\n parentId: this._parentId,\n sourceId: this._sourceId,\n startRun: options?.startRun,\n });\n\n this.handleCancel();\n return appendTask;\n }\n\n public handleCancel() {\n this.endEditCallback();\n this._notifySubscribers();\n }\n}\n"],"mappings":";;;;;AAWA,IAAaW,iCAAb,cAAoDF,wBAAwB;CAC1E,IAAWG,YAAY;EACrB,OAAO;CACT;CAEA,IAAWC,UAAU;EACnB,OAAO,CAAC,KAAKC,WAAW,CAAC,KAAKC;CAChC;CAEA,uBAAiC;EAC/B,OAAO,KAAKE,QAAQC,UAAUC;CAChC;CAEA,sBAAgC;EAC9B,OAAO,KAAKF,QAAQC,UAAUG;CAChC;CAEA;CACA;CACA;CACA;CAQA;CAEAK,YACET,SAQAQ,iBACA,EAAEE,UAAUC,WACZ;EACA,MAAM;EACN,KAAKX,UAAUA;EACf,KAAKQ,kBAAkBA;EACvB,KAAKF,YAAYI;EACjB,KAAKH,YAAYI,QAAQC;EACzB,KAAKC,QAAQ3B,qBAAqByB,OAAO,CAAC;EAE1C,KAAKG,QAAQH,QAAQI,IAAI;EAEzB,IAAIb;EACJ,IAAIS,QAAQI,SAAS,QAAQ;GAC3Bb,cAAc,CACZ,GAAIS,QAAQT,eAAe,CAAA,GAC3B,GAAGf,iBAAiBwB,QAAQK,OAAO,CAAC;GAEtC,KAAKX,sBAAsB,CAAA;EAC7B,OAAO;GACLH,cAAcS,QAAQT,eAAe,CAAA;GACrC,KAAKG,sBAAsBM,QAAQK,QAAQC,QACxCC,MAAMA,EAAEC,SAAS,MACpB;EACF;EACA,KAAKC,eAAelB,WAAW;EAE/B,KAAKmB,aAAa,EAAE,GAAGrB,QAAQsB,SAASC,UAAU,CAAC;CACrD;CAEA,IAAWb,WAAW;EACpB,OAAO,KAAKJ;CACd;CAEA,IAAWkB,WAAW;EACpB,OAAO,KAAKjB;CACd;CAEA,MAAakB,WACXd,SACAgB,SACA;EACA,MAAMX,UACJ,KAAKX,oBAAoBuB,SAAS,IAC7B,CACC,GAAGjB,QAAQK,SACX,GAAG,KAAKX,mBAAmB,IAE7BM,QAAQK;EAId,MAAMa,WAAW,KAAK7B,QAAQ6B;EAC9B,MAAMC,cACJ,KAAKxB,cAAc,OACf,KACAuB,SAASE,WAAWC,MAAMA,EAAEpB,OAAO,KAAKN,SAAS;EACvD,MAAM2B,mBAAmBxC,iCACvB,KAAKO,QAAQkC,gBAAgB,CAAC,CAACC,2BAC/BN,SAASO,MAAM,GAAGN,cAAc,CAAC,CACnC;EACA,MAAMO,WAAW,KAAKC,2BAA2B3B,SAASsB,gBAAgB;EAC1E,MAAMM,aAAa,KAAKvC,QAAQwC,OAAO;GACrC,GAAGH;GACHrB;GACAN,UAAU,KAAKJ;GACfkB,UAAU,KAAKjB;GACfkC,UAAUd,SAASc;EACrB,CAAC;EAED,KAAKC,aAAa;EAClB,OAAOH;CACT;CAEA,eAAsB;EACpB,KAAK/B,gBAAgB;EACrB,KAAKmC,mBAAmB;CAC1B;AACF"}
|
|
@@ -47,9 +47,11 @@ const fromThreadMessageLike = (like, fallbackId, fallbackStatus) => {
|
|
|
47
47
|
const type = part.type;
|
|
48
48
|
switch (type) {
|
|
49
49
|
case "text":
|
|
50
|
-
case "reasoning":
|
|
51
50
|
if (!part.text?.trim()) return null;
|
|
52
51
|
return part;
|
|
52
|
+
case "reasoning":
|
|
53
|
+
if (!part.text?.trim() && !part.unstable_summary?.trim()) return null;
|
|
54
|
+
return part;
|
|
53
55
|
case "file":
|
|
54
56
|
case "source": return part;
|
|
55
57
|
case "image": return sanitizeImageContent(part);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thread-message-like.js","names":["parsePartialJsonObject","generateId","parseDataUrl","ReasoningMessagePart","SourceMessagePart","ThreadStep","MessageStatus","ImageMessagePart","ThreadMessage","ThreadAssistantMessagePart","ThreadAssistantMessage","ThreadUserMessagePart","ThreadUserMessage","ThreadSystemMessage","FileMessagePart","DataMessagePart","GenerativeUIMessagePart","Unstable_AudioMessagePart","CompleteAttachment","MessageTiming","PartProviderMetadata","TextMessagePart","ToolApprovalOption","ToolCallTiming","ReadonlyJSONObject","ReadonlyJSONValue","DataPrefixedPart","type","data","ThreadMessageLike","role","content","toolCallId","toolName","args","argsText","artifact","result","isError","parentId","messages","interrupt","payload","timing","providerMetadata","approval","id","approved","reason","isAutomatic","options","optionId","resolution","createdAt","Date","status","attachments","Omit","metadata","unstable_state","unstable_annotations","unstable_data","steps","submittedFeedback","isOptimistic","custom","Record","convertDataPrefixedPart","startsWith","undefined","name","substring","fromThreadMessageLike","like","fallbackId","fallbackStatus","common","const","text","sanitizeImageContent","image","rest","mimeType","test","console","warn","length","Error","map","part","trim","basePart","commonProps","JSON","stringify","converted","filter","c","att","unsupportedRole"],"sources":["../../../src/runtime/utils/thread-message-like.ts"],"sourcesContent":["import { parsePartialJsonObject } from \"assistant-stream/utils\";\nimport { generateId } from \"../../utils/id\";\nimport { parseDataUrl } from \"../../utils/data-url\";\nimport type {\n ReasoningMessagePart,\n SourceMessagePart,\n ThreadStep,\n MessageStatus,\n ImageMessagePart,\n ThreadMessage,\n ThreadAssistantMessagePart,\n ThreadAssistantMessage,\n ThreadUserMessagePart,\n ThreadUserMessage,\n ThreadSystemMessage,\n FileMessagePart,\n DataMessagePart,\n GenerativeUIMessagePart,\n Unstable_AudioMessagePart,\n} from \"../../types/message\";\nimport type { CompleteAttachment } from \"../../types/attachment\";\nimport type {\n MessageTiming,\n PartProviderMetadata,\n TextMessagePart,\n ToolApprovalOption,\n ToolCallTiming,\n} from \"../../types/message\";\nimport type {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"assistant-stream/utils\";\n\ntype DataPrefixedPart = {\n readonly type: `data-${string}`;\n readonly data: any;\n};\n\nexport type ThreadMessageLike = {\n readonly role: \"assistant\" | \"user\" | \"system\";\n readonly content:\n | string\n | readonly (\n | TextMessagePart\n | ReasoningMessagePart\n | SourceMessagePart\n | ImageMessagePart\n | FileMessagePart\n | DataMessagePart\n | GenerativeUIMessagePart\n | Unstable_AudioMessagePart\n | DataPrefixedPart\n | {\n readonly type: \"tool-call\";\n readonly toolCallId?: string;\n readonly toolName: string;\n readonly args?: ReadonlyJSONObject;\n readonly argsText?: string;\n readonly artifact?: any;\n readonly result?: any | undefined;\n readonly isError?: boolean | undefined;\n readonly parentId?: string | undefined;\n readonly messages?: readonly ThreadMessage[] | undefined;\n readonly interrupt?: { type: \"human\"; payload: unknown };\n readonly timing?: ToolCallTiming;\n readonly providerMetadata?: PartProviderMetadata;\n readonly approval?: {\n readonly id: string;\n readonly approved?: boolean;\n readonly reason?: string;\n readonly isAutomatic?: boolean;\n readonly options?: readonly ToolApprovalOption[];\n readonly optionId?: string;\n readonly resolution?: \"cancelled\" | \"expired\";\n };\n }\n )[];\n readonly id?: string | undefined;\n readonly createdAt?: Date | undefined;\n readonly status?: MessageStatus | undefined;\n readonly attachments?:\n | readonly (Omit<CompleteAttachment, \"content\"> & {\n readonly content: readonly (ThreadUserMessagePart | DataPrefixedPart)[];\n })[]\n | undefined;\n readonly metadata?:\n | {\n readonly unstable_state?: ReadonlyJSONValue;\n readonly unstable_annotations?:\n | readonly ReadonlyJSONValue[]\n | undefined;\n readonly unstable_data?: readonly ReadonlyJSONValue[] | undefined;\n readonly steps?: readonly ThreadStep[] | undefined;\n readonly timing?: MessageTiming | undefined;\n readonly submittedFeedback?: { readonly type: \"positive\" | \"negative\" };\n readonly isOptimistic?: boolean | undefined;\n readonly custom?: Record<string, unknown> | undefined;\n }\n | undefined;\n};\n\nconst convertDataPrefixedPart = (\n type: string,\n data: unknown,\n): DataMessagePart | undefined => {\n if (!type.startsWith(\"data-\")) return undefined;\n return { type: \"data\", name: type.substring(5), data };\n};\n\n/**\n * @deprecated This API is experimental and may change without notice.\n */\nexport const fromThreadMessageLike = (\n like: ThreadMessageLike,\n fallbackId: string,\n fallbackStatus: MessageStatus,\n): ThreadMessage => {\n const { role, id, createdAt, attachments, status, metadata } = like;\n const common = {\n id: id ?? fallbackId,\n createdAt: createdAt ?? new Date(),\n };\n\n const content =\n typeof like.content === \"string\"\n ? [{ type: \"text\" as const, text: like.content }]\n : like.content;\n\n const sanitizeImageContent = ({\n image,\n ...rest\n }: ImageMessagePart): ImageMessagePart | null => {\n if (typeof image !== \"string\") return null;\n if (parseDataUrl(image)?.mimeType.startsWith(\"image/\")) {\n return { ...rest, image };\n }\n if (/^(https:\\/\\/|blob:)/i.test(image)) {\n return { ...rest, image };\n }\n console.warn(`Invalid image data format detected`);\n return null;\n };\n\n if (role !== \"user\" && attachments?.length)\n throw new Error(\"attachments are only supported for user messages\");\n\n if (role !== \"assistant\" && status)\n throw new Error(\"status is only supported for assistant messages\");\n\n if (role !== \"assistant\" && metadata?.steps)\n throw new Error(\"metadata.steps is only supported for assistant messages\");\n\n switch (role) {\n case \"assistant\":\n return {\n ...common,\n role,\n content: content\n .map((part): ThreadAssistantMessagePart | null => {\n const type = part.type;\n switch (type) {\n case \"text\":\n case \"reasoning\":\n if (!part.text?.trim()) return null;\n return part;\n\n case \"file\":\n case \"source\":\n return part;\n\n case \"image\":\n return sanitizeImageContent(part);\n\n case \"data\":\n return part;\n\n case \"generative-ui\":\n return part;\n\n case \"tool-call\": {\n const { parentId, messages, ...basePart } = part;\n const commonProps = {\n ...basePart,\n toolCallId: part.toolCallId ?? `tool-${generateId()}`,\n ...(parentId !== undefined && { parentId }),\n ...(messages !== undefined && { messages }),\n };\n\n if (part.args) {\n return {\n ...commonProps,\n args: part.args,\n argsText: part.argsText ?? JSON.stringify(part.args),\n };\n }\n return {\n ...commonProps,\n args: parsePartialJsonObject(part.argsText ?? \"\") ?? {},\n argsText: part.argsText ?? \"\",\n };\n }\n\n default: {\n const converted = convertDataPrefixedPart(\n type,\n (part as DataPrefixedPart).data,\n );\n if (converted) return converted;\n throw new Error(\n `Unsupported assistant message part type: ${type}`,\n );\n }\n }\n })\n .filter((c) => !!c),\n status: status ?? fallbackStatus,\n metadata: {\n unstable_state: metadata?.unstable_state ?? null,\n unstable_annotations: metadata?.unstable_annotations ?? [],\n unstable_data: metadata?.unstable_data ?? [],\n custom: metadata?.custom ?? {},\n steps: metadata?.steps ?? [],\n ...(metadata?.timing && { timing: metadata.timing }),\n ...(metadata?.submittedFeedback && {\n submittedFeedback: metadata.submittedFeedback,\n }),\n ...(metadata?.isOptimistic && { isOptimistic: true }),\n },\n } satisfies ThreadAssistantMessage;\n\n case \"user\":\n return {\n ...common,\n role,\n content: content.map((part): ThreadUserMessagePart => {\n const type = part.type;\n switch (type) {\n case \"text\":\n case \"image\":\n case \"audio\":\n case \"file\":\n case \"data\":\n return part;\n\n default: {\n const converted = convertDataPrefixedPart(\n type,\n (part as DataPrefixedPart).data,\n );\n if (converted) return converted;\n throw new Error(`Unsupported user message part type: ${type}`);\n }\n }\n }),\n attachments: (attachments ?? []).map((att) => ({\n ...att,\n content: att.content.map((part): ThreadUserMessagePart => {\n const converted = convertDataPrefixedPart(\n part.type,\n (part as DataPrefixedPart).data,\n );\n return converted ?? (part as ThreadUserMessagePart);\n }),\n })),\n metadata: {\n custom: metadata?.custom ?? {},\n ...(metadata?.isOptimistic && { isOptimistic: true }),\n },\n } satisfies ThreadUserMessage;\n\n case \"system\":\n if (content.length !== 1 || content[0]!.type !== \"text\")\n throw new Error(\n \"System messages must have exactly one text message part.\",\n );\n\n return {\n ...common,\n role,\n content: content as [TextMessagePart],\n metadata: {\n custom: metadata?.custom ?? {},\n },\n } satisfies ThreadSystemMessage;\n\n default: {\n const unsupportedRole: never = role;\n throw new Error(`Unknown message role: ${unsupportedRole}`);\n }\n }\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"thread-message-like.js","names":["parsePartialJsonObject","generateId","parseDataUrl","ReasoningMessagePart","SourceMessagePart","ThreadStep","MessageStatus","ImageMessagePart","ThreadMessage","ThreadAssistantMessagePart","ThreadAssistantMessage","ThreadUserMessagePart","ThreadUserMessage","ThreadSystemMessage","FileMessagePart","DataMessagePart","GenerativeUIMessagePart","Unstable_AudioMessagePart","CompleteAttachment","MessageTiming","PartProviderMetadata","TextMessagePart","ToolApprovalOption","ToolCallTiming","ReadonlyJSONObject","ReadonlyJSONValue","DataPrefixedPart","type","data","ThreadMessageLike","role","content","toolCallId","toolName","args","argsText","artifact","result","isError","parentId","messages","interrupt","payload","timing","providerMetadata","approval","id","approved","reason","isAutomatic","options","optionId","resolution","createdAt","Date","status","attachments","Omit","metadata","unstable_state","unstable_annotations","unstable_data","steps","submittedFeedback","isOptimistic","custom","Record","convertDataPrefixedPart","startsWith","undefined","name","substring","fromThreadMessageLike","like","fallbackId","fallbackStatus","common","const","text","sanitizeImageContent","image","rest","mimeType","test","console","warn","length","Error","map","part","trim","unstable_summary","basePart","commonProps","JSON","stringify","converted","filter","c","att","unsupportedRole"],"sources":["../../../src/runtime/utils/thread-message-like.ts"],"sourcesContent":["import { parsePartialJsonObject } from \"assistant-stream/utils\";\nimport { generateId } from \"../../utils/id\";\nimport { parseDataUrl } from \"../../utils/data-url\";\nimport type {\n ReasoningMessagePart,\n SourceMessagePart,\n ThreadStep,\n MessageStatus,\n ImageMessagePart,\n ThreadMessage,\n ThreadAssistantMessagePart,\n ThreadAssistantMessage,\n ThreadUserMessagePart,\n ThreadUserMessage,\n ThreadSystemMessage,\n FileMessagePart,\n DataMessagePart,\n GenerativeUIMessagePart,\n Unstable_AudioMessagePart,\n} from \"../../types/message\";\nimport type { CompleteAttachment } from \"../../types/attachment\";\nimport type {\n MessageTiming,\n PartProviderMetadata,\n TextMessagePart,\n ToolApprovalOption,\n ToolCallTiming,\n} from \"../../types/message\";\nimport type {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"assistant-stream/utils\";\n\ntype DataPrefixedPart = {\n readonly type: `data-${string}`;\n readonly data: any;\n};\n\nexport type ThreadMessageLike = {\n readonly role: \"assistant\" | \"user\" | \"system\";\n readonly content:\n | string\n | readonly (\n | TextMessagePart\n | ReasoningMessagePart\n | SourceMessagePart\n | ImageMessagePart\n | FileMessagePart\n | DataMessagePart\n | GenerativeUIMessagePart\n | Unstable_AudioMessagePart\n | DataPrefixedPart\n | {\n readonly type: \"tool-call\";\n readonly toolCallId?: string;\n readonly toolName: string;\n readonly args?: ReadonlyJSONObject;\n readonly argsText?: string;\n readonly artifact?: any;\n readonly result?: any | undefined;\n readonly isError?: boolean | undefined;\n readonly parentId?: string | undefined;\n readonly messages?: readonly ThreadMessage[] | undefined;\n readonly interrupt?: { type: \"human\"; payload: unknown };\n readonly timing?: ToolCallTiming;\n readonly providerMetadata?: PartProviderMetadata;\n readonly approval?: {\n readonly id: string;\n readonly approved?: boolean;\n readonly reason?: string;\n readonly isAutomatic?: boolean;\n readonly options?: readonly ToolApprovalOption[];\n readonly optionId?: string;\n readonly resolution?: \"cancelled\" | \"expired\";\n };\n }\n )[];\n readonly id?: string | undefined;\n readonly createdAt?: Date | undefined;\n readonly status?: MessageStatus | undefined;\n readonly attachments?:\n | readonly (Omit<CompleteAttachment, \"content\"> & {\n readonly content: readonly (ThreadUserMessagePart | DataPrefixedPart)[];\n })[]\n | undefined;\n readonly metadata?:\n | {\n readonly unstable_state?: ReadonlyJSONValue;\n readonly unstable_annotations?:\n | readonly ReadonlyJSONValue[]\n | undefined;\n readonly unstable_data?: readonly ReadonlyJSONValue[] | undefined;\n readonly steps?: readonly ThreadStep[] | undefined;\n readonly timing?: MessageTiming | undefined;\n readonly submittedFeedback?: { readonly type: \"positive\" | \"negative\" };\n readonly isOptimistic?: boolean | undefined;\n readonly custom?: Record<string, unknown> | undefined;\n }\n | undefined;\n};\n\nconst convertDataPrefixedPart = (\n type: string,\n data: unknown,\n): DataMessagePart | undefined => {\n if (!type.startsWith(\"data-\")) return undefined;\n return { type: \"data\", name: type.substring(5), data };\n};\n\n/**\n * @deprecated This API is experimental and may change without notice.\n */\nexport const fromThreadMessageLike = (\n like: ThreadMessageLike,\n fallbackId: string,\n fallbackStatus: MessageStatus,\n): ThreadMessage => {\n const { role, id, createdAt, attachments, status, metadata } = like;\n const common = {\n id: id ?? fallbackId,\n createdAt: createdAt ?? new Date(),\n };\n\n const content =\n typeof like.content === \"string\"\n ? [{ type: \"text\" as const, text: like.content }]\n : like.content;\n\n const sanitizeImageContent = ({\n image,\n ...rest\n }: ImageMessagePart): ImageMessagePart | null => {\n if (typeof image !== \"string\") return null;\n if (parseDataUrl(image)?.mimeType.startsWith(\"image/\")) {\n return { ...rest, image };\n }\n if (/^(https:\\/\\/|blob:)/i.test(image)) {\n return { ...rest, image };\n }\n console.warn(`Invalid image data format detected`);\n return null;\n };\n\n if (role !== \"user\" && attachments?.length)\n throw new Error(\"attachments are only supported for user messages\");\n\n if (role !== \"assistant\" && status)\n throw new Error(\"status is only supported for assistant messages\");\n\n if (role !== \"assistant\" && metadata?.steps)\n throw new Error(\"metadata.steps is only supported for assistant messages\");\n\n switch (role) {\n case \"assistant\":\n return {\n ...common,\n role,\n content: content\n .map((part): ThreadAssistantMessagePart | null => {\n const type = part.type;\n switch (type) {\n case \"text\":\n if (!part.text?.trim()) return null;\n return part;\n\n case \"reasoning\":\n if (!part.text?.trim() && !part.unstable_summary?.trim())\n return null;\n return part;\n\n case \"file\":\n case \"source\":\n return part;\n\n case \"image\":\n return sanitizeImageContent(part);\n\n case \"data\":\n return part;\n\n case \"generative-ui\":\n return part;\n\n case \"tool-call\": {\n const { parentId, messages, ...basePart } = part;\n const commonProps = {\n ...basePart,\n toolCallId: part.toolCallId ?? `tool-${generateId()}`,\n ...(parentId !== undefined && { parentId }),\n ...(messages !== undefined && { messages }),\n };\n\n if (part.args) {\n return {\n ...commonProps,\n args: part.args,\n argsText: part.argsText ?? JSON.stringify(part.args),\n };\n }\n return {\n ...commonProps,\n args: parsePartialJsonObject(part.argsText ?? \"\") ?? {},\n argsText: part.argsText ?? \"\",\n };\n }\n\n default: {\n const converted = convertDataPrefixedPart(\n type,\n (part as DataPrefixedPart).data,\n );\n if (converted) return converted;\n throw new Error(\n `Unsupported assistant message part type: ${type}`,\n );\n }\n }\n })\n .filter((c) => !!c),\n status: status ?? fallbackStatus,\n metadata: {\n unstable_state: metadata?.unstable_state ?? null,\n unstable_annotations: metadata?.unstable_annotations ?? [],\n unstable_data: metadata?.unstable_data ?? [],\n custom: metadata?.custom ?? {},\n steps: metadata?.steps ?? [],\n ...(metadata?.timing && { timing: metadata.timing }),\n ...(metadata?.submittedFeedback && {\n submittedFeedback: metadata.submittedFeedback,\n }),\n ...(metadata?.isOptimistic && { isOptimistic: true }),\n },\n } satisfies ThreadAssistantMessage;\n\n case \"user\":\n return {\n ...common,\n role,\n content: content.map((part): ThreadUserMessagePart => {\n const type = part.type;\n switch (type) {\n case \"text\":\n case \"image\":\n case \"audio\":\n case \"file\":\n case \"data\":\n return part;\n\n default: {\n const converted = convertDataPrefixedPart(\n type,\n (part as DataPrefixedPart).data,\n );\n if (converted) return converted;\n throw new Error(`Unsupported user message part type: ${type}`);\n }\n }\n }),\n attachments: (attachments ?? []).map((att) => ({\n ...att,\n content: att.content.map((part): ThreadUserMessagePart => {\n const converted = convertDataPrefixedPart(\n part.type,\n (part as DataPrefixedPart).data,\n );\n return converted ?? (part as ThreadUserMessagePart);\n }),\n })),\n metadata: {\n custom: metadata?.custom ?? {},\n ...(metadata?.isOptimistic && { isOptimistic: true }),\n },\n } satisfies ThreadUserMessage;\n\n case \"system\":\n if (content.length !== 1 || content[0]!.type !== \"text\")\n throw new Error(\n \"System messages must have exactly one text message part.\",\n );\n\n return {\n ...common,\n role,\n content: content as [TextMessagePart],\n metadata: {\n custom: metadata?.custom ?? {},\n },\n } satisfies ThreadSystemMessage;\n\n default: {\n const unsupportedRole: never = role;\n throw new Error(`Unknown message role: ${unsupportedRole}`);\n }\n }\n};\n"],"mappings":"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"}
|
package/dist/types/message.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.d.ts","names":[],"sources":["../../src/types/message.ts"],"mappings":";;;;KASY;YACA,uBAAuB;;KAGvB;WACD;WACA;WACA,SAAS;WACT,mBAAmB;WACnB;;KAGC;WACD;WACA;WACA,SAAS;WACT,mBAAmB;WACnB;;KAGC,yBAAyB;KAEzB;WAEG;WACA;WACA;WACA;WACA;WACA,mBAAmB;WACnB;;WAGA;WACA;WACA;WACA;WACA;WACA;WACA;WACA,mBAAmB;WACnB;;KAGH;WACD;WACA;WACA;;KAGC;WACD;WACA;WACA;WACA;;WAEA;WACA;;;;;;;;;;;KAYC;WACD;WACA;aACE;aACA;;;KAID,gBAAgB;WACjB;WACA;WACA,MAAM;;;;;;;;;;;KAYL;;WAIG;;WAEA,QAAQ;;WAER,oBAAoB;;WAEpB;;;;;KAMH;;WAED,MAAM,4BAA4B;;;;;;;;;;KAWjC;WACD;;WAEA,MAAM;;WAEN;WACA;;KAGC;WACD;WACA;WACA;;WAEA;;cAGE;cAEA,cAAe;KAGhB;WACD,MAAM;;KAGL;KAMA;;WAED;;;;;;;WAOA,MAAM;;WAEN;WACA;;WAEA;;WAEA;IAAsB;IAAgB;;;KAGrC;WACG;WAA4B;;WAC5B;WAA2B;;WAE3B;WACA;WACA;;KAGH,oBACV,QAAQ,oBACR;;WAGS;;WAEA;;WAEA;;;;;;WAMA,MAAM;;WAEN,SAAS;;WAET;;WAEA;;WAEA;;WAEA,SAAS;;WAET,MAAM;;WAEN,mBAAmB;;WAEnB,wBAAwB;;WAExB;IAAc;IAAe;;;WAE7B;aACE;aACA;aACA;aACA;;aAEA,mBAAmB;;aAEnB;;aAEA;;;WAGF;;;;;WAKA,oBAAoB;;KAGnB,wBACR,kBACA,mBACA,kBACA,kBACA;KAEQ,6BACR,kBACA,uBACA,sBACA,oBACA,kBACA,mBACA,kBACA;KAEQ;WAEG;;WAGA;;WAGA;WACA;WAMA;;KAGH;WAEG;;WAGA;;WAGA;WACA;;KAQH;;WAGG;;WAEA;IAEX;KAEQ;WAEG;;WAGA;WACA;;WAGA;WACA;;WAGA;WACA;WAOA,QAAQ;;KAGX;WACD;WACA;WACA;WACA;WACA;WACA;WACA;;KAGC;WACD;WACA;aAEM;aACA;;;KAKZ;WACM;WACA,WAAW;;KAGV,sBAAsB;WACvB;WACA,mBAAmB;WACnB;aACE;aACA;aACA;aACA;aACA;aACA;aACA,QAAQ;;;KAIT,oBAAoB;WACrB;WACA,kBAAkB;WAClB,sBAAsB;WACtB;aACE;aACA;aACA;aACA;aACA;aACA;aACA;aACA,QAAQ;;;KAIT,yBAAyB;WAC1B;WACA,kBAAkB;WAClB,QAAQ;WACR;aACE,gBAAgB;aAChB,+BAA+B;aAC/B,wBAAwB;aACxB,gBAAgB;aAChB;eAA+B;;aAC/B,SAAS;;;;;aAKT;aACA,QAAQ;;;KAIhB;WACM,SAAS;WACT;aACE,iBAAiB;aACjB,gCAAgC;aAChC,yBAAyB;aACzB,iBAAiB;aACjB;eAA+B;;aAC/B,SAAS;aACT;aACA,QAAQ;;WAEV,cAAc;;KAGb,gBAAgB,qBACzB,sBAAsB,oBAAoB;KAEjC,cAAc;KAEd;WACD,SAAS;;KAGR,gBAAgB,KAAK;EAC/B;;EAGA;EACA,WAAW;EACX;;EAEA"}
|
|
1
|
+
{"version":3,"file":"message.d.ts","names":[],"sources":["../../src/types/message.ts"],"mappings":";;;;KASY;YACA,uBAAuB;;KAGvB;WACD;WACA;WACA,SAAS;WACT,mBAAmB;WACnB;;KAGC;WACD;WACA;WACA,SAAS;WACT;WACA,mBAAmB;WACnB;;KAGC,yBAAyB;KAEzB;WAEG;WACA;WACA;WACA;WACA;WACA,mBAAmB;WACnB;;WAGA;WACA;WACA;WACA;WACA;WACA;WACA;WACA,mBAAmB;WACnB;;KAGH;WACD;WACA;WACA;;KAGC;WACD;WACA;WACA;WACA;;WAEA;WACA;;;;;;;;;;;KAYC;WACD;WACA;aACE;aACA;;;KAID,gBAAgB;WACjB;WACA;WACA,MAAM;;;;;;;;;;;KAYL;;WAIG;;WAEA,QAAQ;;WAER,oBAAoB;;WAEpB;;;;;KAMH;;WAED,MAAM,4BAA4B;;;;;;;;;;KAWjC;WACD;;WAEA,MAAM;;WAEN;WACA;;KAGC;WACD;WACA;WACA;;WAEA;;cAGE;cAEA,cAAe;KAGhB;WACD,MAAM;;KAGL;KAMA;;WAED;;;;;;;WAOA,MAAM;;WAEN;WACA;;WAEA;;WAEA;IAAsB;IAAgB;;;KAGrC;WACG;WAA4B;;WAC5B;WAA2B;;WAE3B;WACA;WACA;;KAGH,oBACV,QAAQ,oBACR;;WAGS;;WAEA;;WAEA;;;;;;WAMA,MAAM;;WAEN,SAAS;;WAET;;WAEA;;WAEA;;WAEA,SAAS;;WAET,MAAM;;WAEN,mBAAmB;;WAEnB,wBAAwB;;WAExB;IAAc;IAAe;;;WAE7B;aACE;aACA;aACA;aACA;;aAEA,mBAAmB;;aAEnB;;aAEA;;;WAGF;;;;;WAKA,oBAAoB;;KAGnB,wBACR,kBACA,mBACA,kBACA,kBACA;KAEQ,6BACR,kBACA,uBACA,sBACA,oBACA,kBACA,mBACA,kBACA;KAEQ;WAEG;;WAGA;;WAGA;WACA;WAMA;;KAGH;WAEG;;WAGA;;WAGA;WACA;;KAQH;;WAGG;;WAEA;IAEX;KAEQ;WAEG;;WAGA;WACA;;WAGA;WACA;;WAGA;WACA;WAOA,QAAQ;;KAGX;WACD;WACA;WACA;WACA;WACA;WACA;WACA;;KAGC;WACD;WACA;aAEM;aACA;;;KAKZ;WACM;WACA,WAAW;;KAGV,sBAAsB;WACvB;WACA,mBAAmB;WACnB;aACE;aACA;aACA;aACA;aACA;aACA;aACA,QAAQ;;;KAIT,oBAAoB;WACrB;WACA,kBAAkB;WAClB,sBAAsB;WACtB;aACE;aACA;aACA;aACA;aACA;aACA;aACA;aACA,QAAQ;;;KAIT,yBAAyB;WAC1B;WACA,kBAAkB;WAClB,QAAQ;WACR;aACE,gBAAgB;aAChB,+BAA+B;aAC/B,wBAAwB;aACxB,gBAAgB;aAChB;eAA+B;;aAC/B,SAAS;;;;;aAKT;aACA,QAAQ;;;KAIhB;WACM,SAAS;WACT;aACE,iBAAiB;aACjB,gCAAgC;aAChC,yBAAyB;aACzB,iBAAiB;aACjB;eAA+B;;aAC/B,SAAS;aACT;aACA,QAAQ;;WAEV,cAAc;;KAGb,gBAAgB,qBACzB,sBAAsB,oBAAoB;KAEjC,cAAc;KAEd;WACD,SAAS;;KAGR,gBAAgB,KAAK;EAC/B;;EAGA;EACA,WAAW;EACX;;EAEA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.js","names":["ReadonlyJSONObject","ReadonlyJSONValue","ToolCallTiming","ToolModelContentPart","CompleteAttachment","PartProviderMetadata","providerName","TextMessagePart","type","text","status","MessagePartStreamStatus","providerMetadata","parentId","ReasoningMessagePart","SourceProviderMetadata","SourceMessagePart","sourceType","id","url","title","mediaType","filename","ImageMessagePart","image","FileMessagePart","data","mimeType","Unstable_AudioMessagePart","audio","format","DataMessagePart","name","T","GenerativeUINode","component","props","Record","children","key","GenerativeUISpec","root","GenerativeUIMessagePart","spec","McpAppMetadata","resourceUri","visibility","serverId","MCP_APP_URI_SCHEME","isMcpAppUri","uri","startsWith","ToolCallMessagePartMcpMetadata","app","ToolApprovalOptionKind","ToolApprovalOption","kind","label","description","grants","confirm","ToolApprovalResponse","approved","reason","optionId","ToolCallMessagePart","toolCallId","toolName","args","TArgs","result","TResult","isError","argsText","artifact","timing","mcp","modelContent","interrupt","payload","approval","isAutomatic","options","resolution","messages","ThreadMessage","ThreadUserMessagePart","ThreadAssistantMessagePart","MessagePartStatus","error","ToolCallMessagePartStatus","MessageStatus","MessageTiming","streamStartTime","firstTokenTime","totalStreamTime","tokenCount","tokensPerSecond","totalChunks","toolCallCount","ThreadStep","messageId","usage","inputTokens","outputTokens","MessageCommonProps","createdAt","Date","ThreadSystemMessage","role","content","metadata","unstable_state","unstable_annotations","unstable_data","steps","submittedFeedback","custom","ThreadUserMessage","attachments","isOptimistic","ThreadAssistantMessage","BaseThreadMessage","MessageRole","RunConfig","AppendMessage","Omit","sourceId","runConfig","startRun","steer"],"sources":["../../src/types/message.ts"],"sourcesContent":["import type {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"assistant-stream/utils\";\nimport type { ToolCallTiming, ToolModelContentPart } from \"assistant-stream\";\nimport type { CompleteAttachment } from \"./attachment\";\n\nexport type { ToolCallTiming, ToolModelContentPart };\n\nexport type PartProviderMetadata = {\n readonly [providerName: string]: ReadonlyJSONObject;\n};\n\nexport type TextMessagePart = {\n readonly type: \"text\";\n readonly text: string;\n readonly status?: MessagePartStreamStatus;\n readonly providerMetadata?: PartProviderMetadata;\n readonly parentId?: string;\n};\n\nexport type ReasoningMessagePart = {\n readonly type: \"reasoning\";\n readonly text: string;\n readonly status?: MessagePartStreamStatus;\n readonly providerMetadata?: PartProviderMetadata;\n readonly parentId?: string;\n};\n\nexport type SourceProviderMetadata = PartProviderMetadata;\n\nexport type SourceMessagePart =\n | {\n readonly type: \"source\";\n readonly sourceType: \"url\";\n readonly id: string;\n readonly url: string;\n readonly title?: string;\n readonly providerMetadata?: SourceProviderMetadata;\n readonly parentId?: string;\n }\n | {\n readonly type: \"source\";\n readonly sourceType: \"document\";\n readonly id: string;\n readonly url?: undefined;\n readonly title: string;\n readonly mediaType: string;\n readonly filename?: string;\n readonly providerMetadata?: SourceProviderMetadata;\n readonly parentId?: string;\n };\n\nexport type ImageMessagePart = {\n readonly type: \"image\";\n readonly image: string;\n readonly filename?: string;\n};\n\nexport type FileMessagePart = {\n readonly type: \"file\";\n readonly filename?: string;\n readonly data: string;\n readonly mimeType: string;\n /** How `data` goes on the wire: a url or id reference; omitted = inferred (http(s) → url, else base64). \"url\" is honored by the LangChain-family, A2A, AG-UI, and Google ADK runtimes; \"id\" by the LangChain family only. */\n readonly sourceType?: \"url\" | \"id\";\n readonly parentId?: string;\n};\n\n/**\n * @deprecated Use {@link FileMessagePart} with an `audio/*` mime type. `file`\n * is the carrier for every non-image binary modality: it is a member of both\n * the user and assistant unions, carries a filename, and can declare how its\n * payload goes on the wire, none of which this shape can express. The payload\n * form a `file` part needs is still adapter specific; see the Part Types\n * section of the message primitive docs. Honored everywhere it is accepted; it\n * will not gain fields.\n */\nexport type Unstable_AudioMessagePart = {\n readonly type: \"audio\";\n readonly audio: {\n readonly data: string;\n readonly format: \"mp3\" | \"wav\";\n };\n};\n\nexport type DataMessagePart<T = any> = {\n readonly type: \"data\";\n readonly name: string;\n readonly data: T;\n};\n\n/**\n * A JSON spec describing a tree of UI components to render.\n *\n * The agent emits a {@link GenerativeUIMessagePart} containing this spec, and\n * the consumer-provided component allowlist is used to resolve `component`\n * names. Any component referenced that is not present in the allowlist is\n * rejected with a typed error — the allowlist is the security boundary in the\n * default same-realm rendering path.\n */\nexport type GenerativeUINode =\n | string\n | {\n /** Allowlisted component name (resolved against the consumer registry). */\n readonly component: string;\n /** Props passed to the resolved component (must be JSON-serializable). */\n readonly props?: Record<string, unknown>;\n /** Optional children — strings render as text, objects recurse. */\n readonly children?: readonly GenerativeUINode[];\n /** Optional stable key for React reconciliation. */\n readonly key?: string;\n };\n\n/**\n * The root spec for a generative UI tree.\n */\nexport type GenerativeUISpec = {\n /** Root node(s) to render. */\n readonly root: GenerativeUINode | readonly GenerativeUINode[];\n};\n\n/**\n * A message part that carries a JSON spec describing UI to render.\n *\n * Render with `<MessagePrimitive.GenerativeUI components={...} />`. The\n * primitive resolves component names against the consumer-provided allowlist\n * — any unknown name throws a typed error rather than rendering. Stream-\n * friendly: a partially-streamed spec renders progressively.\n */\nexport type GenerativeUIMessagePart = {\n readonly type: \"generative-ui\";\n /** The JSON spec describing the UI tree. */\n readonly spec: GenerativeUISpec;\n /** Optional id (useful for replays / stable keys). */\n readonly id?: string;\n readonly parentId?: string;\n};\n\nexport type McpAppMetadata = {\n readonly resourceUri: string;\n readonly mimeType?: string;\n readonly visibility?: readonly (\"model\" | \"app\")[];\n /** Routable server identity emitted by the agent stack when multiple MCP servers back one agent; for @ag-ui/mcp-apps-middleware this is the configured serverId, falling back to its serverHash. */\n readonly serverId?: string;\n};\n\nexport const MCP_APP_URI_SCHEME = \"ui://\";\n\nexport const isMcpAppUri = (uri: string | undefined): boolean =>\n !!uri?.startsWith(MCP_APP_URI_SCHEME);\n\nexport type ToolCallMessagePartMcpMetadata = {\n readonly app?: McpAppMetadata;\n};\n\nexport type ToolApprovalOptionKind =\n | \"allow-once\"\n | \"allow-always\"\n | \"reject-once\"\n | \"reject-always\";\n\nexport type ToolApprovalOption = {\n /** Opaque, host-defined identifier. Scope semantics (session vs project vs global) belong to the option supplier. */\n readonly id: string;\n /**\n * Decision class. Drives approved-resolution and default rendering.\n * Open union: `_`-prefixed custom kinds are never auto-resolved and the\n * default kit skips them; they must be answered with an explicit\n * `approved` value (optionally alongside the `optionId`).\n */\n readonly kind: ToolApprovalOptionKind | (string & {});\n /** Human label. Renderers supply defaults per kind when omitted. */\n readonly label?: string;\n readonly description?: string;\n /** Patterns or rules this option would persist, shown before the user commits. Supplied by the host; never derived by the library. */\n readonly grants?: readonly string[];\n /** Opt-in confirmation step before this option resolves. */\n readonly confirm?: boolean | { title?: string; description?: string };\n};\n\nexport type ToolApprovalResponse =\n | { readonly approved: boolean; readonly reason?: string }\n | { readonly optionId: string; readonly reason?: string }\n | {\n readonly approved: boolean;\n readonly optionId: string;\n readonly reason?: string;\n };\n\nexport type ToolCallMessagePart<\n TArgs = ReadonlyJSONObject,\n TResult = unknown,\n> = {\n /** Identifies this part as a tool call. */\n readonly type: \"tool-call\";\n /** Stable identifier for this invocation of the tool. */\n readonly toolCallId: string;\n /** Name of the tool requested by the model. */\n readonly toolName: string;\n /**\n * Arguments supplied by the model. During streaming this is a partial parse:\n * fields may be missing or incomplete. From a tool-call renderer, use\n * `useToolArgsStatus` to detect which fields are still arriving.\n */\n readonly args: TArgs;\n /** Result returned by the tool, if it has completed. */\n readonly result?: TResult | undefined;\n /** Whether the result represents a tool execution error. */\n readonly isError?: boolean | undefined;\n /** Raw JSON argument text streamed by the model. */\n readonly argsText: string;\n /** UI-only artifact associated with the tool result. */\n readonly artifact?: unknown;\n /** Wall-clock timing for this call, when the runtime or host tracks it. */\n readonly timing?: ToolCallTiming;\n /** MCP app metadata associated with this tool call, when present. */\n readonly mcp?: ToolCallMessagePartMcpMetadata;\n /** Provider metadata associated with this tool call, when present. */\n readonly providerMetadata?: PartProviderMetadata;\n /** Content returned to the model for this tool result. */\n readonly modelContent?: readonly ToolModelContentPart[] | undefined;\n /** Human-input request that must be resolved before the run can continue. */\n readonly interrupt?: { type: \"human\"; payload: unknown };\n /** Server-side approval gate. `respondToApproval` may only be called while `approved` is undefined and no `resolution` is recorded. */\n readonly approval?: {\n readonly id: string;\n readonly approved?: boolean;\n readonly reason?: string;\n readonly isAutomatic?: boolean;\n /** Available decisions for this call. Absent: a plain allow / deny pair. */\n readonly options?: readonly ToolApprovalOption[];\n /** The option chosen at resolution, when options were present. */\n readonly optionId?: string;\n /** Terminal non-decision state: the request was cancelled or expired without a user decision. Set by the host. */\n readonly resolution?: \"cancelled\" | \"expired\";\n };\n /** Parent message-part ID when this part belongs to a nested structure. */\n readonly parentId?: string;\n /**\n * Nested thread messages produced by this tool call, for example a sub-agent\n * conversation.\n */\n readonly messages?: readonly ThreadMessage[];\n};\n\nexport type ThreadUserMessagePart =\n | TextMessagePart\n | ImageMessagePart\n | FileMessagePart\n | DataMessagePart\n | Unstable_AudioMessagePart;\n\nexport type ThreadAssistantMessagePart =\n | TextMessagePart\n | ReasoningMessagePart\n | ToolCallMessagePart\n | SourceMessagePart\n | FileMessagePart\n | ImageMessagePart\n | DataMessagePart\n | GenerativeUIMessagePart;\n\nexport type MessagePartStatus =\n | {\n readonly type: \"running\";\n }\n | {\n readonly type: \"complete\";\n }\n | {\n readonly type: \"incomplete\";\n readonly reason:\n | \"cancelled\"\n | \"length\"\n | \"content-filter\"\n | \"other\"\n | \"error\";\n readonly error?: unknown;\n };\n\nexport type MessagePartStreamStatus =\n | {\n readonly type: \"running\";\n }\n | {\n readonly type: \"complete\";\n }\n | {\n readonly type: \"incomplete\";\n readonly reason:\n | \"cancelled\"\n | \"length\"\n | \"content-filter\"\n | \"other\"\n | \"error\";\n };\n\nexport type ToolCallMessagePartStatus =\n | {\n /** The tool call is waiting for UI or human input before continuing. */\n readonly type: \"requires-action\";\n /** Reason the tool call requires action. */\n readonly reason: \"interrupt\";\n }\n | MessagePartStatus;\n\nexport type MessageStatus =\n | {\n readonly type: \"running\";\n }\n | {\n readonly type: \"requires-action\";\n readonly reason: \"tool-calls\" | \"interrupt\";\n }\n | {\n readonly type: \"complete\";\n readonly reason: \"stop\" | \"unknown\";\n }\n | {\n readonly type: \"incomplete\";\n readonly reason:\n | \"cancelled\"\n | \"tool-calls\"\n | \"length\"\n | \"content-filter\"\n | \"other\"\n | \"error\";\n readonly error?: ReadonlyJSONValue;\n };\n\nexport type MessageTiming = {\n readonly streamStartTime: number;\n readonly firstTokenTime?: number;\n readonly totalStreamTime?: number;\n readonly tokenCount?: number;\n readonly tokensPerSecond?: number;\n readonly totalChunks: number;\n readonly toolCallCount: number;\n};\n\nexport type ThreadStep = {\n readonly messageId?: string;\n readonly usage?:\n | {\n readonly inputTokens: number;\n readonly outputTokens: number;\n }\n | undefined;\n};\n\ntype MessageCommonProps = {\n readonly id: string;\n readonly createdAt: Date;\n};\n\nexport type ThreadSystemMessage = MessageCommonProps & {\n readonly role: \"system\";\n readonly content: readonly [TextMessagePart];\n readonly metadata: {\n readonly unstable_state?: undefined;\n readonly unstable_annotations?: undefined;\n readonly unstable_data?: undefined;\n readonly steps?: undefined;\n readonly submittedFeedback?: undefined;\n readonly timing?: undefined;\n readonly custom: Record<string, unknown>;\n };\n};\n\nexport type ThreadUserMessage = MessageCommonProps & {\n readonly role: \"user\";\n readonly content: readonly ThreadUserMessagePart[];\n readonly attachments: readonly CompleteAttachment[];\n readonly metadata: {\n readonly unstable_state?: undefined;\n readonly unstable_annotations?: undefined;\n readonly unstable_data?: undefined;\n readonly steps?: undefined;\n readonly submittedFeedback?: undefined;\n readonly timing?: undefined;\n readonly isOptimistic?: boolean;\n readonly custom: Record<string, unknown>;\n };\n};\n\nexport type ThreadAssistantMessage = MessageCommonProps & {\n readonly role: \"assistant\";\n readonly content: readonly ThreadAssistantMessagePart[];\n readonly status: MessageStatus;\n readonly metadata: {\n readonly unstable_state: ReadonlyJSONValue;\n readonly unstable_annotations: readonly ReadonlyJSONValue[];\n readonly unstable_data: readonly ReadonlyJSONValue[];\n readonly steps: readonly ThreadStep[];\n readonly submittedFeedback?: { readonly type: \"positive\" | \"negative\" };\n readonly timing?: MessageTiming;\n /**\n * Marks a client-side optimistic placeholder. Such messages are evicted\n * once off the head branch and are never persisted.\n */\n readonly isOptimistic?: boolean;\n readonly custom: Record<string, unknown>;\n };\n};\n\ntype BaseThreadMessage = {\n readonly status?: ThreadAssistantMessage[\"status\"];\n readonly metadata: {\n readonly unstable_state?: ReadonlyJSONValue;\n readonly unstable_annotations?: readonly ReadonlyJSONValue[];\n readonly unstable_data?: readonly ReadonlyJSONValue[];\n readonly steps?: readonly ThreadStep[];\n readonly submittedFeedback?: { readonly type: \"positive\" | \"negative\" };\n readonly timing?: MessageTiming;\n readonly isOptimistic?: boolean;\n readonly custom: Record<string, unknown>;\n };\n readonly attachments?: ThreadUserMessage[\"attachments\"];\n};\n\nexport type ThreadMessage = BaseThreadMessage &\n (ThreadSystemMessage | ThreadUserMessage | ThreadAssistantMessage);\n\nexport type MessageRole = ThreadMessage[\"role\"];\n\nexport type RunConfig = {\n readonly custom?: Record<string, unknown>;\n};\n\nexport type AppendMessage = Omit<ThreadMessage, \"id\"> & {\n parentId: string | null;\n\n /** The ID of the message that was edited or undefined. */\n sourceId: string | null;\n runConfig: RunConfig | undefined;\n startRun?: boolean | undefined;\n /** Process this message next; only meaningful for queue-capable runtimes. */\n steer?: boolean | undefined;\n};\n"],"mappings":";AAmJA,MAAagD,qBAAqB;AAElC,MAAaC,eAAeC,QAC1B,CAAC,CAACA,KAAKC,WAAWH,kBAAkB"}
|
|
1
|
+
{"version":3,"file":"message.js","names":["ReadonlyJSONObject","ReadonlyJSONValue","ToolCallTiming","ToolModelContentPart","CompleteAttachment","PartProviderMetadata","providerName","TextMessagePart","type","text","status","MessagePartStreamStatus","providerMetadata","parentId","ReasoningMessagePart","unstable_summary","SourceProviderMetadata","SourceMessagePart","sourceType","id","url","title","mediaType","filename","ImageMessagePart","image","FileMessagePart","data","mimeType","Unstable_AudioMessagePart","audio","format","DataMessagePart","name","T","GenerativeUINode","component","props","Record","children","key","GenerativeUISpec","root","GenerativeUIMessagePart","spec","McpAppMetadata","resourceUri","visibility","serverId","MCP_APP_URI_SCHEME","isMcpAppUri","uri","startsWith","ToolCallMessagePartMcpMetadata","app","ToolApprovalOptionKind","ToolApprovalOption","kind","label","description","grants","confirm","ToolApprovalResponse","approved","reason","optionId","ToolCallMessagePart","toolCallId","toolName","args","TArgs","result","TResult","isError","argsText","artifact","timing","mcp","modelContent","interrupt","payload","approval","isAutomatic","options","resolution","messages","ThreadMessage","ThreadUserMessagePart","ThreadAssistantMessagePart","MessagePartStatus","error","ToolCallMessagePartStatus","MessageStatus","MessageTiming","streamStartTime","firstTokenTime","totalStreamTime","tokenCount","tokensPerSecond","totalChunks","toolCallCount","ThreadStep","messageId","usage","inputTokens","outputTokens","MessageCommonProps","createdAt","Date","ThreadSystemMessage","role","content","metadata","unstable_state","unstable_annotations","unstable_data","steps","submittedFeedback","custom","ThreadUserMessage","attachments","isOptimistic","ThreadAssistantMessage","BaseThreadMessage","MessageRole","RunConfig","AppendMessage","Omit","sourceId","runConfig","startRun","steer"],"sources":["../../src/types/message.ts"],"sourcesContent":["import type {\n ReadonlyJSONObject,\n ReadonlyJSONValue,\n} from \"assistant-stream/utils\";\nimport type { ToolCallTiming, ToolModelContentPart } from \"assistant-stream\";\nimport type { CompleteAttachment } from \"./attachment\";\n\nexport type { ToolCallTiming, ToolModelContentPart };\n\nexport type PartProviderMetadata = {\n readonly [providerName: string]: ReadonlyJSONObject;\n};\n\nexport type TextMessagePart = {\n readonly type: \"text\";\n readonly text: string;\n readonly status?: MessagePartStreamStatus;\n readonly providerMetadata?: PartProviderMetadata;\n readonly parentId?: string;\n};\n\nexport type ReasoningMessagePart = {\n readonly type: \"reasoning\";\n readonly text: string;\n readonly status?: MessagePartStreamStatus;\n readonly unstable_summary?: string;\n readonly providerMetadata?: PartProviderMetadata;\n readonly parentId?: string;\n};\n\nexport type SourceProviderMetadata = PartProviderMetadata;\n\nexport type SourceMessagePart =\n | {\n readonly type: \"source\";\n readonly sourceType: \"url\";\n readonly id: string;\n readonly url: string;\n readonly title?: string;\n readonly providerMetadata?: SourceProviderMetadata;\n readonly parentId?: string;\n }\n | {\n readonly type: \"source\";\n readonly sourceType: \"document\";\n readonly id: string;\n readonly url?: undefined;\n readonly title: string;\n readonly mediaType: string;\n readonly filename?: string;\n readonly providerMetadata?: SourceProviderMetadata;\n readonly parentId?: string;\n };\n\nexport type ImageMessagePart = {\n readonly type: \"image\";\n readonly image: string;\n readonly filename?: string;\n};\n\nexport type FileMessagePart = {\n readonly type: \"file\";\n readonly filename?: string;\n readonly data: string;\n readonly mimeType: string;\n /** How `data` goes on the wire: a url or id reference; omitted = inferred (http(s) → url, else base64). \"url\" is honored by the LangChain-family, A2A, AG-UI, and Google ADK runtimes; \"id\" by the LangChain family only. */\n readonly sourceType?: \"url\" | \"id\";\n readonly parentId?: string;\n};\n\n/**\n * @deprecated Use {@link FileMessagePart} with an `audio/*` mime type. `file`\n * is the carrier for every non-image binary modality: it is a member of both\n * the user and assistant unions, carries a filename, and can declare how its\n * payload goes on the wire, none of which this shape can express. The payload\n * form a `file` part needs is still adapter specific; see the Part Types\n * section of the message primitive docs. Honored everywhere it is accepted; it\n * will not gain fields.\n */\nexport type Unstable_AudioMessagePart = {\n readonly type: \"audio\";\n readonly audio: {\n readonly data: string;\n readonly format: \"mp3\" | \"wav\";\n };\n};\n\nexport type DataMessagePart<T = any> = {\n readonly type: \"data\";\n readonly name: string;\n readonly data: T;\n};\n\n/**\n * A JSON spec describing a tree of UI components to render.\n *\n * The agent emits a {@link GenerativeUIMessagePart} containing this spec, and\n * the consumer-provided component allowlist is used to resolve `component`\n * names. Any component referenced that is not present in the allowlist is\n * rejected with a typed error — the allowlist is the security boundary in the\n * default same-realm rendering path.\n */\nexport type GenerativeUINode =\n | string\n | {\n /** Allowlisted component name (resolved against the consumer registry). */\n readonly component: string;\n /** Props passed to the resolved component (must be JSON-serializable). */\n readonly props?: Record<string, unknown>;\n /** Optional children — strings render as text, objects recurse. */\n readonly children?: readonly GenerativeUINode[];\n /** Optional stable key for React reconciliation. */\n readonly key?: string;\n };\n\n/**\n * The root spec for a generative UI tree.\n */\nexport type GenerativeUISpec = {\n /** Root node(s) to render. */\n readonly root: GenerativeUINode | readonly GenerativeUINode[];\n};\n\n/**\n * A message part that carries a JSON spec describing UI to render.\n *\n * Render with `<MessagePrimitive.GenerativeUI components={...} />`. The\n * primitive resolves component names against the consumer-provided allowlist\n * — any unknown name throws a typed error rather than rendering. Stream-\n * friendly: a partially-streamed spec renders progressively.\n */\nexport type GenerativeUIMessagePart = {\n readonly type: \"generative-ui\";\n /** The JSON spec describing the UI tree. */\n readonly spec: GenerativeUISpec;\n /** Optional id (useful for replays / stable keys). */\n readonly id?: string;\n readonly parentId?: string;\n};\n\nexport type McpAppMetadata = {\n readonly resourceUri: string;\n readonly mimeType?: string;\n readonly visibility?: readonly (\"model\" | \"app\")[];\n /** Routable server identity emitted by the agent stack when multiple MCP servers back one agent; for @ag-ui/mcp-apps-middleware this is the configured serverId, falling back to its serverHash. */\n readonly serverId?: string;\n};\n\nexport const MCP_APP_URI_SCHEME = \"ui://\";\n\nexport const isMcpAppUri = (uri: string | undefined): boolean =>\n !!uri?.startsWith(MCP_APP_URI_SCHEME);\n\nexport type ToolCallMessagePartMcpMetadata = {\n readonly app?: McpAppMetadata;\n};\n\nexport type ToolApprovalOptionKind =\n | \"allow-once\"\n | \"allow-always\"\n | \"reject-once\"\n | \"reject-always\";\n\nexport type ToolApprovalOption = {\n /** Opaque, host-defined identifier. Scope semantics (session vs project vs global) belong to the option supplier. */\n readonly id: string;\n /**\n * Decision class. Drives approved-resolution and default rendering.\n * Open union: `_`-prefixed custom kinds are never auto-resolved and the\n * default kit skips them; they must be answered with an explicit\n * `approved` value (optionally alongside the `optionId`).\n */\n readonly kind: ToolApprovalOptionKind | (string & {});\n /** Human label. Renderers supply defaults per kind when omitted. */\n readonly label?: string;\n readonly description?: string;\n /** Patterns or rules this option would persist, shown before the user commits. Supplied by the host; never derived by the library. */\n readonly grants?: readonly string[];\n /** Opt-in confirmation step before this option resolves. */\n readonly confirm?: boolean | { title?: string; description?: string };\n};\n\nexport type ToolApprovalResponse =\n | { readonly approved: boolean; readonly reason?: string }\n | { readonly optionId: string; readonly reason?: string }\n | {\n readonly approved: boolean;\n readonly optionId: string;\n readonly reason?: string;\n };\n\nexport type ToolCallMessagePart<\n TArgs = ReadonlyJSONObject,\n TResult = unknown,\n> = {\n /** Identifies this part as a tool call. */\n readonly type: \"tool-call\";\n /** Stable identifier for this invocation of the tool. */\n readonly toolCallId: string;\n /** Name of the tool requested by the model. */\n readonly toolName: string;\n /**\n * Arguments supplied by the model. During streaming this is a partial parse:\n * fields may be missing or incomplete. From a tool-call renderer, use\n * `useToolArgsStatus` to detect which fields are still arriving.\n */\n readonly args: TArgs;\n /** Result returned by the tool, if it has completed. */\n readonly result?: TResult | undefined;\n /** Whether the result represents a tool execution error. */\n readonly isError?: boolean | undefined;\n /** Raw JSON argument text streamed by the model. */\n readonly argsText: string;\n /** UI-only artifact associated with the tool result. */\n readonly artifact?: unknown;\n /** Wall-clock timing for this call, when the runtime or host tracks it. */\n readonly timing?: ToolCallTiming;\n /** MCP app metadata associated with this tool call, when present. */\n readonly mcp?: ToolCallMessagePartMcpMetadata;\n /** Provider metadata associated with this tool call, when present. */\n readonly providerMetadata?: PartProviderMetadata;\n /** Content returned to the model for this tool result. */\n readonly modelContent?: readonly ToolModelContentPart[] | undefined;\n /** Human-input request that must be resolved before the run can continue. */\n readonly interrupt?: { type: \"human\"; payload: unknown };\n /** Server-side approval gate. `respondToApproval` may only be called while `approved` is undefined and no `resolution` is recorded. */\n readonly approval?: {\n readonly id: string;\n readonly approved?: boolean;\n readonly reason?: string;\n readonly isAutomatic?: boolean;\n /** Available decisions for this call. Absent: a plain allow / deny pair. */\n readonly options?: readonly ToolApprovalOption[];\n /** The option chosen at resolution, when options were present. */\n readonly optionId?: string;\n /** Terminal non-decision state: the request was cancelled or expired without a user decision. Set by the host. */\n readonly resolution?: \"cancelled\" | \"expired\";\n };\n /** Parent message-part ID when this part belongs to a nested structure. */\n readonly parentId?: string;\n /**\n * Nested thread messages produced by this tool call, for example a sub-agent\n * conversation.\n */\n readonly messages?: readonly ThreadMessage[];\n};\n\nexport type ThreadUserMessagePart =\n | TextMessagePart\n | ImageMessagePart\n | FileMessagePart\n | DataMessagePart\n | Unstable_AudioMessagePart;\n\nexport type ThreadAssistantMessagePart =\n | TextMessagePart\n | ReasoningMessagePart\n | ToolCallMessagePart\n | SourceMessagePart\n | FileMessagePart\n | ImageMessagePart\n | DataMessagePart\n | GenerativeUIMessagePart;\n\nexport type MessagePartStatus =\n | {\n readonly type: \"running\";\n }\n | {\n readonly type: \"complete\";\n }\n | {\n readonly type: \"incomplete\";\n readonly reason:\n | \"cancelled\"\n | \"length\"\n | \"content-filter\"\n | \"other\"\n | \"error\";\n readonly error?: unknown;\n };\n\nexport type MessagePartStreamStatus =\n | {\n readonly type: \"running\";\n }\n | {\n readonly type: \"complete\";\n }\n | {\n readonly type: \"incomplete\";\n readonly reason:\n | \"cancelled\"\n | \"length\"\n | \"content-filter\"\n | \"other\"\n | \"error\";\n };\n\nexport type ToolCallMessagePartStatus =\n | {\n /** The tool call is waiting for UI or human input before continuing. */\n readonly type: \"requires-action\";\n /** Reason the tool call requires action. */\n readonly reason: \"interrupt\";\n }\n | MessagePartStatus;\n\nexport type MessageStatus =\n | {\n readonly type: \"running\";\n }\n | {\n readonly type: \"requires-action\";\n readonly reason: \"tool-calls\" | \"interrupt\";\n }\n | {\n readonly type: \"complete\";\n readonly reason: \"stop\" | \"unknown\";\n }\n | {\n readonly type: \"incomplete\";\n readonly reason:\n | \"cancelled\"\n | \"tool-calls\"\n | \"length\"\n | \"content-filter\"\n | \"other\"\n | \"error\";\n readonly error?: ReadonlyJSONValue;\n };\n\nexport type MessageTiming = {\n readonly streamStartTime: number;\n readonly firstTokenTime?: number;\n readonly totalStreamTime?: number;\n readonly tokenCount?: number;\n readonly tokensPerSecond?: number;\n readonly totalChunks: number;\n readonly toolCallCount: number;\n};\n\nexport type ThreadStep = {\n readonly messageId?: string;\n readonly usage?:\n | {\n readonly inputTokens: number;\n readonly outputTokens: number;\n }\n | undefined;\n};\n\ntype MessageCommonProps = {\n readonly id: string;\n readonly createdAt: Date;\n};\n\nexport type ThreadSystemMessage = MessageCommonProps & {\n readonly role: \"system\";\n readonly content: readonly [TextMessagePart];\n readonly metadata: {\n readonly unstable_state?: undefined;\n readonly unstable_annotations?: undefined;\n readonly unstable_data?: undefined;\n readonly steps?: undefined;\n readonly submittedFeedback?: undefined;\n readonly timing?: undefined;\n readonly custom: Record<string, unknown>;\n };\n};\n\nexport type ThreadUserMessage = MessageCommonProps & {\n readonly role: \"user\";\n readonly content: readonly ThreadUserMessagePart[];\n readonly attachments: readonly CompleteAttachment[];\n readonly metadata: {\n readonly unstable_state?: undefined;\n readonly unstable_annotations?: undefined;\n readonly unstable_data?: undefined;\n readonly steps?: undefined;\n readonly submittedFeedback?: undefined;\n readonly timing?: undefined;\n readonly isOptimistic?: boolean;\n readonly custom: Record<string, unknown>;\n };\n};\n\nexport type ThreadAssistantMessage = MessageCommonProps & {\n readonly role: \"assistant\";\n readonly content: readonly ThreadAssistantMessagePart[];\n readonly status: MessageStatus;\n readonly metadata: {\n readonly unstable_state: ReadonlyJSONValue;\n readonly unstable_annotations: readonly ReadonlyJSONValue[];\n readonly unstable_data: readonly ReadonlyJSONValue[];\n readonly steps: readonly ThreadStep[];\n readonly submittedFeedback?: { readonly type: \"positive\" | \"negative\" };\n readonly timing?: MessageTiming;\n /**\n * Marks a client-side optimistic placeholder. Such messages are evicted\n * once off the head branch and are never persisted.\n */\n readonly isOptimistic?: boolean;\n readonly custom: Record<string, unknown>;\n };\n};\n\ntype BaseThreadMessage = {\n readonly status?: ThreadAssistantMessage[\"status\"];\n readonly metadata: {\n readonly unstable_state?: ReadonlyJSONValue;\n readonly unstable_annotations?: readonly ReadonlyJSONValue[];\n readonly unstable_data?: readonly ReadonlyJSONValue[];\n readonly steps?: readonly ThreadStep[];\n readonly submittedFeedback?: { readonly type: \"positive\" | \"negative\" };\n readonly timing?: MessageTiming;\n readonly isOptimistic?: boolean;\n readonly custom: Record<string, unknown>;\n };\n readonly attachments?: ThreadUserMessage[\"attachments\"];\n};\n\nexport type ThreadMessage = BaseThreadMessage &\n (ThreadSystemMessage | ThreadUserMessage | ThreadAssistantMessage);\n\nexport type MessageRole = ThreadMessage[\"role\"];\n\nexport type RunConfig = {\n readonly custom?: Record<string, unknown>;\n};\n\nexport type AppendMessage = Omit<ThreadMessage, \"id\"> & {\n parentId: string | null;\n\n /** The ID of the message that was edited or undefined. */\n sourceId: string | null;\n runConfig: RunConfig | undefined;\n startRun?: boolean | undefined;\n /** Process this message next; only meaningful for queue-capable runtimes. */\n steer?: boolean | undefined;\n};\n"],"mappings":";AAoJA,MAAaiD,qBAAqB;AAElC,MAAaC,eAAeC,QAC1B,CAAC,CAACA,KAAKC,WAAWH,kBAAkB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"description": "Framework-agnostic core runtime for assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"assistant",
|
|
@@ -58,14 +58,8 @@
|
|
|
58
58
|
"README.md"
|
|
59
59
|
],
|
|
60
60
|
"sideEffects": false,
|
|
61
|
-
"scripts": {
|
|
62
|
-
"build": "aui-build",
|
|
63
|
-
"test": "vitest run",
|
|
64
|
-
"test:react-compiler": "vitest run --config vitest.react-compiler.config.ts",
|
|
65
|
-
"test:watch": "vitest"
|
|
66
|
-
},
|
|
67
61
|
"dependencies": {
|
|
68
|
-
"assistant-stream": "^0.3.
|
|
62
|
+
"assistant-stream": "^0.3.35",
|
|
69
63
|
"nanoid": "^6.0.0"
|
|
70
64
|
},
|
|
71
65
|
"optionalDevDependencies": {
|
|
@@ -94,18 +88,18 @@
|
|
|
94
88
|
}
|
|
95
89
|
},
|
|
96
90
|
"devDependencies": {
|
|
97
|
-
"@assistant-ui/store": "workspace:*",
|
|
98
|
-
"@assistant-ui/tap": "workspace:*",
|
|
99
|
-
"@assistant-ui/vite": "workspace:*",
|
|
100
|
-
"@assistant-ui/x-buildutils": "workspace:*",
|
|
101
91
|
"@testing-library/react": "^16.3.2",
|
|
102
92
|
"@types/react": "^19.2.17",
|
|
103
|
-
"assistant-cloud": "workspace:*",
|
|
104
93
|
"jsdom": "^29.1.1",
|
|
105
94
|
"react": "^19.2.8",
|
|
106
95
|
"react-dom": "^19.2.8",
|
|
107
96
|
"vitest": "^4.1.10",
|
|
108
|
-
"zustand": "^5.0.14"
|
|
97
|
+
"zustand": "^5.0.14",
|
|
98
|
+
"@assistant-ui/store": "0.3.7",
|
|
99
|
+
"@assistant-ui/tap": "0.9.10",
|
|
100
|
+
"@assistant-ui/vite": "0.0.11",
|
|
101
|
+
"@assistant-ui/x-buildutils": "0.0.21",
|
|
102
|
+
"assistant-cloud": "0.1.38"
|
|
109
103
|
},
|
|
110
104
|
"publishConfig": {
|
|
111
105
|
"access": "public",
|
|
@@ -119,5 +113,11 @@
|
|
|
119
113
|
},
|
|
120
114
|
"bugs": {
|
|
121
115
|
"url": "https://github.com/assistant-ui/assistant-ui/issues"
|
|
116
|
+
},
|
|
117
|
+
"scripts": {
|
|
118
|
+
"build": "aui-build",
|
|
119
|
+
"test": "vitest run",
|
|
120
|
+
"test:react-compiler": "vitest run --config vitest.react-compiler.config.ts",
|
|
121
|
+
"test:watch": "vitest"
|
|
122
122
|
}
|
|
123
|
-
}
|
|
123
|
+
}
|
|
@@ -32,6 +32,7 @@ type AuiV0MessagePart =
|
|
|
32
32
|
| {
|
|
33
33
|
readonly type: "reasoning";
|
|
34
34
|
readonly text: string;
|
|
35
|
+
readonly unstable_summary?: string;
|
|
35
36
|
}
|
|
36
37
|
| {
|
|
37
38
|
readonly type: "source";
|
|
@@ -226,7 +227,13 @@ export function auiV0Encode(message: ThreadMessage): AuiV0Message {
|
|
|
226
227
|
return { type: "text", text: part.text };
|
|
227
228
|
|
|
228
229
|
case "reasoning":
|
|
229
|
-
return {
|
|
230
|
+
return {
|
|
231
|
+
type: "reasoning",
|
|
232
|
+
text: part.text,
|
|
233
|
+
...(part.unstable_summary !== undefined
|
|
234
|
+
? { unstable_summary: part.unstable_summary }
|
|
235
|
+
: undefined),
|
|
236
|
+
};
|
|
230
237
|
|
|
231
238
|
case "source":
|
|
232
239
|
if (part.sourceType === "url") {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AppendMessage, ThreadMessage } from "../../types/message";
|
|
2
2
|
import type { CompleteAttachment } from "../../types/attachment";
|
|
3
3
|
import { getThreadMessageText } from "../../utils/text";
|
|
4
|
-
import {
|
|
4
|
+
import { liftNonTextParts } from "../../adapters/attachment";
|
|
5
5
|
import type { AttachmentAdapter } from "../../adapters/attachment";
|
|
6
6
|
import type { DictationAdapter } from "../../adapters/speech";
|
|
7
7
|
import type { SendOptions } from "../interfaces/composer-runtime-core";
|
|
@@ -26,8 +26,6 @@ export class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {
|
|
|
26
26
|
return this.runtime.adapters?.dictation;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
private _previousText;
|
|
30
|
-
private _previousAttachments: readonly CompleteAttachment[];
|
|
31
29
|
private _nonTextPassthrough: readonly ThreadMessage["content"][number][];
|
|
32
30
|
private _parentId: string | null;
|
|
33
31
|
private _sourceId: string | null;
|
|
@@ -58,24 +56,24 @@ export class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {
|
|
|
58
56
|
this.endEditCallback = endEditCallback;
|
|
59
57
|
this._parentId = parentId;
|
|
60
58
|
this._sourceId = message.id;
|
|
61
|
-
this.
|
|
62
|
-
this.setText(this._previousText);
|
|
59
|
+
this.setText(getThreadMessageText(message));
|
|
63
60
|
|
|
64
61
|
this.setRole(message.role);
|
|
65
62
|
|
|
63
|
+
let attachments: readonly CompleteAttachment[];
|
|
66
64
|
if (message.role === "user") {
|
|
67
|
-
|
|
65
|
+
attachments = [
|
|
68
66
|
...(message.attachments ?? []),
|
|
69
67
|
...liftNonTextParts(message.content),
|
|
70
68
|
];
|
|
71
69
|
this._nonTextPassthrough = [];
|
|
72
70
|
} else {
|
|
73
|
-
|
|
71
|
+
attachments = message.attachments ?? [];
|
|
74
72
|
this._nonTextPassthrough = message.content.filter(
|
|
75
73
|
(p) => p.type !== "text",
|
|
76
74
|
);
|
|
77
75
|
}
|
|
78
|
-
this.setAttachments(
|
|
76
|
+
this.setAttachments(attachments);
|
|
79
77
|
|
|
80
78
|
this.setRunConfig({ ...runtime.composer.runConfig });
|
|
81
79
|
}
|
|
@@ -92,49 +90,33 @@ export class DefaultEditComposerRuntimeCore extends BaseComposerRuntimeCore {
|
|
|
92
90
|
message: Omit<AppendMessage, "parentId" | "sourceId">,
|
|
93
91
|
options?: SendOptions,
|
|
94
92
|
) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
93
|
+
const content =
|
|
94
|
+
this._nonTextPassthrough.length > 0
|
|
95
|
+
? ([
|
|
96
|
+
...message.content,
|
|
97
|
+
...this._nonTextPassthrough,
|
|
98
|
+
] as AppendMessage["content"])
|
|
99
|
+
: message.content;
|
|
100
|
+
// Gate live state against the new branch's prefix (messages up to the
|
|
101
|
+
// parent): an unchanged interactable re-stamps the prior baseline, an
|
|
102
|
+
// interactable edited since the original message stamps its newest state.
|
|
103
|
+
const messages = this.runtime.messages;
|
|
104
|
+
const parentIndex =
|
|
105
|
+
this._parentId === null
|
|
106
|
+
? -1
|
|
107
|
+
: messages.findIndex((m) => m.id === this._parentId);
|
|
108
|
+
const composerMetadata = gateInteractableComposerMetadata(
|
|
109
|
+
this.runtime.getModelContext().unstable_composerMetadata,
|
|
110
|
+
messages.slice(0, parentIndex + 1),
|
|
100
111
|
);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
? ([
|
|
110
|
-
...message.content,
|
|
111
|
-
...this._nonTextPassthrough,
|
|
112
|
-
] as AppendMessage["content"])
|
|
113
|
-
: message.content;
|
|
114
|
-
// Gate live state against the new branch's prefix (messages up to the
|
|
115
|
-
// parent): an unchanged interactable re-stamps the prior baseline, an
|
|
116
|
-
// interactable edited since the original message stamps its newest state.
|
|
117
|
-
const messages = this.runtime.messages;
|
|
118
|
-
const parentIndex =
|
|
119
|
-
this._parentId === null
|
|
120
|
-
? -1
|
|
121
|
-
: messages.findIndex((m) => m.id === this._parentId);
|
|
122
|
-
const composerMetadata = gateInteractableComposerMetadata(
|
|
123
|
-
this.runtime.getModelContext().unstable_composerMetadata,
|
|
124
|
-
messages.slice(0, parentIndex + 1),
|
|
125
|
-
);
|
|
126
|
-
const enriched = this.enrichWithComposerMetadata(
|
|
127
|
-
message,
|
|
128
|
-
composerMetadata,
|
|
129
|
-
);
|
|
130
|
-
appendTask = this.runtime.append({
|
|
131
|
-
...enriched,
|
|
132
|
-
content,
|
|
133
|
-
parentId: this._parentId,
|
|
134
|
-
sourceId: this._sourceId,
|
|
135
|
-
startRun: options?.startRun,
|
|
136
|
-
});
|
|
137
|
-
}
|
|
112
|
+
const enriched = this.enrichWithComposerMetadata(message, composerMetadata);
|
|
113
|
+
const appendTask = this.runtime.append({
|
|
114
|
+
...enriched,
|
|
115
|
+
content,
|
|
116
|
+
parentId: this._parentId,
|
|
117
|
+
sourceId: this._sourceId,
|
|
118
|
+
startRun: options?.startRun,
|
|
119
|
+
});
|
|
138
120
|
|
|
139
121
|
this.handleCancel();
|
|
140
122
|
return appendTask;
|
|
@@ -160,10 +160,14 @@ export const fromThreadMessageLike = (
|
|
|
160
160
|
const type = part.type;
|
|
161
161
|
switch (type) {
|
|
162
162
|
case "text":
|
|
163
|
-
case "reasoning":
|
|
164
163
|
if (!part.text?.trim()) return null;
|
|
165
164
|
return part;
|
|
166
165
|
|
|
166
|
+
case "reasoning":
|
|
167
|
+
if (!part.text?.trim() && !part.unstable_summary?.trim())
|
|
168
|
+
return null;
|
|
169
|
+
return part;
|
|
170
|
+
|
|
167
171
|
case "file":
|
|
168
172
|
case "source":
|
|
169
173
|
return part;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { AuiConfig, createAssistantClient } from "@assistant-ui/store/client";
|
|
3
|
+
import { RuntimeAdapter, Suggestions } from "../index";
|
|
4
|
+
import { ExternalStoreRuntimeCore } from "../../runtimes/internal";
|
|
5
|
+
import { AssistantRuntimeImpl } from "../../runtime/internal";
|
|
6
|
+
import type { ExternalStoreAdapter } from "../../runtimes/external-store/external-store-adapter";
|
|
7
|
+
|
|
8
|
+
type DemoMessage = { id: string; role: "user" | "assistant"; text: string };
|
|
9
|
+
|
|
10
|
+
const createClient = () => {
|
|
11
|
+
const adapter: ExternalStoreAdapter<DemoMessage> = {
|
|
12
|
+
messages: [
|
|
13
|
+
{ id: "u1", role: "user", text: "hi" },
|
|
14
|
+
{ id: "a1", role: "assistant", text: "hello" },
|
|
15
|
+
],
|
|
16
|
+
convertMessage: (message) => ({
|
|
17
|
+
id: message.id,
|
|
18
|
+
role: message.role,
|
|
19
|
+
content: [{ type: "text", text: message.text }],
|
|
20
|
+
}),
|
|
21
|
+
onNew: async () => {},
|
|
22
|
+
adapters: {
|
|
23
|
+
threadList: {
|
|
24
|
+
threadId: "t1",
|
|
25
|
+
threads: [{ status: "regular", id: "t1", title: "one" }],
|
|
26
|
+
archivedThreads: [{ status: "archived", id: "t2", title: "two" }],
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
const runtime = new AssistantRuntimeImpl(
|
|
31
|
+
new ExternalStoreRuntimeCore(adapter),
|
|
32
|
+
);
|
|
33
|
+
return createAssistantClient(
|
|
34
|
+
AuiConfig({
|
|
35
|
+
threads: RuntimeAdapter(runtime),
|
|
36
|
+
suggestions: Suggestions([
|
|
37
|
+
{ title: "a", label: "a", prompt: "a" },
|
|
38
|
+
{ title: "b", label: "b", prompt: "b" },
|
|
39
|
+
]),
|
|
40
|
+
}),
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Pins each by-index lookup's valid domain to the state array that backs it.
|
|
46
|
+
* Consumers (the vue by-index providers) guard with `index < array.length`
|
|
47
|
+
* against these arrays; a lookup changing its backing array must fail here.
|
|
48
|
+
*/
|
|
49
|
+
describe("by-index lookup domains", () => {
|
|
50
|
+
it("thread.message is indexed by thread.getState().messages", () => {
|
|
51
|
+
const handle = createClient();
|
|
52
|
+
const aui = handle.getClient();
|
|
53
|
+
const length = aui.thread.getState().messages.length;
|
|
54
|
+
expect(length).toBe(2);
|
|
55
|
+
expect(aui.thread.message({ index: length - 1 }).getState().id).toBe("a1");
|
|
56
|
+
expect(() => aui.thread.message({ index: length }).getState()).toThrow(
|
|
57
|
+
/out of bounds/,
|
|
58
|
+
);
|
|
59
|
+
handle.destroy();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("message.part is indexed by message.getState().parts", () => {
|
|
63
|
+
const handle = createClient();
|
|
64
|
+
const aui = handle.getClient();
|
|
65
|
+
const message = aui.thread.message({ index: 1 });
|
|
66
|
+
const length = message.getState().parts.length;
|
|
67
|
+
expect(length).toBe(1);
|
|
68
|
+
expect(message.part({ index: length - 1 }).getState().type).toBe("text");
|
|
69
|
+
expect(() => message.part({ index: length }).getState()).toThrow(
|
|
70
|
+
/out of bounds/,
|
|
71
|
+
);
|
|
72
|
+
handle.destroy();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("suggestions.suggestion is indexed by suggestions.getState().suggestions", () => {
|
|
76
|
+
const handle = createClient();
|
|
77
|
+
const aui = handle.getClient();
|
|
78
|
+
const length = aui.suggestions.getState().suggestions.length;
|
|
79
|
+
expect(length).toBe(2);
|
|
80
|
+
expect(
|
|
81
|
+
aui.suggestions.suggestion({ index: length - 1 }).getState().title,
|
|
82
|
+
).toBe("b");
|
|
83
|
+
expect(() =>
|
|
84
|
+
aui.suggestions.suggestion({ index: length }).getState(),
|
|
85
|
+
).toThrow(/out of bounds/);
|
|
86
|
+
handle.destroy();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("threads.item is indexed by threadIds and archivedThreadIds", () => {
|
|
90
|
+
const handle = createClient();
|
|
91
|
+
const aui = handle.getClient();
|
|
92
|
+
const state = aui.threads.getState();
|
|
93
|
+
expect(state.threadIds).toHaveLength(1);
|
|
94
|
+
expect(state.archivedThreadIds).toHaveLength(1);
|
|
95
|
+
expect(aui.threads.item({ index: 0, archived: false }).getState().id).toBe(
|
|
96
|
+
"t1",
|
|
97
|
+
);
|
|
98
|
+
expect(aui.threads.item({ index: 0, archived: true }).getState().id).toBe(
|
|
99
|
+
"t2",
|
|
100
|
+
);
|
|
101
|
+
expect(() =>
|
|
102
|
+
aui.threads.item({ index: 1, archived: false }).getState(),
|
|
103
|
+
).toThrow(/not found|out of bounds/);
|
|
104
|
+
expect(() =>
|
|
105
|
+
aui.threads.item({ index: 1, archived: true }).getState(),
|
|
106
|
+
).toThrow(/not found|out of bounds/);
|
|
107
|
+
handle.destroy();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -236,6 +236,33 @@ describe("auiV0Encode", () => {
|
|
|
236
236
|
]);
|
|
237
237
|
});
|
|
238
238
|
|
|
239
|
+
it("preserves reasoning summaries and omits absent summaries", () => {
|
|
240
|
+
const encoded = auiV0Encode({
|
|
241
|
+
id: "m1",
|
|
242
|
+
createdAt: new Date("2026-03-15T00:00:00.000Z"),
|
|
243
|
+
role: "assistant",
|
|
244
|
+
status: { type: "complete", reason: "stop" },
|
|
245
|
+
metadata: {
|
|
246
|
+
unstable_state: null,
|
|
247
|
+
unstable_annotations: [],
|
|
248
|
+
unstable_data: [],
|
|
249
|
+
steps: [],
|
|
250
|
+
custom: {},
|
|
251
|
+
},
|
|
252
|
+
content: [
|
|
253
|
+
{ type: "reasoning", text: "thinking", unstable_summary: "Planning" },
|
|
254
|
+
{ type: "reasoning", text: "more thinking", unstable_summary: "" },
|
|
255
|
+
{ type: "reasoning", text: "no summary" },
|
|
256
|
+
],
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
expect(encoded.content).toEqual([
|
|
260
|
+
{ type: "reasoning", text: "thinking", unstable_summary: "Planning" },
|
|
261
|
+
{ type: "reasoning", text: "more thinking", unstable_summary: "" },
|
|
262
|
+
{ type: "reasoning", text: "no summary" },
|
|
263
|
+
]);
|
|
264
|
+
});
|
|
265
|
+
|
|
239
266
|
it("drops per-part status from attachment content in the core cloud encoder", () => {
|
|
240
267
|
const encoded = auiV0Encode({
|
|
241
268
|
id: "m1",
|
|
@@ -306,6 +333,76 @@ describe("auiV0Encode", () => {
|
|
|
306
333
|
});
|
|
307
334
|
|
|
308
335
|
describe("auiV0Decode", () => {
|
|
336
|
+
it("round-trips a reasoning summary", () => {
|
|
337
|
+
const encoded = auiV0Encode({
|
|
338
|
+
id: "local",
|
|
339
|
+
createdAt: new Date("2026-03-15T00:00:00.000Z"),
|
|
340
|
+
role: "assistant",
|
|
341
|
+
status: { type: "complete", reason: "stop" },
|
|
342
|
+
metadata: {
|
|
343
|
+
unstable_state: null,
|
|
344
|
+
unstable_annotations: [],
|
|
345
|
+
unstable_data: [],
|
|
346
|
+
steps: [],
|
|
347
|
+
custom: {},
|
|
348
|
+
},
|
|
349
|
+
content: [
|
|
350
|
+
{ type: "reasoning", text: "thinking", unstable_summary: "Planning" },
|
|
351
|
+
],
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
const { message } = auiV0Decode({
|
|
355
|
+
id: "cloud",
|
|
356
|
+
parent_id: null,
|
|
357
|
+
format: "aui/v0",
|
|
358
|
+
content: encoded,
|
|
359
|
+
created_at: new Date("2026-03-15T00:00:00.000Z"),
|
|
360
|
+
} as unknown as Parameters<typeof auiV0Decode>[0]);
|
|
361
|
+
|
|
362
|
+
expect(message.content).toEqual([
|
|
363
|
+
{ type: "reasoning", text: "thinking", unstable_summary: "Planning" },
|
|
364
|
+
]);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it("round-trips a reasoning summary without text", () => {
|
|
368
|
+
const encoded = auiV0Encode({
|
|
369
|
+
id: "local",
|
|
370
|
+
createdAt: new Date("2026-03-15T00:00:00.000Z"),
|
|
371
|
+
role: "assistant",
|
|
372
|
+
status: { type: "complete", reason: "stop" },
|
|
373
|
+
metadata: {
|
|
374
|
+
unstable_state: null,
|
|
375
|
+
unstable_annotations: [],
|
|
376
|
+
unstable_data: [],
|
|
377
|
+
steps: [],
|
|
378
|
+
custom: {},
|
|
379
|
+
},
|
|
380
|
+
content: [
|
|
381
|
+
{
|
|
382
|
+
type: "reasoning",
|
|
383
|
+
text: "",
|
|
384
|
+
unstable_summary: "Searching the codebase",
|
|
385
|
+
},
|
|
386
|
+
],
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
const { message } = auiV0Decode({
|
|
390
|
+
id: "cloud",
|
|
391
|
+
parent_id: null,
|
|
392
|
+
format: "aui/v0",
|
|
393
|
+
content: encoded,
|
|
394
|
+
created_at: new Date("2026-03-15T00:00:00.000Z"),
|
|
395
|
+
} as unknown as Parameters<typeof auiV0Decode>[0]);
|
|
396
|
+
|
|
397
|
+
expect(message.content).toEqual([
|
|
398
|
+
{
|
|
399
|
+
type: "reasoning",
|
|
400
|
+
text: "",
|
|
401
|
+
unstable_summary: "Searching the codebase",
|
|
402
|
+
},
|
|
403
|
+
]);
|
|
404
|
+
});
|
|
405
|
+
|
|
309
406
|
it("round-trips a pending tool-call approval so a paused run stays resumable", () => {
|
|
310
407
|
const content = auiV0Encode({
|
|
311
408
|
id: "local",
|
|
@@ -132,7 +132,7 @@ describe("DefaultEditComposerRuntimeCore", () => {
|
|
|
132
132
|
});
|
|
133
133
|
|
|
134
134
|
describe("send behavior", () => {
|
|
135
|
-
it("
|
|
135
|
+
it("calls append even when nothing changed, branching with the same message", async () => {
|
|
136
136
|
const { runtime, append } = makeRuntime();
|
|
137
137
|
const composer = new DefaultEditComposerRuntimeCore(runtime, () => {}, {
|
|
138
138
|
parentId: "p1",
|
|
@@ -141,7 +141,11 @@ describe("DefaultEditComposerRuntimeCore", () => {
|
|
|
141
141
|
}),
|
|
142
142
|
});
|
|
143
143
|
await composer.send();
|
|
144
|
-
expect(append).
|
|
144
|
+
expect(append).toHaveBeenCalledTimes(1);
|
|
145
|
+
const appended = append.mock.calls[0]![0] as AppendMessage;
|
|
146
|
+
expect(appended.content).toEqual([{ type: "text", text: "same" }]);
|
|
147
|
+
expect(appended.parentId).toBe("p1");
|
|
148
|
+
expect(appended.sourceId).toBe("msg-1");
|
|
145
149
|
});
|
|
146
150
|
|
|
147
151
|
it("calls append when text changes", async () => {
|
|
@@ -147,6 +147,49 @@ describe("fromThreadMessageLike", () => {
|
|
|
147
147
|
expect(result.content).toEqual([{ type: "reasoning", text: "hi" }]);
|
|
148
148
|
});
|
|
149
149
|
|
|
150
|
+
it("keeps a reasoning part with a summary and no text", () => {
|
|
151
|
+
const result = fromThreadMessageLike(
|
|
152
|
+
{
|
|
153
|
+
role: "assistant",
|
|
154
|
+
content: [
|
|
155
|
+
{
|
|
156
|
+
type: "reasoning",
|
|
157
|
+
text: "",
|
|
158
|
+
unstable_summary: "Searching the codebase",
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
},
|
|
162
|
+
fallbackId,
|
|
163
|
+
fallbackStatus,
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
expect(result.content).toEqual([
|
|
167
|
+
{
|
|
168
|
+
type: "reasoning",
|
|
169
|
+
text: "",
|
|
170
|
+
unstable_summary: "Searching the codebase",
|
|
171
|
+
},
|
|
172
|
+
]);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("drops a reasoning part with neither text nor a summary to show", () => {
|
|
176
|
+
// the transport layers round-trip an empty summary faithfully; this is
|
|
177
|
+
// the display normalizer, so it drops a part with nothing to render for
|
|
178
|
+
// the same reason it drops whitespace-only text.
|
|
179
|
+
const message = fromThreadMessageLike(
|
|
180
|
+
{
|
|
181
|
+
role: "assistant",
|
|
182
|
+
content: [
|
|
183
|
+
{ type: "reasoning", text: "", unstable_summary: "" },
|
|
184
|
+
{ type: "reasoning", text: " ", unstable_summary: " " },
|
|
185
|
+
],
|
|
186
|
+
},
|
|
187
|
+
"m1",
|
|
188
|
+
{ type: "complete", reason: "unknown" },
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
expect(message.content).toEqual([]);
|
|
192
|
+
});
|
|
150
193
|
it("drops an assistant image part whose image is undefined", () => {
|
|
151
194
|
const result = fromThreadMessageLike(
|
|
152
195
|
{
|
package/src/types/message.ts
CHANGED
|
@@ -23,6 +23,7 @@ export type ReasoningMessagePart = {
|
|
|
23
23
|
readonly type: "reasoning";
|
|
24
24
|
readonly text: string;
|
|
25
25
|
readonly status?: MessagePartStreamStatus;
|
|
26
|
+
readonly unstable_summary?: string;
|
|
26
27
|
readonly providerMetadata?: PartProviderMetadata;
|
|
27
28
|
readonly parentId?: string;
|
|
28
29
|
};
|