mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-26 21:39:43 +02:00
feat: aggregate artifacts from messages
This commit is contained in:
parent
e9deb1dcb1
commit
cba2a726a2
1 changed files with 74 additions and 1 deletions
|
|
@ -1,4 +1,32 @@
|
|||
import type { ArtifactKind, ArtifactStatus } from "../model/artifact";
|
||||
import type { ThreadMessageLike } from "@assistant-ui/react";
|
||||
import {
|
||||
ARTIFACT_TOOL_KINDS,
|
||||
type ArtifactKind,
|
||||
type ArtifactStatus,
|
||||
type ChatArtifact,
|
||||
} from "../model/artifact";
|
||||
|
||||
interface ToolCallPart {
|
||||
type: "tool-call";
|
||||
toolCallId: string;
|
||||
toolName: string;
|
||||
args?: Record<string, unknown>;
|
||||
result?: unknown;
|
||||
}
|
||||
|
||||
function isToolCallPart(part: unknown): part is ToolCallPart {
|
||||
return (
|
||||
typeof part === "object" &&
|
||||
part !== null &&
|
||||
(part as { type?: unknown }).type === "tool-call" &&
|
||||
typeof (part as { toolCallId?: unknown }).toolCallId === "string" &&
|
||||
typeof (part as { toolName?: unknown }).toolName === "string"
|
||||
);
|
||||
}
|
||||
|
||||
function asRecord(value: unknown): Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null ? (value as Record<string, unknown>) : {};
|
||||
}
|
||||
|
||||
function firstString(...values: unknown[]): string | null {
|
||||
for (const value of values) {
|
||||
|
|
@ -64,3 +92,48 @@ function describeArtifact(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregate the deliverable artifacts referenced across a thread's messages.
|
||||
*
|
||||
* Scans assistant tool-call parts, keeps recognized deliverable tools, and
|
||||
* dedupes by backing entity (so a regenerated report collapses to one entry,
|
||||
* refreshed in place to keep chronological order). Errored deliverables are
|
||||
* dropped — they have nothing to open or jump to.
|
||||
*/
|
||||
export function collectArtifacts(messages: readonly ThreadMessageLike[]): ChatArtifact[] {
|
||||
const byKey = new Map<string, ChatArtifact>();
|
||||
|
||||
for (const message of messages) {
|
||||
if (message.role !== "assistant" || !Array.isArray(message.content)) continue;
|
||||
|
||||
for (const part of message.content) {
|
||||
if (!isToolCallPart(part)) continue;
|
||||
const kind = ARTIFACT_TOOL_KINDS[part.toolName];
|
||||
if (!kind) continue;
|
||||
|
||||
const args = asRecord(part.args);
|
||||
const result = asRecord(part.result);
|
||||
const { title, entityId, status } = describeArtifact(
|
||||
kind,
|
||||
args,
|
||||
result,
|
||||
part.result !== undefined
|
||||
);
|
||||
if (status === "error") continue;
|
||||
|
||||
const key = entityId != null ? `${kind}:${entityId}` : part.toolCallId;
|
||||
byKey.set(key, {
|
||||
key,
|
||||
kind,
|
||||
title,
|
||||
status,
|
||||
toolCallId: part.toolCallId,
|
||||
entityId,
|
||||
contentType: kind === "resume" ? "typst" : "markdown",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(byKey.values());
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue