107 lines
2.6 KiB
TypeScript
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 "";
|
|
}
|
|
}
|