mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-19 15:04:45 +00:00
Release v0.7.18
This commit is contained in:
parent
a11c1aa4ff
commit
22d8a0ae4a
16 changed files with 284 additions and 174 deletions
28
package-lock.json
generated
28
package-lock.json
generated
|
|
@ -3195,11 +3195,11 @@
|
||||||
},
|
},
|
||||||
"packages/agent": {
|
"packages/agent": {
|
||||||
"name": "@mariozechner/pi-agent",
|
"name": "@mariozechner/pi-agent",
|
||||||
"version": "0.7.17",
|
"version": "0.7.18",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mariozechner/pi-ai": "^0.7.16",
|
"@mariozechner/pi-ai": "^0.7.17",
|
||||||
"@mariozechner/pi-tui": "^0.7.16"
|
"@mariozechner/pi-tui": "^0.7.17"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^24.3.0",
|
"@types/node": "^24.3.0",
|
||||||
|
|
@ -3225,7 +3225,7 @@
|
||||||
},
|
},
|
||||||
"packages/ai": {
|
"packages/ai": {
|
||||||
"name": "@mariozechner/pi-ai",
|
"name": "@mariozechner/pi-ai",
|
||||||
"version": "0.7.17",
|
"version": "0.7.18",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@anthropic-ai/sdk": "^0.61.0",
|
"@anthropic-ai/sdk": "^0.61.0",
|
||||||
|
|
@ -3272,11 +3272,11 @@
|
||||||
},
|
},
|
||||||
"packages/coding-agent": {
|
"packages/coding-agent": {
|
||||||
"name": "@mariozechner/pi-coding-agent",
|
"name": "@mariozechner/pi-coding-agent",
|
||||||
"version": "0.7.17",
|
"version": "0.7.18",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mariozechner/pi-agent": "^0.7.16",
|
"@mariozechner/pi-agent": "^0.7.17",
|
||||||
"@mariozechner/pi-ai": "^0.7.16",
|
"@mariozechner/pi-ai": "^0.7.17",
|
||||||
"chalk": "^5.5.0",
|
"chalk": "^5.5.0",
|
||||||
"diff": "^8.0.2",
|
"diff": "^8.0.2",
|
||||||
"glob": "^11.0.3"
|
"glob": "^11.0.3"
|
||||||
|
|
@ -3319,10 +3319,10 @@
|
||||||
},
|
},
|
||||||
"packages/pods": {
|
"packages/pods": {
|
||||||
"name": "@mariozechner/pi",
|
"name": "@mariozechner/pi",
|
||||||
"version": "0.7.17",
|
"version": "0.7.18",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mariozechner/pi-agent": "^0.7.16",
|
"@mariozechner/pi-agent": "^0.7.17",
|
||||||
"chalk": "^5.5.0"
|
"chalk": "^5.5.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
@ -3345,7 +3345,7 @@
|
||||||
},
|
},
|
||||||
"packages/proxy": {
|
"packages/proxy": {
|
||||||
"name": "@mariozechner/pi-proxy",
|
"name": "@mariozechner/pi-proxy",
|
||||||
"version": "0.7.17",
|
"version": "0.7.18",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hono/node-server": "^1.14.0",
|
"@hono/node-server": "^1.14.0",
|
||||||
"hono": "^4.6.16"
|
"hono": "^4.6.16"
|
||||||
|
|
@ -3361,7 +3361,7 @@
|
||||||
},
|
},
|
||||||
"packages/tui": {
|
"packages/tui": {
|
||||||
"name": "@mariozechner/pi-tui",
|
"name": "@mariozechner/pi-tui",
|
||||||
"version": "0.7.17",
|
"version": "0.7.18",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/mime-types": "^2.1.4",
|
"@types/mime-types": "^2.1.4",
|
||||||
|
|
@ -3400,12 +3400,12 @@
|
||||||
},
|
},
|
||||||
"packages/web-ui": {
|
"packages/web-ui": {
|
||||||
"name": "@mariozechner/pi-web-ui",
|
"name": "@mariozechner/pi-web-ui",
|
||||||
"version": "0.7.17",
|
"version": "0.7.18",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lmstudio/sdk": "^1.5.0",
|
"@lmstudio/sdk": "^1.5.0",
|
||||||
"@mariozechner/pi-ai": "^0.7.16",
|
"@mariozechner/pi-ai": "^0.7.17",
|
||||||
"@mariozechner/pi-tui": "^0.7.16",
|
"@mariozechner/pi-tui": "^0.7.17",
|
||||||
"docx-preview": "^0.3.7",
|
"docx-preview": "^0.3.7",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"lucide": "^0.544.0",
|
"lucide": "^0.544.0",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@mariozechner/pi-agent",
|
"name": "@mariozechner/pi-agent",
|
||||||
"version": "0.7.17",
|
"version": "0.7.18",
|
||||||
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
|
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
|
|
@ -18,8 +18,8 @@
|
||||||
"prepublishOnly": "npm run clean && npm run build"
|
"prepublishOnly": "npm run clean && npm run build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mariozechner/pi-ai": "^0.7.17",
|
"@mariozechner/pi-ai": "^0.7.18",
|
||||||
"@mariozechner/pi-tui": "^0.7.17"
|
"@mariozechner/pi-tui": "^0.7.18"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"ai",
|
"ai",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@mariozechner/pi-ai",
|
"name": "@mariozechner/pi-ai",
|
||||||
"version": "0.7.17",
|
"version": "0.7.18",
|
||||||
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,13 @@
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.7.18] - 2025-11-18
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Bash Tool Error Handling**: Bash tool now properly throws errors for failed commands (non-zero exit codes), timeouts, and aborted executions. This ensures tool execution components display with red background when bash commands fail.
|
||||||
|
- **Thinking Traces Styling**: Thinking traces now maintain gray italic styling throughout, even when containing inline code blocks, bold text, or other inline formatting
|
||||||
|
|
||||||
## [0.7.17] - 2025-11-18
|
## [0.7.17] - 2025-11-18
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@mariozechner/pi-coding-agent",
|
"name": "@mariozechner/pi-coding-agent",
|
||||||
"version": "0.7.17",
|
"version": "0.7.18",
|
||||||
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
@ -21,8 +21,8 @@
|
||||||
"prepublishOnly": "npm run clean && npm run build"
|
"prepublishOnly": "npm run clean && npm run build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mariozechner/pi-agent": "^0.7.17",
|
"@mariozechner/pi-agent": "^0.7.18",
|
||||||
"@mariozechner/pi-ai": "^0.7.17",
|
"@mariozechner/pi-ai": "^0.7.18",
|
||||||
"chalk": "^5.5.0",
|
"chalk": "^5.5.0",
|
||||||
"diff": "^8.0.2",
|
"diff": "^8.0.2",
|
||||||
"glob": "^11.0.3"
|
"glob": "^11.0.3"
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ export const bashTool: AgentTool<typeof bashSchema> = {
|
||||||
}
|
}
|
||||||
if (output) output += "\n\n";
|
if (output) output += "\n\n";
|
||||||
output += "Command aborted";
|
output += "Command aborted";
|
||||||
resolve({ content: [{ type: "text", text: `Command failed\n\n${output}` }], details: undefined });
|
_reject(new Error(output));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,7 +150,7 @@ export const bashTool: AgentTool<typeof bashSchema> = {
|
||||||
}
|
}
|
||||||
if (output) output += "\n\n";
|
if (output) output += "\n\n";
|
||||||
output += `Command timed out after ${timeout} seconds`;
|
output += `Command timed out after ${timeout} seconds`;
|
||||||
resolve({ content: [{ type: "text", text: `Command failed\n\n${output}` }], details: undefined });
|
_reject(new Error(output));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -163,10 +163,7 @@ export const bashTool: AgentTool<typeof bashSchema> = {
|
||||||
|
|
||||||
if (code !== 0 && code !== null) {
|
if (code !== 0 && code !== null) {
|
||||||
if (output) output += "\n\n";
|
if (output) output += "\n\n";
|
||||||
resolve({
|
_reject(new Error(`${output}Command exited with code ${code}`));
|
||||||
content: [{ type: "text", text: `Command failed\n\n${output}Command exited with code ${code}` }],
|
|
||||||
details: undefined,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
resolve({ content: [{ type: "text", text: output || "(no output)" }], details: undefined });
|
resolve({ content: [{ type: "text", text: output || "(no output)" }], details: undefined });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,12 +38,16 @@ export class AssistantMessageComponent extends Container {
|
||||||
if (content.type === "text" && content.text.trim()) {
|
if (content.type === "text" && content.text.trim()) {
|
||||||
// Assistant text messages with no background - trim the text
|
// Assistant text messages with no background - trim the text
|
||||||
// Set paddingY=0 to avoid extra spacing before tool executions
|
// Set paddingY=0 to avoid extra spacing before tool executions
|
||||||
this.contentContainer.addChild(new Markdown(content.text.trim(), undefined, undefined, undefined, 1, 0));
|
this.contentContainer.addChild(new Markdown(content.text.trim(), 1, 0));
|
||||||
} else if (content.type === "thinking" && content.thinking.trim()) {
|
} else if (content.type === "thinking" && content.thinking.trim()) {
|
||||||
// Thinking traces in dark gray italic
|
// Thinking traces in dark gray italic
|
||||||
// Use Markdown component because it preserves ANSI codes across wrapped lines
|
// Use Markdown component with default text style for consistent styling
|
||||||
const thinkingText = chalk.gray.italic(content.thinking);
|
this.contentContainer.addChild(
|
||||||
this.contentContainer.addChild(new Markdown(thinkingText, undefined, undefined, undefined, 1, 0));
|
new Markdown(content.thinking.trim(), 1, 0, {
|
||||||
|
color: "gray",
|
||||||
|
italic: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
this.contentContainer.addChild(new Spacer(1));
|
this.contentContainer.addChild(new Spacer(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ export class TuiRenderer {
|
||||||
this.ui.addChild(new DynamicBorder(chalk.cyan));
|
this.ui.addChild(new DynamicBorder(chalk.cyan));
|
||||||
this.ui.addChild(new Text(chalk.bold.cyan("What's New"), 1, 0));
|
this.ui.addChild(new Text(chalk.bold.cyan("What's New"), 1, 0));
|
||||||
this.ui.addChild(new Spacer(1));
|
this.ui.addChild(new Spacer(1));
|
||||||
this.ui.addChild(new Markdown(this.changelogMarkdown.trim(), undefined, undefined, undefined, 1, 0));
|
this.ui.addChild(new Markdown(this.changelogMarkdown.trim(), 1, 0));
|
||||||
this.ui.addChild(new Spacer(1));
|
this.ui.addChild(new Spacer(1));
|
||||||
this.ui.addChild(new DynamicBorder(chalk.cyan));
|
this.ui.addChild(new DynamicBorder(chalk.cyan));
|
||||||
}
|
}
|
||||||
|
|
@ -989,7 +989,7 @@ export class TuiRenderer {
|
||||||
this.chatContainer.addChild(new DynamicBorder(chalk.cyan));
|
this.chatContainer.addChild(new DynamicBorder(chalk.cyan));
|
||||||
this.ui.addChild(new Text(chalk.bold.cyan("What's New"), 1, 0));
|
this.ui.addChild(new Text(chalk.bold.cyan("What's New"), 1, 0));
|
||||||
this.ui.addChild(new Spacer(1));
|
this.ui.addChild(new Spacer(1));
|
||||||
this.chatContainer.addChild(new Markdown(changelogMarkdown));
|
this.chatContainer.addChild(new Markdown(changelogMarkdown, 1, 1));
|
||||||
this.chatContainer.addChild(new DynamicBorder(chalk.cyan));
|
this.chatContainer.addChild(new DynamicBorder(chalk.cyan));
|
||||||
this.ui.requestRender();
|
this.ui.requestRender();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ export class UserMessageComponent extends Container {
|
||||||
}
|
}
|
||||||
|
|
||||||
// User messages with dark gray background
|
// User messages with dark gray background
|
||||||
this.markdown = new Markdown(text, undefined, undefined, { r: 52, g: 53, b: 65 });
|
this.markdown = new Markdown(text, 1, 1, { bgColor: "#343541" });
|
||||||
this.addChild(this.markdown);
|
this.addChild(this.markdown);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@mariozechner/pi",
|
"name": "@mariozechner/pi",
|
||||||
"version": "0.7.17",
|
"version": "0.7.18",
|
||||||
"description": "CLI tool for managing vLLM deployments on GPU pods",
|
"description": "CLI tool for managing vLLM deployments on GPU pods",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
"node": ">=20.0.0"
|
"node": ">=20.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mariozechner/pi-agent": "^0.7.17",
|
"@mariozechner/pi-agent": "^0.7.18",
|
||||||
"chalk": "^5.5.0"
|
"chalk": "^5.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {}
|
"devDependencies": {}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@mariozechner/pi-proxy",
|
"name": "@mariozechner/pi-proxy",
|
||||||
"version": "0.7.17",
|
"version": "0.7.18",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "CORS and authentication proxy for pi-ai",
|
"description": "CORS and authentication proxy for pi-ai",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@mariozechner/pi-tui",
|
"name": "@mariozechner/pi-tui",
|
||||||
"version": "0.7.17",
|
"version": "0.7.18",
|
||||||
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
|
|
||||||
|
|
@ -1,55 +1,46 @@
|
||||||
import chalk from "chalk";
|
import { Chalk } from "chalk";
|
||||||
import { marked, type Token } from "marked";
|
import { marked, type Token } from "marked";
|
||||||
import type { Component } from "../tui.js";
|
import type { Component } from "../tui.js";
|
||||||
import { visibleWidth } from "../utils.js";
|
import { visibleWidth } from "../utils.js";
|
||||||
|
|
||||||
type Color =
|
// Use a chalk instance with color level 3 for consistent ANSI output
|
||||||
| "black"
|
const colorChalk = new Chalk({ level: 3 });
|
||||||
| "red"
|
|
||||||
| "green"
|
/**
|
||||||
| "yellow"
|
* Default text styling for markdown content.
|
||||||
| "blue"
|
* Applied to all text unless overridden by markdown formatting.
|
||||||
| "magenta"
|
*/
|
||||||
| "cyan"
|
export interface DefaultTextStyle {
|
||||||
| "white"
|
/** Foreground color - named color or hex string like "#ff0000" */
|
||||||
| "gray"
|
color?: string;
|
||||||
| "bgBlack"
|
/** Background color - named color or hex string like "#ff0000" */
|
||||||
| "bgRed"
|
bgColor?: string;
|
||||||
| "bgGreen"
|
/** Bold text */
|
||||||
| "bgYellow"
|
bold?: boolean;
|
||||||
| "bgBlue"
|
/** Italic text */
|
||||||
| "bgMagenta"
|
italic?: boolean;
|
||||||
| "bgCyan"
|
/** Strikethrough text */
|
||||||
| "bgWhite"
|
strikethrough?: boolean;
|
||||||
| "bgGray";
|
/** Underline text */
|
||||||
|
underline?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export class Markdown implements Component {
|
export class Markdown implements Component {
|
||||||
private text: string;
|
private text: string;
|
||||||
private bgColor?: Color;
|
|
||||||
private fgColor?: Color;
|
|
||||||
private customBgRgb?: { r: number; g: number; b: number };
|
|
||||||
private paddingX: number; // Left/right padding
|
private paddingX: number; // Left/right padding
|
||||||
private paddingY: number; // Top/bottom padding
|
private paddingY: number; // Top/bottom padding
|
||||||
|
private defaultTextStyle?: DefaultTextStyle;
|
||||||
|
|
||||||
// Cache for rendered output
|
// Cache for rendered output
|
||||||
private cachedText?: string;
|
private cachedText?: string;
|
||||||
private cachedWidth?: number;
|
private cachedWidth?: number;
|
||||||
private cachedLines?: string[];
|
private cachedLines?: string[];
|
||||||
|
|
||||||
constructor(
|
constructor(text: string = "", paddingX: number = 1, paddingY: number = 1, defaultTextStyle?: DefaultTextStyle) {
|
||||||
text: string = "",
|
|
||||||
bgColor?: Color,
|
|
||||||
fgColor?: Color,
|
|
||||||
customBgRgb?: { r: number; g: number; b: number },
|
|
||||||
paddingX: number = 1,
|
|
||||||
paddingY: number = 1,
|
|
||||||
) {
|
|
||||||
this.text = text;
|
this.text = text;
|
||||||
this.bgColor = bgColor;
|
|
||||||
this.fgColor = fgColor;
|
|
||||||
this.customBgRgb = customBgRgb;
|
|
||||||
this.paddingX = paddingX;
|
this.paddingX = paddingX;
|
||||||
this.paddingY = paddingY;
|
this.paddingY = paddingY;
|
||||||
|
this.defaultTextStyle = defaultTextStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
setText(text: string): void {
|
setText(text: string): void {
|
||||||
|
|
@ -60,30 +51,6 @@ export class Markdown implements Component {
|
||||||
this.cachedLines = undefined;
|
this.cachedLines = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
setBgColor(bgColor?: Color): void {
|
|
||||||
this.bgColor = bgColor;
|
|
||||||
// Invalidate cache when color changes
|
|
||||||
this.cachedText = undefined;
|
|
||||||
this.cachedWidth = undefined;
|
|
||||||
this.cachedLines = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
setFgColor(fgColor?: Color): void {
|
|
||||||
this.fgColor = fgColor;
|
|
||||||
// Invalidate cache when color changes
|
|
||||||
this.cachedText = undefined;
|
|
||||||
this.cachedWidth = undefined;
|
|
||||||
this.cachedLines = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
setCustomBgRgb(customBgRgb?: { r: number; g: number; b: number }): void {
|
|
||||||
this.customBgRgb = customBgRgb;
|
|
||||||
// Invalidate cache when color changes
|
|
||||||
this.cachedText = undefined;
|
|
||||||
this.cachedWidth = undefined;
|
|
||||||
this.cachedLines = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
render(width: number): string[] {
|
render(width: number): string[] {
|
||||||
// Check cache
|
// Check cache
|
||||||
if (this.cachedLines && this.cachedText === this.text && this.cachedWidth === width) {
|
if (this.cachedLines && this.cachedText === this.text && this.cachedWidth === width) {
|
||||||
|
|
@ -125,7 +92,7 @@ export class Markdown implements Component {
|
||||||
wrappedLines.push(...this.wrapLine(line, contentWidth));
|
wrappedLines.push(...this.wrapLine(line, contentWidth));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add padding and apply colors
|
// Add padding and apply background color if specified
|
||||||
const leftPad = " ".repeat(this.paddingX);
|
const leftPad = " ".repeat(this.paddingX);
|
||||||
const paddedLines: string[] = [];
|
const paddedLines: string[] = [];
|
||||||
|
|
||||||
|
|
@ -139,16 +106,9 @@ export class Markdown implements Component {
|
||||||
// Add left padding, content, and right padding
|
// Add left padding, content, and right padding
|
||||||
let paddedLine = leftPad + line + rightPad;
|
let paddedLine = leftPad + line + rightPad;
|
||||||
|
|
||||||
// Apply foreground color if specified
|
// Apply background color to entire line if specified
|
||||||
if (this.fgColor) {
|
if (this.defaultTextStyle?.bgColor) {
|
||||||
paddedLine = (chalk as any)[this.fgColor](paddedLine);
|
paddedLine = this.applyBgColor(paddedLine);
|
||||||
}
|
|
||||||
|
|
||||||
// Apply background color if specified
|
|
||||||
if (this.customBgRgb) {
|
|
||||||
paddedLine = chalk.bgRgb(this.customBgRgb.r, this.customBgRgb.g, this.customBgRgb.b)(paddedLine);
|
|
||||||
} else if (this.bgColor) {
|
|
||||||
paddedLine = (chalk as any)[this.bgColor](paddedLine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
paddedLines.push(paddedLine);
|
paddedLines.push(paddedLine);
|
||||||
|
|
@ -158,25 +118,15 @@ export class Markdown implements Component {
|
||||||
const emptyLine = " ".repeat(width);
|
const emptyLine = " ".repeat(width);
|
||||||
const topPadding: string[] = [];
|
const topPadding: string[] = [];
|
||||||
for (let i = 0; i < this.paddingY; i++) {
|
for (let i = 0; i < this.paddingY; i++) {
|
||||||
let emptyPaddedLine = emptyLine;
|
const paddedEmptyLine = this.defaultTextStyle?.bgColor ? this.applyBgColor(emptyLine) : emptyLine;
|
||||||
if (this.customBgRgb) {
|
topPadding.push(paddedEmptyLine);
|
||||||
emptyPaddedLine = chalk.bgRgb(this.customBgRgb.r, this.customBgRgb.g, this.customBgRgb.b)(emptyPaddedLine);
|
|
||||||
} else if (this.bgColor) {
|
|
||||||
emptyPaddedLine = (chalk as any)[this.bgColor](emptyPaddedLine);
|
|
||||||
}
|
|
||||||
topPadding.push(emptyPaddedLine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add bottom padding (empty lines)
|
// Add bottom padding (empty lines)
|
||||||
const bottomPadding: string[] = [];
|
const bottomPadding: string[] = [];
|
||||||
for (let i = 0; i < this.paddingY; i++) {
|
for (let i = 0; i < this.paddingY; i++) {
|
||||||
let emptyPaddedLine = emptyLine;
|
const paddedEmptyLine = this.defaultTextStyle?.bgColor ? this.applyBgColor(emptyLine) : emptyLine;
|
||||||
if (this.customBgRgb) {
|
bottomPadding.push(paddedEmptyLine);
|
||||||
emptyPaddedLine = chalk.bgRgb(this.customBgRgb.r, this.customBgRgb.g, this.customBgRgb.b)(emptyPaddedLine);
|
|
||||||
} else if (this.bgColor) {
|
|
||||||
emptyPaddedLine = (chalk as any)[this.bgColor](emptyPaddedLine);
|
|
||||||
}
|
|
||||||
bottomPadding.push(emptyPaddedLine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combine top padding, content, and bottom padding
|
// Combine top padding, content, and bottom padding
|
||||||
|
|
@ -190,6 +140,85 @@ export class Markdown implements Component {
|
||||||
return result.length > 0 ? result : [""];
|
return result.length > 0 ? result : [""];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply only background color from default style.
|
||||||
|
* Used for padding lines that don't have text content.
|
||||||
|
*/
|
||||||
|
private applyBgColor(text: string): string {
|
||||||
|
if (!this.defaultTextStyle?.bgColor) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.defaultTextStyle.bgColor.startsWith("#")) {
|
||||||
|
// Hex color
|
||||||
|
const hex = this.defaultTextStyle.bgColor.substring(1);
|
||||||
|
const r = Number.parseInt(hex.substring(0, 2), 16);
|
||||||
|
const g = Number.parseInt(hex.substring(2, 4), 16);
|
||||||
|
const b = Number.parseInt(hex.substring(4, 6), 16);
|
||||||
|
return colorChalk.bgRgb(r, g, b)(text);
|
||||||
|
}
|
||||||
|
// Named background color (bgRed, bgBlue, etc.)
|
||||||
|
return (colorChalk as any)[this.defaultTextStyle.bgColor](text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply default text style to a string.
|
||||||
|
* This is the base styling applied to all text content.
|
||||||
|
*/
|
||||||
|
private applyDefaultStyle(text: string): string {
|
||||||
|
if (!this.defaultTextStyle) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
let styled = text;
|
||||||
|
|
||||||
|
// Apply color
|
||||||
|
if (this.defaultTextStyle.color) {
|
||||||
|
if (this.defaultTextStyle.color.startsWith("#")) {
|
||||||
|
// Hex color
|
||||||
|
const hex = this.defaultTextStyle.color.substring(1);
|
||||||
|
const r = Number.parseInt(hex.substring(0, 2), 16);
|
||||||
|
const g = Number.parseInt(hex.substring(2, 4), 16);
|
||||||
|
const b = Number.parseInt(hex.substring(4, 6), 16);
|
||||||
|
styled = colorChalk.rgb(r, g, b)(styled);
|
||||||
|
} else {
|
||||||
|
// Named color
|
||||||
|
styled = (colorChalk as any)[this.defaultTextStyle.color](styled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply background color
|
||||||
|
if (this.defaultTextStyle.bgColor) {
|
||||||
|
if (this.defaultTextStyle.bgColor.startsWith("#")) {
|
||||||
|
// Hex color
|
||||||
|
const hex = this.defaultTextStyle.bgColor.substring(1);
|
||||||
|
const r = Number.parseInt(hex.substring(0, 2), 16);
|
||||||
|
const g = Number.parseInt(hex.substring(2, 4), 16);
|
||||||
|
const b = Number.parseInt(hex.substring(4, 6), 16);
|
||||||
|
styled = colorChalk.bgRgb(r, g, b)(styled);
|
||||||
|
} else {
|
||||||
|
// Named background color (bgRed, bgBlue, etc.)
|
||||||
|
styled = (colorChalk as any)[this.defaultTextStyle.bgColor](styled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply text decorations
|
||||||
|
if (this.defaultTextStyle.bold) {
|
||||||
|
styled = colorChalk.bold(styled);
|
||||||
|
}
|
||||||
|
if (this.defaultTextStyle.italic) {
|
||||||
|
styled = colorChalk.italic(styled);
|
||||||
|
}
|
||||||
|
if (this.defaultTextStyle.strikethrough) {
|
||||||
|
styled = colorChalk.strikethrough(styled);
|
||||||
|
}
|
||||||
|
if (this.defaultTextStyle.underline) {
|
||||||
|
styled = colorChalk.underline(styled);
|
||||||
|
}
|
||||||
|
|
||||||
|
return styled;
|
||||||
|
}
|
||||||
|
|
||||||
private renderToken(token: Token, width: number, nextTokenType?: string): string[] {
|
private renderToken(token: Token, width: number, nextTokenType?: string): string[] {
|
||||||
const lines: string[] = [];
|
const lines: string[] = [];
|
||||||
|
|
||||||
|
|
@ -199,11 +228,11 @@ export class Markdown implements Component {
|
||||||
const headingPrefix = "#".repeat(headingLevel) + " ";
|
const headingPrefix = "#".repeat(headingLevel) + " ";
|
||||||
const headingText = this.renderInlineTokens(token.tokens || []);
|
const headingText = this.renderInlineTokens(token.tokens || []);
|
||||||
if (headingLevel === 1) {
|
if (headingLevel === 1) {
|
||||||
lines.push(chalk.bold.underline.yellow(headingText));
|
lines.push(colorChalk.bold.underline.yellow(headingText));
|
||||||
} else if (headingLevel === 2) {
|
} else if (headingLevel === 2) {
|
||||||
lines.push(chalk.bold.yellow(headingText));
|
lines.push(colorChalk.bold.yellow(headingText));
|
||||||
} else {
|
} else {
|
||||||
lines.push(chalk.bold(headingPrefix + headingText));
|
lines.push(colorChalk.bold(headingPrefix + headingText));
|
||||||
}
|
}
|
||||||
lines.push(""); // Add spacing after headings
|
lines.push(""); // Add spacing after headings
|
||||||
break;
|
break;
|
||||||
|
|
@ -220,13 +249,13 @@ export class Markdown implements Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
case "code": {
|
case "code": {
|
||||||
lines.push(chalk.gray("```" + (token.lang || "")));
|
lines.push(colorChalk.gray("```" + (token.lang || "")));
|
||||||
// Split code by newlines and style each line
|
// Split code by newlines and style each line
|
||||||
const codeLines = token.text.split("\n");
|
const codeLines = token.text.split("\n");
|
||||||
for (const codeLine of codeLines) {
|
for (const codeLine of codeLines) {
|
||||||
lines.push(chalk.dim(" ") + chalk.green(codeLine));
|
lines.push(colorChalk.dim(" ") + colorChalk.green(codeLine));
|
||||||
}
|
}
|
||||||
lines.push(chalk.gray("```"));
|
lines.push(colorChalk.gray("```"));
|
||||||
lines.push(""); // Add spacing after code blocks
|
lines.push(""); // Add spacing after code blocks
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -249,14 +278,14 @@ export class Markdown implements Component {
|
||||||
const quoteText = this.renderInlineTokens(token.tokens || []);
|
const quoteText = this.renderInlineTokens(token.tokens || []);
|
||||||
const quoteLines = quoteText.split("\n");
|
const quoteLines = quoteText.split("\n");
|
||||||
for (const quoteLine of quoteLines) {
|
for (const quoteLine of quoteLines) {
|
||||||
lines.push(chalk.gray("│ ") + chalk.italic(quoteLine));
|
lines.push(colorChalk.gray("│ ") + colorChalk.italic(quoteLine));
|
||||||
}
|
}
|
||||||
lines.push(""); // Add spacing after blockquotes
|
lines.push(""); // Add spacing after blockquotes
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "hr":
|
case "hr":
|
||||||
lines.push(chalk.gray("─".repeat(Math.min(width, 80))));
|
lines.push(colorChalk.gray("─".repeat(Math.min(width, 80))));
|
||||||
lines.push(""); // Add spacing after horizontal rules
|
lines.push(""); // Add spacing after horizontal rules
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -289,29 +318,44 @@ export class Markdown implements Component {
|
||||||
if (token.tokens && token.tokens.length > 0) {
|
if (token.tokens && token.tokens.length > 0) {
|
||||||
result += this.renderInlineTokens(token.tokens);
|
result += this.renderInlineTokens(token.tokens);
|
||||||
} else {
|
} else {
|
||||||
result += token.text;
|
// Apply default style to plain text
|
||||||
|
result += this.applyDefaultStyle(token.text);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "strong":
|
case "strong": {
|
||||||
result += chalk.bold(this.renderInlineTokens(token.tokens || []));
|
// Apply bold, then reapply default style after
|
||||||
|
const boldContent = this.renderInlineTokens(token.tokens || []);
|
||||||
|
result += colorChalk.bold(boldContent) + this.applyDefaultStyle("");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case "em":
|
case "em": {
|
||||||
result += chalk.italic(this.renderInlineTokens(token.tokens || []));
|
// Apply italic, then reapply default style after
|
||||||
|
const italicContent = this.renderInlineTokens(token.tokens || []);
|
||||||
|
result += colorChalk.italic(italicContent) + this.applyDefaultStyle("");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case "codespan":
|
case "codespan":
|
||||||
result += chalk.gray("`") + chalk.cyan(token.text) + chalk.gray("`");
|
// Apply code styling, then reapply default style after
|
||||||
|
result +=
|
||||||
|
colorChalk.gray("`") +
|
||||||
|
colorChalk.cyan(token.text) +
|
||||||
|
colorChalk.gray("`") +
|
||||||
|
this.applyDefaultStyle("");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "link": {
|
case "link": {
|
||||||
const linkText = this.renderInlineTokens(token.tokens || []);
|
const linkText = this.renderInlineTokens(token.tokens || []);
|
||||||
// If link text matches href, only show the link once
|
// If link text matches href, only show the link once
|
||||||
if (linkText === token.href) {
|
if (linkText === token.href) {
|
||||||
result += chalk.underline.blue(linkText);
|
result += colorChalk.underline.blue(linkText) + this.applyDefaultStyle("");
|
||||||
} else {
|
} else {
|
||||||
result += chalk.underline.blue(linkText) + chalk.gray(` (${token.href})`);
|
result +=
|
||||||
|
colorChalk.underline.blue(linkText) +
|
||||||
|
colorChalk.gray(` (${token.href})`) +
|
||||||
|
this.applyDefaultStyle("");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -320,14 +364,16 @@ export class Markdown implements Component {
|
||||||
result += "\n";
|
result += "\n";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "del":
|
case "del": {
|
||||||
result += chalk.strikethrough(this.renderInlineTokens(token.tokens || []));
|
const delContent = this.renderInlineTokens(token.tokens || []);
|
||||||
|
result += colorChalk.strikethrough(delContent) + this.applyDefaultStyle("");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Handle any other inline token types as plain text
|
// Handle any other inline token types as plain text
|
||||||
if ("text" in token && typeof token.text === "string") {
|
if ("text" in token && typeof token.text === "string") {
|
||||||
result += token.text;
|
result += this.applyDefaultStyle(token.text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -469,7 +515,7 @@ export class Markdown implements Component {
|
||||||
lines.push(firstLine);
|
lines.push(firstLine);
|
||||||
} else {
|
} else {
|
||||||
// Regular text content - add indent and bullet
|
// Regular text content - add indent and bullet
|
||||||
lines.push(indent + chalk.cyan(bullet) + firstLine);
|
lines.push(indent + colorChalk.cyan(bullet) + firstLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rest of the lines
|
// Rest of the lines
|
||||||
|
|
@ -486,7 +532,7 @@ export class Markdown implements Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
lines.push(indent + chalk.cyan(bullet));
|
lines.push(indent + colorChalk.cyan(bullet));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -517,12 +563,12 @@ export class Markdown implements Component {
|
||||||
lines.push(text);
|
lines.push(text);
|
||||||
} else if (token.type === "code") {
|
} else if (token.type === "code") {
|
||||||
// Code block in list item
|
// Code block in list item
|
||||||
lines.push(chalk.gray("```" + (token.lang || "")));
|
lines.push(colorChalk.gray("```" + (token.lang || "")));
|
||||||
const codeLines = token.text.split("\n");
|
const codeLines = token.text.split("\n");
|
||||||
for (const codeLine of codeLines) {
|
for (const codeLine of codeLines) {
|
||||||
lines.push(chalk.dim(" ") + chalk.green(codeLine));
|
lines.push(colorChalk.dim(" ") + colorChalk.green(codeLine));
|
||||||
}
|
}
|
||||||
lines.push(chalk.gray("```"));
|
lines.push(colorChalk.gray("```"));
|
||||||
} else {
|
} else {
|
||||||
// Other token types - try to render as inline
|
// Other token types - try to render as inline
|
||||||
const text = this.renderInlineTokens([token]);
|
const text = this.renderInlineTokens([token]);
|
||||||
|
|
@ -569,7 +615,7 @@ export class Markdown implements Component {
|
||||||
// Render header
|
// Render header
|
||||||
const headerCells = token.header.map((cell, i) => {
|
const headerCells = token.header.map((cell, i) => {
|
||||||
const text = this.renderInlineTokens(cell.tokens || []);
|
const text = this.renderInlineTokens(cell.tokens || []);
|
||||||
return chalk.bold(text.padEnd(columnWidths[i]));
|
return colorChalk.bold(text.padEnd(columnWidths[i]));
|
||||||
});
|
});
|
||||||
lines.push("│ " + headerCells.join(" │ ") + " │");
|
lines.push("│ " + headerCells.join(" │ ") + " │");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ editor.onSubmit = (value: string) => {
|
||||||
isResponding = true;
|
isResponding = true;
|
||||||
editor.disableSubmit = true;
|
editor.disableSubmit = true;
|
||||||
|
|
||||||
const userMessage = new Markdown(value, undefined, undefined, { r: 52, g: 53, b: 65 });
|
const userMessage = new Markdown(value, 1, 1, { bgColor: "#343541" });
|
||||||
|
|
||||||
const children = tui.children;
|
const children = tui.children;
|
||||||
children.splice(children.length - 1, 0, userMessage);
|
children.splice(children.length - 1, 0, userMessage);
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,6 @@ describe("Markdown component", () => {
|
||||||
- Nested 1.1
|
- Nested 1.1
|
||||||
- Nested 1.2
|
- Nested 1.2
|
||||||
- Item 2`,
|
- Item 2`,
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
@ -38,9 +35,6 @@ describe("Markdown component", () => {
|
||||||
- Level 2
|
- Level 2
|
||||||
- Level 3
|
- Level 3
|
||||||
- Level 4`,
|
- Level 4`,
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
@ -61,9 +55,6 @@ describe("Markdown component", () => {
|
||||||
1. Nested first
|
1. Nested first
|
||||||
2. Nested second
|
2. Nested second
|
||||||
2. Second`,
|
2. Second`,
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
@ -84,9 +75,6 @@ describe("Markdown component", () => {
|
||||||
- Another nested
|
- Another nested
|
||||||
2. Second ordered
|
2. Second ordered
|
||||||
- More nested`,
|
- More nested`,
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
@ -107,9 +95,6 @@ describe("Markdown component", () => {
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Alice | 30 |
|
| Alice | 30 |
|
||||||
| Bob | 25 |`,
|
| Bob | 25 |`,
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
@ -133,9 +118,6 @@ describe("Markdown component", () => {
|
||||||
| :--- | :---: | ---: |
|
| :--- | :---: | ---: |
|
||||||
| A | B | C |
|
| A | B | C |
|
||||||
| Long text | Middle | End |`,
|
| Long text | Middle | End |`,
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
@ -157,9 +139,6 @@ describe("Markdown component", () => {
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| A | This is a much longer cell content |
|
| A | This is a much longer cell content |
|
||||||
| B | Short |`,
|
| B | Short |`,
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
@ -187,9 +166,6 @@ describe("Markdown component", () => {
|
||||||
| Col1 | Col2 |
|
| Col1 | Col2 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| A | B |`,
|
| A | B |`,
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
@ -207,4 +183,84 @@ describe("Markdown component", () => {
|
||||||
assert.ok(plainLines.some((line) => line.includes("│")));
|
assert.ok(plainLines.some((line) => line.includes("│")));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Pre-styled text (thinking traces)", () => {
|
||||||
|
it("should preserve gray italic styling after inline code", () => {
|
||||||
|
// This replicates how thinking content is rendered in assistant-message.ts
|
||||||
|
const markdown = new Markdown("This is thinking with `inline code` and more text after", 1, 0, {
|
||||||
|
color: "gray",
|
||||||
|
italic: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const lines = markdown.render(80);
|
||||||
|
const joinedOutput = lines.join("\n");
|
||||||
|
|
||||||
|
// Should contain the inline code block
|
||||||
|
assert.ok(joinedOutput.includes("inline code"));
|
||||||
|
|
||||||
|
// The output should have ANSI codes for gray (90) and italic (3)
|
||||||
|
assert.ok(joinedOutput.includes("\x1b[90m"), "Should have gray color code");
|
||||||
|
assert.ok(joinedOutput.includes("\x1b[3m"), "Should have italic code");
|
||||||
|
|
||||||
|
// Verify that after the inline code (cyan text), we reapply gray italic
|
||||||
|
const hasCyan = joinedOutput.includes("\x1b[36m"); // cyan
|
||||||
|
assert.ok(hasCyan, "Should have cyan for inline code");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should preserve gray italic styling after bold text", () => {
|
||||||
|
const markdown = new Markdown("This is thinking with **bold text** and more after", 1, 0, {
|
||||||
|
color: "gray",
|
||||||
|
italic: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const lines = markdown.render(80);
|
||||||
|
const joinedOutput = lines.join("\n");
|
||||||
|
|
||||||
|
// Should contain bold text
|
||||||
|
assert.ok(joinedOutput.includes("bold text"));
|
||||||
|
|
||||||
|
// The output should have ANSI codes for gray (90) and italic (3)
|
||||||
|
assert.ok(joinedOutput.includes("\x1b[90m"), "Should have gray color code");
|
||||||
|
assert.ok(joinedOutput.includes("\x1b[3m"), "Should have italic code");
|
||||||
|
|
||||||
|
// Should have bold codes (1 or 22 for bold on/off)
|
||||||
|
assert.ok(joinedOutput.includes("\x1b[1m"), "Should have bold code");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("HTML-like tags in text", () => {
|
||||||
|
it("should render content with HTML-like tags as text", () => {
|
||||||
|
// When the model emits something like <thinking>content</thinking> in regular text,
|
||||||
|
// marked might treat it as HTML and hide the content
|
||||||
|
const markdown = new Markdown(
|
||||||
|
"This is text with <thinking>hidden content</thinking> that should be visible",
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
|
const lines = markdown.render(80);
|
||||||
|
const plainLines = lines.map((line) => line.replace(/\x1b\[[0-9;]*m/g, ""));
|
||||||
|
const joinedPlain = plainLines.join(" ");
|
||||||
|
|
||||||
|
// The content inside the tags should be visible
|
||||||
|
assert.ok(
|
||||||
|
joinedPlain.includes("hidden content") || joinedPlain.includes("<thinking>"),
|
||||||
|
"Should render HTML-like tags or their content as text, not hide them",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render HTML tags in code blocks correctly", () => {
|
||||||
|
const markdown = new Markdown("```html\n<div>Some HTML</div>\n```", 0, 0);
|
||||||
|
|
||||||
|
const lines = markdown.render(80);
|
||||||
|
const plainLines = lines.map((line) => line.replace(/\x1b\[[0-9;]*m/g, ""));
|
||||||
|
const joinedPlain = plainLines.join("\n");
|
||||||
|
|
||||||
|
// HTML in code blocks should be visible
|
||||||
|
assert.ok(
|
||||||
|
joinedPlain.includes("<div>") && joinedPlain.includes("</div>"),
|
||||||
|
"Should render HTML in code blocks",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@mariozechner/pi-web-ui",
|
"name": "@mariozechner/pi-web-ui",
|
||||||
"version": "0.7.17",
|
"version": "0.7.18",
|
||||||
"description": "Reusable web UI components for AI chat interfaces powered by @mariozechner/pi-ai",
|
"description": "Reusable web UI components for AI chat interfaces powered by @mariozechner/pi-ai",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
|
@ -18,8 +18,8 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lmstudio/sdk": "^1.5.0",
|
"@lmstudio/sdk": "^1.5.0",
|
||||||
"@mariozechner/pi-ai": "^0.7.17",
|
"@mariozechner/pi-ai": "^0.7.18",
|
||||||
"@mariozechner/pi-tui": "^0.7.17",
|
"@mariozechner/pi-tui": "^0.7.18",
|
||||||
"docx-preview": "^0.3.7",
|
"docx-preview": "^0.3.7",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"lucide": "^0.544.0",
|
"lucide": "^0.544.0",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue