Files
paseo/packages/app/src/utils/tool-call-detail-state.ts
T
Mohamed BoudraandGitHub 53c14d9855 Extract client SDK package (#1052)
* Extract client SDK package

* Polish SDK client identity defaults

* Build client before dependent CI jobs

* Restore daemon client server export

* Extract protocol and client SDK packages

* Fix provider override schema validation

* Fix app test daemon client imports

* Simplify workspace build targets

* Fix CLI test server build bootstrap

* Run SDK package tests in CI

* Fix rebase package split drift

* Restore lockfile registry metadata

* Update SDK config test for prompt default

* Move terminal stream router test to client package

* Fix rebase drift for protocol imports

* Fix SDK agent capability fixture

* Restore legacy server client exports

* Fix server export compatibility test

* Advertise custom mode icon client capability

* Remove server daemon-client exports

* Format rebased mode control import

* Fix rebase drift for protocol imports

Files added by upstream PRs (#893, #1147, #1154) referenced the pre-split
shared/ paths that this branch moves into @getpaseo/protocol. Redirect
those imports to the protocol package so typecheck stays green after the
rebase.
2026-05-28 01:58:18 +08:00

104 lines
3.4 KiB
TypeScript

import type { ToolCallDetail } from "@getpaseo/protocol/agent-types";
function hasMeaningfulUnknownValue(value: unknown): boolean {
if (value === null || value === undefined) {
return false;
}
if (typeof value === "string") {
return value.trim().length > 0;
}
if (typeof value === "number" || typeof value === "boolean") {
return true;
}
if (Array.isArray(value)) {
return value.some(hasMeaningfulUnknownValue);
}
if (typeof value === "object") {
return Object.values(value).some(hasMeaningfulUnknownValue);
}
return true;
}
function hasMeaningfulSearchDetail(detail: Extract<ToolCallDetail, { type: "search" }>): boolean {
if (detail.query.trim().length > 0) return true;
if (detail.content) return true;
if (detail.filePaths && detail.filePaths.length > 0) return true;
if (detail.webResults && detail.webResults.length > 0) return true;
if (detail.annotations && detail.annotations.length > 0) return true;
return false;
}
function hasMeaningfulReadLikeDetail(detail: { filePath?: unknown; content?: unknown }): boolean {
return Boolean(detail.filePath || detail.content);
}
function hasMeaningfulEditDetail(detail: Extract<ToolCallDetail, { type: "edit" }>): boolean {
return Boolean(detail.filePath || detail.unifiedDiff || detail.oldString || detail.newString);
}
function hasMeaningfulFetchDetail(detail: Extract<ToolCallDetail, { type: "fetch" }>): boolean {
return Boolean(detail.url || detail.result || detail.codeText);
}
function hasMeaningfulWorktreeSetupDetail(
detail: Extract<ToolCallDetail, { type: "worktree_setup" }>,
): boolean {
return Boolean(detail.branchName || detail.worktreePath || detail.log);
}
function hasMeaningfulSubAgentDetail(
detail: Extract<ToolCallDetail, { type: "sub_agent" }>,
): boolean {
return Boolean(detail.subAgentType || detail.description || detail.log);
}
function hasMeaningfulPlainTextDetail(
detail: Extract<ToolCallDetail, { type: "plain_text" }>,
): boolean {
return Boolean(detail.label || detail.text);
}
function hasMeaningfulUnknownDetail(detail: Extract<ToolCallDetail, { type: "unknown" }>): boolean {
return hasMeaningfulUnknownValue(detail.input) || hasMeaningfulUnknownValue(detail.output);
}
export function hasMeaningfulToolCallDetail(detail: ToolCallDetail | undefined): boolean {
if (!detail) {
return false;
}
switch (detail.type) {
case "shell":
return true;
case "read":
return hasMeaningfulReadLikeDetail(detail);
case "edit":
return hasMeaningfulEditDetail(detail);
case "write":
return hasMeaningfulReadLikeDetail(detail);
case "search":
return hasMeaningfulSearchDetail(detail);
case "fetch":
return hasMeaningfulFetchDetail(detail);
case "worktree_setup":
return hasMeaningfulWorktreeSetupDetail(detail);
case "sub_agent":
return hasMeaningfulSubAgentDetail(detail);
case "plain_text":
return hasMeaningfulPlainTextDetail(detail);
case "plan":
return detail.text.trim().length > 0;
case "unknown":
return hasMeaningfulUnknownDetail(detail);
}
}
export function isPendingToolCallDetail(params: {
detail: ToolCallDetail | undefined;
status: "executing" | "running" | "completed" | "failed" | "canceled";
error: unknown;
}): boolean {
const isRunning = params.status === "running" || params.status === "executing";
return isRunning && params.error == null && !hasMeaningfulToolCallDetail(params.detail);
}