Files
pi-mobile/apps/mobile/lib/tool-format.ts
T
2026-07-09 12:07:57 -05:00

107 lines
2.6 KiB
TypeScript

const PREVIEW_KEYS = [
"command",
"cmd",
"path",
"file_path",
"filePath",
"pattern",
"query",
"url",
] as const;
const MAX_PREVIEW_LENGTH = 160;
const MAX_DETAIL_LENGTH = 6000;
/** Single-line summary of tool call arguments, e.g. the bash command or file path. */
export function toolArgsPreview(args: unknown): string | undefined {
if (!args || typeof args !== "object" || Array.isArray(args)) {
return undefined;
}
const record = args as Record<string, unknown>;
let preview: string | undefined;
for (const key of PREVIEW_KEYS) {
const value = record[key];
if (typeof value === "string" && value.trim()) {
preview = value.trim();
break;
}
}
if (!preview) {
const entries = Object.entries(record).filter(([, value]) => value !== undefined);
if (entries.length === 0) {
return undefined;
}
preview = entries
.map(([key, value]) => `${key}: ${typeof value === "string" ? value : safeStringify(value)}`)
.join(", ");
}
const lines = preview.split("\n");
let line = lines[0].trim();
if (lines.length > 1) {
line += " …";
}
return line.length > MAX_PREVIEW_LENGTH ? `${line.slice(0, MAX_PREVIEW_LENGTH)}…` : line;
}
/** Pulls readable text out of a tool result / partial result of unknown shape. */
export function extractResultText(result: unknown): string {
if (result == null) {
return "";
}
if (typeof result === "string") {
return result;
}
if (Array.isArray(result)) {
return result.map(blockText).join("");
}
if (typeof result === "object") {
const record = result as Record<string, unknown>;
if (Array.isArray(record.content)) {
return record.content.map(blockText).join("");
}
if (typeof record.output === "string") {
return record.output;
}
if (typeof record.text === "string") {
return record.text;
}
return safeStringify(record);
}
return String(result);
}
/** Caps tool output length so a huge result doesn't bloat list state. */
export function truncateDetail(text: string): string {
const trimmed = text.trim();
if (trimmed.length <= MAX_DETAIL_LENGTH) {
return trimmed;
}
return `${trimmed.slice(0, MAX_DETAIL_LENGTH)}\n… (output truncated)`;
}
function blockText(block: unknown): string {
if (typeof block === "string") {
return block;
}
if (typeof block === "object" && block && "text" in block) {
return String((block as { text?: string }).text ?? "");
}
return "";
}
function safeStringify(value: unknown): string {
try {
return JSON.stringify(value) ?? "";
} catch {
return "";
}
}