mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 18:01:22 +00:00
Add /thinking command and improve TUI UX
- Add /thinking slash command with autocomplete for setting reasoning levels (off, minimal, low, medium, high) - Fix Ctrl+C behavior: remove hardcoded exit in TUI, let focused component handle it - Add empty lines before and after tool execution components for better visual separation - Fix stats rendering: display stats AFTER tool executions complete (matches web-ui behavior) - Remove "Press Ctrl+C again to exit" message, show "(esc to interrupt)" in loader instead - Add bash tool abort signal support with immediate SIGKILL on interrupt - Make Text and Markdown components return empty arrays when no actual text content - Add setCustomBgRgb() method to Markdown for dynamic background colors
This commit is contained in:
parent
c5083bb7cb
commit
dc1e2f928b
7 changed files with 516 additions and 166 deletions
|
|
@ -1,9 +1,6 @@
|
|||
import type { AgentTool } from "@mariozechner/pi-ai";
|
||||
import { Type } from "@sinclair/typebox";
|
||||
import { exec } from "child_process";
|
||||
import { promisify } from "util";
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
const bashSchema = Type.Object({
|
||||
command: Type.String({ description: "Bash command to execute" }),
|
||||
|
|
@ -15,23 +12,54 @@ export const bashTool: AgentTool<typeof bashSchema> = {
|
|||
description:
|
||||
"Execute a bash command in the current working directory. Returns stdout and stderr. Commands run with a 30 second timeout.",
|
||||
parameters: bashSchema,
|
||||
execute: async (_toolCallId: string, { command }: { command: string }) => {
|
||||
try {
|
||||
const { stdout, stderr } = await execAsync(command, {
|
||||
timeout: 30000,
|
||||
maxBuffer: 10 * 1024 * 1024, // 10MB
|
||||
});
|
||||
execute: async (_toolCallId: string, { command }: { command: string }, signal?: AbortSignal) => {
|
||||
return new Promise((resolve) => {
|
||||
const child = exec(
|
||||
command,
|
||||
{
|
||||
timeout: 30000,
|
||||
maxBuffer: 10 * 1024 * 1024, // 10MB
|
||||
},
|
||||
(error, stdout, stderr) => {
|
||||
if (signal) {
|
||||
signal.removeEventListener("abort", onAbort);
|
||||
}
|
||||
|
||||
let output = "";
|
||||
if (stdout) output += stdout;
|
||||
if (stderr) output += stderr ? `\nSTDERR:\n${stderr}` : "";
|
||||
if (signal?.aborted) {
|
||||
resolve({
|
||||
output: `Command aborted by user\nSTDOUT: ${stdout}\nSTDERR: ${stderr}`,
|
||||
details: undefined,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
return { output: output || "(no output)", details: undefined };
|
||||
} catch (error: any) {
|
||||
return {
|
||||
output: `Error executing command: ${error.message}\nSTDOUT: ${error.stdout || ""}\nSTDERR: ${error.stderr || ""}`,
|
||||
details: undefined,
|
||||
let output = "";
|
||||
if (stdout) output += stdout;
|
||||
if (stderr) output += stderr ? `\nSTDERR:\n${stderr}` : "";
|
||||
|
||||
if (error && !error.killed) {
|
||||
resolve({
|
||||
output: `Error executing command: ${error.message}\n${output}`,
|
||||
details: undefined,
|
||||
});
|
||||
} else {
|
||||
resolve({ output: output || "(no output)", details: undefined });
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Handle abort signal
|
||||
const onAbort = () => {
|
||||
child.kill("SIGKILL");
|
||||
};
|
||||
}
|
||||
|
||||
if (signal) {
|
||||
if (signal.aborted) {
|
||||
onAbort();
|
||||
} else {
|
||||
signal.addEventListener("abort", onAbort, { once: true });
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue