From 58b9c36268d538d39408ee474ad03f59d52d0f96 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Wed, 8 Oct 2025 14:12:02 +0200 Subject: [PATCH] Make renderHeader and renderCollapsibleHeader accept string | TemplateResult - Update renderHeader and renderCollapsibleHeader in renderer-registry.ts to accept `text: string | TemplateResult` - Remove duplicated renderCollapsibleHeaderWithPill helper in artifacts-tool-renderer.ts - Update all artifact renderer calls to use renderHeaderWithPill() inline - Remove all separate pill rendering below headers This allows artifact pills to be rendered inline with header text without code duplication. --- packages/ai/src/models.generated.ts | 123 ++++++++---------- .../src/tools/artifacts/ArtifactPill.ts | 8 +- .../artifacts/artifacts-tool-renderer.ts | 40 +++--- .../web-ui/src/tools/renderer-registry.ts | 16 ++- 4 files changed, 84 insertions(+), 103 deletions(-) diff --git a/packages/ai/src/models.generated.ts b/packages/ai/src/models.generated.ts index 448cc03c..f7008755 100644 --- a/packages/ai/src/models.generated.ts +++ b/packages/ai/src/models.generated.ts @@ -1711,8 +1711,8 @@ export const MODELS = { reasoning: true, input: ["text", "image"], cost: { - input: 0.19, - output: 0.78, + input: 0.3, + output: 1.2, cacheRead: 0, cacheWrite: 0, }, @@ -2042,23 +2042,6 @@ export const MODELS = { contextWindow: 131072, maxTokens: 131072, } satisfies Model<"openai-completions">, - "deepseek/deepseek-chat-v3.1:free": { - id: "deepseek/deepseek-chat-v3.1:free", - name: "DeepSeek: DeepSeek V3.1 (free)", - api: "openai-completions", - provider: "openrouter", - baseUrl: "https://openrouter.ai/api/v1", - reasoning: true, - input: ["text"], - cost: { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - }, - contextWindow: 163800, - maxTokens: 4096, - } satisfies Model<"openai-completions">, "deepseek/deepseek-chat-v3.1": { id: "deepseek/deepseek-chat-v3.1", name: "DeepSeek: DeepSeek V3.1", @@ -2238,13 +2221,13 @@ export const MODELS = { reasoning: true, input: ["text"], cost: { - input: 0.14, - output: 0.86, + input: 0, + output: 0, cacheRead: 0, cacheWrite: 0, }, - contextWindow: 131072, - maxTokens: 131072, + contextWindow: 32768, + maxTokens: 32768, } satisfies Model<"openai-completions">, "qwen/qwen3-235b-a22b-thinking-2507": { id: "qwen/qwen3-235b-a22b-thinking-2507", @@ -3300,23 +3283,6 @@ export const MODELS = { contextWindow: 32768, maxTokens: 4096, } satisfies Model<"openai-completions">, - "cohere/command-r-plus-08-2024": { - id: "cohere/command-r-plus-08-2024", - name: "Cohere: Command R+ (08-2024)", - api: "openai-completions", - provider: "openrouter", - baseUrl: "https://openrouter.ai/api/v1", - reasoning: false, - input: ["text"], - cost: { - input: 2.5, - output: 10, - cacheRead: 0, - cacheWrite: 0, - }, - contextWindow: 128000, - maxTokens: 4000, - } satisfies Model<"openai-completions">, "cohere/command-r-08-2024": { id: "cohere/command-r-08-2024", name: "Cohere: Command R (08-2024)", @@ -3334,6 +3300,23 @@ export const MODELS = { contextWindow: 128000, maxTokens: 4000, } satisfies Model<"openai-completions">, + "cohere/command-r-plus-08-2024": { + id: "cohere/command-r-plus-08-2024", + name: "Cohere: Command R+ (08-2024)", + api: "openai-completions", + provider: "openrouter", + baseUrl: "https://openrouter.ai/api/v1", + reasoning: false, + input: ["text"], + cost: { + input: 2.5, + output: 10, + cacheRead: 0, + cacheWrite: 0, + }, + contextWindow: 128000, + maxTokens: 4000, + } satisfies Model<"openai-completions">, "microsoft/phi-3.5-mini-128k-instruct": { id: "microsoft/phi-3.5-mini-128k-instruct", name: "Microsoft: Phi-3.5 Mini 128K Instruct", @@ -3368,22 +3351,22 @@ export const MODELS = { contextWindow: 65000, maxTokens: 4096, } satisfies Model<"openai-completions">, - "meta-llama/llama-3.1-8b-instruct": { - id: "meta-llama/llama-3.1-8b-instruct", - name: "Meta: Llama 3.1 8B Instruct", + "meta-llama/llama-3.1-70b-instruct": { + id: "meta-llama/llama-3.1-70b-instruct", + name: "Meta: Llama 3.1 70B Instruct", api: "openai-completions", provider: "openrouter", baseUrl: "https://openrouter.ai/api/v1", reasoning: false, input: ["text"], cost: { - input: 0.02, - output: 0.03, + input: 0.39999999999999997, + output: 0.39999999999999997, cacheRead: 0, cacheWrite: 0, }, - contextWindow: 16384, - maxTokens: 16384, + contextWindow: 131072, + maxTokens: 4096, } satisfies Model<"openai-completions">, "meta-llama/llama-3.1-405b-instruct": { id: "meta-llama/llama-3.1-405b-instruct", @@ -3402,22 +3385,22 @@ export const MODELS = { contextWindow: 32768, maxTokens: 16384, } satisfies Model<"openai-completions">, - "meta-llama/llama-3.1-70b-instruct": { - id: "meta-llama/llama-3.1-70b-instruct", - name: "Meta: Llama 3.1 70B Instruct", + "meta-llama/llama-3.1-8b-instruct": { + id: "meta-llama/llama-3.1-8b-instruct", + name: "Meta: Llama 3.1 8B Instruct", api: "openai-completions", provider: "openrouter", baseUrl: "https://openrouter.ai/api/v1", reasoning: false, input: ["text"], cost: { - input: 0.39999999999999997, - output: 0.39999999999999997, + input: 0.02, + output: 0.03, cacheRead: 0, cacheWrite: 0, }, contextWindow: 131072, - maxTokens: 4096, + maxTokens: 16384, } satisfies Model<"openai-completions">, "mistralai/mistral-nemo": { id: "mistralai/mistral-nemo", @@ -3589,23 +3572,6 @@ export const MODELS = { contextWindow: 128000, maxTokens: 4096, } satisfies Model<"openai-completions">, - "mistralai/mistral-small": { - id: "mistralai/mistral-small", - name: "Mistral Small", - api: "openai-completions", - provider: "openrouter", - baseUrl: "https://openrouter.ai/api/v1", - reasoning: false, - input: ["text"], - cost: { - input: 0.19999999999999998, - output: 0.6, - cacheRead: 0, - cacheWrite: 0, - }, - contextWindow: 32768, - maxTokens: 4096, - } satisfies Model<"openai-completions">, "mistralai/mistral-tiny": { id: "mistralai/mistral-tiny", name: "Mistral Tiny", @@ -3623,6 +3589,23 @@ export const MODELS = { contextWindow: 32768, maxTokens: 4096, } satisfies Model<"openai-completions">, + "mistralai/mistral-small": { + id: "mistralai/mistral-small", + name: "Mistral Small", + api: "openai-completions", + provider: "openrouter", + baseUrl: "https://openrouter.ai/api/v1", + reasoning: false, + input: ["text"], + cost: { + input: 0.19999999999999998, + output: 0.6, + cacheRead: 0, + cacheWrite: 0, + }, + contextWindow: 32768, + maxTokens: 4096, + } satisfies Model<"openai-completions">, "mistralai/mixtral-8x7b-instruct": { id: "mistralai/mixtral-8x7b-instruct", name: "Mistral: Mixtral 8x7B Instruct", diff --git a/packages/web-ui/src/tools/artifacts/ArtifactPill.ts b/packages/web-ui/src/tools/artifacts/ArtifactPill.ts index b57157fd..2e22b2c7 100644 --- a/packages/web-ui/src/tools/artifacts/ArtifactPill.ts +++ b/packages/web-ui/src/tools/artifacts/ArtifactPill.ts @@ -10,14 +10,14 @@ export function ArtifactPill(filename: string, artifactsPanel?: ArtifactsPanel): }; return html` -
${icon(FileCode2, "sm")} - ${filename} -
+ ${filename} + `; } diff --git a/packages/web-ui/src/tools/artifacts/artifacts-tool-renderer.ts b/packages/web-ui/src/tools/artifacts/artifacts-tool-renderer.ts index 3e7ec337..0237662f 100644 --- a/packages/web-ui/src/tools/artifacts/artifacts-tool-renderer.ts +++ b/packages/web-ui/src/tools/artifacts/artifacts-tool-renderer.ts @@ -1,8 +1,8 @@ -import { Diff, html, type TemplateResult } from "@mariozechner/mini-lit"; +import { Diff, html, icon, iconDOM, type TemplateResult } from "@mariozechner/mini-lit"; import "@mariozechner/mini-lit/dist/CodeBlock.js"; import type { ToolResultMessage } from "@mariozechner/pi-ai"; import { createRef, ref } from "lit/directives/ref.js"; -import { FileCode2 } from "lucide"; +import { ChevronDown, ChevronRight, FileCode2, Loader } from "lucide"; import "../../components/ConsoleBlock.js"; import { i18n } from "../../utils/i18n.js"; import { renderCollapsibleHeader, renderHeader } from "../renderer-registry.js"; @@ -74,9 +74,12 @@ export class ArtifactsToolRenderer implements ToolRenderer { - return filename ? ArtifactPill(filename, this.artifactsPanel) : ""; + // Helper to render header text with inline artifact pill + const renderHeaderWithPill = (labelText: string, filename?: string): TemplateResult => { + if (filename) { + return html`${labelText} ${ArtifactPill(filename, this.artifactsPanel)}`; + } + return html`${labelText}`; }; // Error handling @@ -96,8 +99,7 @@ export class ArtifactsToolRenderer implements ToolRenderer - ${renderCollapsibleHeader(state, FileCode2, headerText, contentRef, chevronRef, false)} - ${renderPill(filename) ? html`
${renderPill(filename)}
` : ""} + ${renderCollapsibleHeader(state, FileCode2, renderHeaderWithPill(headerText, filename), contentRef, chevronRef, false)}
${content ? html`` : ""} ${ @@ -132,8 +134,7 @@ export class ArtifactsToolRenderer implements ToolRenderer - ${renderCollapsibleHeader(state, FileCode2, headerText, contentRef, chevronRef, false)} - ${renderPill(filename) ? html`
${renderPill(filename)}
` : ""} + ${renderCollapsibleHeader(state, FileCode2, renderHeaderWithPill(headerText, filename), contentRef, chevronRef, false)}
@@ -146,8 +147,7 @@ export class ArtifactsToolRenderer implements ToolRenderer - ${renderCollapsibleHeader(state, FileCode2, headerText, contentRef, chevronRef, false)} - ${renderPill(filename) ? html`
${renderPill(filename)}
` : ""} + ${renderCollapsibleHeader(state, FileCode2, renderHeaderWithPill(headerText, filename), contentRef, chevronRef, false)}
@@ -163,8 +163,7 @@ export class ArtifactsToolRenderer implements ToolRenderer - ${renderCollapsibleHeader(state, FileCode2, headerText, contentRef, chevronRef, false)} - ${renderPill(filename) ? html`
${renderPill(filename)}
` : ""} + ${renderCollapsibleHeader(state, FileCode2, renderHeaderWithPill(headerText, filename), contentRef, chevronRef, false)}
${codeContent ? html`` : ""} ${isHtml && logs ? html`` : ""} @@ -176,8 +175,7 @@ export class ArtifactsToolRenderer implements ToolRenderer - ${renderHeader(state, FileCode2, headerText)} - ${renderPill(filename) ? html`
${renderPill(filename)}
` : ""} + ${renderHeader(state, FileCode2, renderHeaderWithPill(headerText, filename))}
`; } @@ -200,8 +198,7 @@ export class ArtifactsToolRenderer implements ToolRenderer - ${renderCollapsibleHeader(state, FileCode2, headerText, contentRef, chevronRef, false)} - ${renderPill(filename) ? html`
${renderPill(filename)}
` : ""} + ${renderCollapsibleHeader(state, FileCode2, renderHeaderWithPill(headerText, filename), contentRef, chevronRef, false)}
${ content @@ -215,8 +212,7 @@ export class ArtifactsToolRenderer implements ToolRenderer - ${renderCollapsibleHeader(state, FileCode2, headerText, contentRef, chevronRef, false)} - ${renderPill(filename) ? html`
${renderPill(filename)}
` : ""} + ${renderCollapsibleHeader(state, FileCode2, renderHeaderWithPill(headerText, filename), contentRef, chevronRef, false)}
${ old_str !== undefined && new_str !== undefined @@ -231,8 +227,7 @@ export class ArtifactsToolRenderer implements ToolRenderer - ${renderCollapsibleHeader(state, FileCode2, headerText, contentRef, chevronRef, false)} - ${renderPill(filename) ? html`
${renderPill(filename)}
` : ""} + ${renderCollapsibleHeader(state, FileCode2, renderHeaderWithPill(headerText, filename), contentRef, chevronRef, false)}
`; @@ -241,8 +236,7 @@ export class ArtifactsToolRenderer implements ToolRenderer - ${renderHeader(state, FileCode2, headerText)} - ${renderPill(filename) ? html`
${renderPill(filename)}
` : ""} + ${renderHeader(state, FileCode2, renderHeaderWithPill(headerText, filename))}
`; } diff --git a/packages/web-ui/src/tools/renderer-registry.ts b/packages/web-ui/src/tools/renderer-registry.ts index d951b10d..ac5f2b8f 100644 --- a/packages/web-ui/src/tools/renderer-registry.ts +++ b/packages/web-ui/src/tools/renderer-registry.ts @@ -25,7 +25,11 @@ export function getToolRenderer(toolName: string): ToolRenderer | undefined { * Helper to render a header for tool renderers * Shows icon on left when complete/error, spinner on right when in progress */ -export function renderHeader(state: "inprogress" | "complete" | "error", toolIcon: any, text: string): TemplateResult { +export function renderHeader( + state: "inprogress" | "complete" | "error", + toolIcon: any, + text: string | TemplateResult, +): TemplateResult { const statusIcon = (iconComponent: any, color: string) => html`${icon(iconComponent, "sm")}`; @@ -35,7 +39,7 @@ export function renderHeader(state: "inprogress" | "complete" | "error", toolIco
${statusIcon(toolIcon, "text-foreground")} - ${text} + ${text}
${statusIcon(Loader, "text-foreground animate-spin")}
@@ -44,14 +48,14 @@ export function renderHeader(state: "inprogress" | "complete" | "error", toolIco return html`
${statusIcon(toolIcon, "text-green-600 dark:text-green-500")} - ${text} + ${text}
`; case "error": return html`
${statusIcon(toolIcon, "text-destructive")} - ${text} + ${text}
`; } @@ -64,7 +68,7 @@ export function renderHeader(state: "inprogress" | "complete" | "error", toolIco export function renderCollapsibleHeader( state: "inprogress" | "complete" | "error", toolIcon: any, - text: string, + text: string | TemplateResult, contentRef: Ref, chevronRef: Ref, defaultExpanded = false, @@ -102,7 +106,7 @@ export function renderCollapsibleHeader(
${state === "inprogress" ? statusIcon(Loader, "text-foreground animate-spin") : ""} ${statusIcon(toolIcon, toolIconColor)} - ${text} + ${text}
${icon(defaultExpanded ? ChevronDown : ChevronRight, "sm")}