78 lines
2.0 KiB
TypeScript
78 lines
2.0 KiB
TypeScript
import type { ConversationMessage } from "./types";
|
|
|
|
export interface ConversationRow {
|
|
readonly attachments: readonly {
|
|
readonly filename: string | null;
|
|
readonly id: string;
|
|
readonly mediaType: string;
|
|
readonly url: string | null;
|
|
}[];
|
|
readonly error: string | null;
|
|
readonly messageId: string;
|
|
readonly rawText: string;
|
|
readonly role: "assistant" | "user";
|
|
readonly status:
|
|
| "aborted"
|
|
| "completed"
|
|
| "dispatching"
|
|
| "failed"
|
|
| "queued"
|
|
| "running";
|
|
}
|
|
|
|
export const projectConversation = (rows: readonly ConversationRow[]) => {
|
|
const streaming = rows.some(
|
|
(row) =>
|
|
row.role === "assistant" &&
|
|
row.status === "running" &&
|
|
row.rawText.length > 0
|
|
);
|
|
return {
|
|
failedError: rows.findLast(
|
|
(row) => row.role === "assistant" && row.status === "failed"
|
|
)?.error,
|
|
messages: rows
|
|
.filter(
|
|
(row) =>
|
|
row.role === "user" ||
|
|
row.status === "completed" ||
|
|
(row.role === "assistant" &&
|
|
row.status === "running" &&
|
|
row.rawText.length > 0)
|
|
)
|
|
.map<ConversationMessage>((row) => ({
|
|
id: row.messageId,
|
|
parts: [
|
|
...row.attachments.map((attachment) => ({
|
|
filename: attachment.filename ?? undefined,
|
|
id: attachment.id,
|
|
mediaType: attachment.mediaType,
|
|
type: "file" as const,
|
|
url: attachment.url ?? undefined,
|
|
})),
|
|
...(row.rawText
|
|
? [
|
|
{
|
|
state:
|
|
row.status === "running"
|
|
? ("streaming" as const)
|
|
: ("done" as const),
|
|
text: row.rawText,
|
|
type: "text" as const,
|
|
},
|
|
]
|
|
: []),
|
|
],
|
|
role: row.role,
|
|
})),
|
|
pending: rows.some(
|
|
(row) =>
|
|
row.role === "assistant" &&
|
|
(row.status === "queued" ||
|
|
row.status === "dispatching" ||
|
|
row.status === "running")
|
|
),
|
|
streaming,
|
|
};
|
|
};
|