mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-16 07:04:25 +00:00
- Add ArtifactMessage type as core part of AppMessage union (not CustomMessages) - ArtifactsRuntimeProvider appends artifact messages on create/update/delete - MessageList filters out artifact messages (UI display only) - artifacts.ts reconstructFromMessages handles artifact messages - Export ARTIFACTS_RUNTIME_PROVIDER_DESCRIPTION from main index - Fix artifact creation bug: pass filename as title instead of mimeType Changes: - web-ui/src/components/Messages.ts: Add ArtifactMessage to BaseMessage union - web-ui/src/components/MessageList.ts: Skip artifact messages in render - web-ui/src/components/sandbox/ArtifactsRuntimeProvider.ts: Append messages, fix title parameter - web-ui/src/ChatPanel.ts: Pass agent.appendMessage callback - web-ui/src/tools/artifacts/artifacts.ts: Handle artifact messages in reconstructFromMessages - web-ui/src/index.ts: Export ARTIFACTS_RUNTIME_PROVIDER_DESCRIPTION - web-ui/example/src/custom-messages.ts: Update message transformer to filter artifacts
97 lines
2.7 KiB
TypeScript
97 lines
2.7 KiB
TypeScript
import { html } from "@mariozechner/mini-lit";
|
|
import type {
|
|
AgentTool,
|
|
AssistantMessage as AssistantMessageType,
|
|
ToolResultMessage as ToolResultMessageType,
|
|
} from "@mariozechner/pi-ai";
|
|
import { LitElement, type TemplateResult } from "lit";
|
|
import { property } from "lit/decorators.js";
|
|
import { repeat } from "lit/directives/repeat.js";
|
|
import type { AppMessage } from "./Messages.js";
|
|
import { renderMessage } from "./message-renderer-registry.js";
|
|
|
|
export class MessageList extends LitElement {
|
|
@property({ type: Array }) messages: AppMessage[] = [];
|
|
@property({ type: Array }) tools: AgentTool[] = [];
|
|
@property({ type: Object }) pendingToolCalls?: Set<string>;
|
|
@property({ type: Boolean }) isStreaming: boolean = false;
|
|
|
|
protected override createRenderRoot(): HTMLElement | DocumentFragment {
|
|
return this;
|
|
}
|
|
|
|
override connectedCallback(): void {
|
|
super.connectedCallback();
|
|
this.style.display = "block";
|
|
}
|
|
|
|
private buildRenderItems() {
|
|
// Map tool results by call id for quick lookup
|
|
const resultByCallId = new Map<string, ToolResultMessageType>();
|
|
for (const message of this.messages) {
|
|
if (message.role === "toolResult") {
|
|
resultByCallId.set(message.toolCallId, message);
|
|
}
|
|
}
|
|
|
|
const items: Array<{ key: string; template: TemplateResult }> = [];
|
|
let index = 0;
|
|
for (const msg of this.messages) {
|
|
// Skip artifact messages - they're for session persistence only, not UI display
|
|
if (msg.role === "artifact") {
|
|
continue;
|
|
}
|
|
|
|
// Try custom renderer first
|
|
const customTemplate = renderMessage(msg);
|
|
if (customTemplate) {
|
|
items.push({ key: `msg:${index}`, template: customTemplate });
|
|
index++;
|
|
continue;
|
|
}
|
|
|
|
// Fall back to built-in renderers
|
|
if (msg.role === "user") {
|
|
items.push({
|
|
key: `msg:${index}`,
|
|
template: html`<user-message .message=${msg}></user-message>`,
|
|
});
|
|
index++;
|
|
} else if (msg.role === "assistant") {
|
|
const amsg = msg as AssistantMessageType;
|
|
items.push({
|
|
key: `msg:${index}`,
|
|
template: html`<assistant-message
|
|
.message=${amsg}
|
|
.tools=${this.tools}
|
|
.isStreaming=${this.isStreaming}
|
|
.pendingToolCalls=${this.pendingToolCalls}
|
|
.toolResultsById=${resultByCallId}
|
|
.hideToolCalls=${false}
|
|
></assistant-message>`,
|
|
});
|
|
index++;
|
|
} else {
|
|
// Skip standalone toolResult messages; they are rendered via paired tool-message above
|
|
// Skip unknown roles
|
|
}
|
|
}
|
|
return items;
|
|
}
|
|
|
|
override render() {
|
|
const items = this.buildRenderItems();
|
|
return html`<div class="flex flex-col gap-3">
|
|
${repeat(
|
|
items,
|
|
(it) => it.key,
|
|
(it) => it.template,
|
|
)}
|
|
</div>`;
|
|
}
|
|
}
|
|
|
|
// Register custom element
|
|
if (!customElements.get("message-list")) {
|
|
customElements.define("message-list", MessageList);
|
|
}
|