Archived
Improve shell output rendering
This commit is contained in:
@@ -31,13 +31,12 @@ function normalizeMessage(message: any): ChatLine[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function normalizeBashExecution(message: any): ChatLine {
|
function normalizeBashExecution(message: any): ChatLine {
|
||||||
const lines = [`$ ${message.command ?? ""}`];
|
const lines = message.excludeFromContext ? ["excluded from context", "", `$ ${message.command ?? ""}`] : [`$ ${message.command ?? ""}`];
|
||||||
if (message.output) lines.push("", String(message.output));
|
if (message.output) lines.push("", String(message.output));
|
||||||
if (message.exitCode != null) lines.push("", `exit ${message.exitCode}`);
|
if (message.exitCode != null) lines.push("", `exit ${message.exitCode}`);
|
||||||
if (message.cancelled) lines.push("", "cancelled");
|
if (message.cancelled) lines.push("", "cancelled");
|
||||||
if (message.truncated) lines.push("", "output truncated");
|
if (message.truncated) lines.push("", "output truncated");
|
||||||
if (message.fullOutputPath) lines.push("", `full output: ${message.fullOutputPath}`);
|
if (message.fullOutputPath) lines.push("", `full output: ${message.fullOutputPath}`);
|
||||||
if (message.excludeFromContext) lines.push("", "excluded from context");
|
|
||||||
return { role: "bash", parts: [{ type: "text", text: lines.join("\n") }] };
|
return { role: "bash", parts: [{ type: "text", text: lines.join("\n") }] };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export class ChatView extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<article class="msg ${message.role}" data-index=${index}>
|
<article class="msg ${message.role}" data-index=${index}>
|
||||||
<b class="label">${message.role}</b>
|
<b class="label">${message.role}</b>
|
||||||
${message.parts.map((part) => this.renderPart(part))}
|
${message.parts.map((part) => this.renderPart(part, message))}
|
||||||
</article>
|
</article>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ export class ChatView extends LitElement {
|
|||||||
${messages.map((message) => html`
|
${messages.map((message) => html`
|
||||||
<section class="group-msg ${message.role}">
|
<section class="group-msg ${message.role}">
|
||||||
<b class="label">${message.role}</b>
|
<b class="label">${message.role}</b>
|
||||||
${message.parts.map((part) => this.renderPart(part))}
|
${message.parts.map((part) => this.renderPart(part, message))}
|
||||||
</section>
|
</section>
|
||||||
`)}
|
`)}
|
||||||
</div>
|
</div>
|
||||||
@@ -69,7 +69,8 @@ export class ChatView extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderPart(part: ChatPart) {
|
private renderPart(part: ChatPart, message?: ChatLine) {
|
||||||
|
if (part.type === "text" && message?.role === "bash") return html`<pre class="part shell-output">${part.text}</pre>`;
|
||||||
if (part.type === "text") return html`<formatted-text class="part" .text=${part.text}></formatted-text>`;
|
if (part.type === "text") return html`<formatted-text class="part" .text=${part.text}></formatted-text>`;
|
||||||
if (part.type === "thinking") return html`<details class="part"><summary>thinking</summary><formatted-text .text=${part.text}></formatted-text></details>`;
|
if (part.type === "thinking") return html`<details class="part"><summary>thinking</summary><formatted-text .text=${part.text}></formatted-text></details>`;
|
||||||
if (part.type === "toolCall") return html`<div class="part tool-line">▶ ${part.toolName}<span class="summary">${part.summary}</span></div>`;
|
if (part.type === "toolCall") return html`<div class="part tool-line">▶ ${part.toolName}<span class="summary">${part.summary}</span></div>`;
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ export const chatStyles = css`
|
|||||||
.part:is(details) { border-top: 1px solid #30363d; padding-top: 8px; }
|
.part:is(details) { border-top: 1px solid #30363d; padding-top: 8px; }
|
||||||
summary { cursor: pointer; color: #8b949e; }
|
summary { cursor: pointer; color: #8b949e; }
|
||||||
pre { margin: 6px 0 0; white-space: pre-wrap; overflow-wrap: anywhere; font: inherit; }
|
pre { margin: 6px 0 0; white-space: pre-wrap; overflow-wrap: anywhere; font: inherit; }
|
||||||
|
.shell-output { color: #e6edf3; font: 13px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; line-height: 1.45; }
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const formattedTextStyles = css`
|
export const formattedTextStyles = css`
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ import type { ChatLine } from "./components/shared";
|
|||||||
import type { SessionUiEvent } from "./sessionSocket";
|
import type { SessionUiEvent } from "./sessionSocket";
|
||||||
|
|
||||||
export function shellStartMessage(command: string, excludeFromContext?: boolean): ChatLine {
|
export function shellStartMessage(command: string, excludeFromContext?: boolean): ChatLine {
|
||||||
return textMessage("bash", `$ ${command}${excludeFromContext ? "\n\nexcluded from context" : ""}`);
|
return textMessage("bash", `${excludeFromContext ? "excluded from context\n\n" : ""}$ ${command}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function appendShellChunk(messages: ChatLine[], chunk: string): ChatLine[] {
|
export function appendShellChunk(messages: ChatLine[], chunk: string): ChatLine[] {
|
||||||
const last = messages.at(-1);
|
const last = messages.at(-1);
|
||||||
const lastPart = last?.parts.at(-1);
|
const lastPart = last?.parts.at(-1);
|
||||||
if (last?.role !== "bash" || lastPart?.type !== "text") return [...messages, textMessage("bash", chunk)];
|
if (last?.role !== "bash" || lastPart?.type !== "text") return [...messages, textMessage("bash", chunk)];
|
||||||
const separator = lastPart.text.includes("\n\n") ? "" : "\n\n";
|
const separator = hasShellOutput(lastPart.text) ? "" : "\n\n";
|
||||||
return [...messages.slice(0, -1), { ...last, parts: [...last.parts.slice(0, -1), { ...lastPart, text: lastPart.text + separator + chunk }] }];
|
return [...messages.slice(0, -1), { ...last, parts: [...last.parts.slice(0, -1), { ...lastPart, text: lastPart.text + separator + chunk }] }];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,3 +28,9 @@ export function finalizeShellMessage(messages: ChatLine[], event: Extract<Sessio
|
|||||||
if (!notes.length) return messages;
|
if (!notes.length) return messages;
|
||||||
return [...messages.slice(0, -1), { ...last, parts: [...last.parts.slice(0, -1), { ...lastPart, text: `${lastPart.text}\n\n${notes.join("\n")}` }] }];
|
return [...messages.slice(0, -1), { ...last, parts: [...last.parts.slice(0, -1), { ...lastPart, text: `${lastPart.text}\n\n${notes.join("\n")}` }] }];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasShellOutput(text: string): boolean {
|
||||||
|
const outputStart = text.lastIndexOf("\n\n");
|
||||||
|
const promptStart = text.lastIndexOf("$ ");
|
||||||
|
return outputStart > promptStart;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user