Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
170 lines
4.4 KiB
TypeScript
170 lines
4.4 KiB
TypeScript
import type { AgentAskUserQuestionItemVM } from "../contracts/agentAskUserQuestionItemVM";
|
|
import type { AgentPlanModeItemVM } from "../contracts/agentPlanModeItemVM";
|
|
import type { AgentTaskItemVM } from "../contracts/agentTaskItemVM";
|
|
import type {
|
|
AgentToolCallVM,
|
|
AgentToolRendererKind
|
|
} from "../contracts/agentToolCallVM";
|
|
import { isImageGenerationToolCall } from "../../imageGenerationTool";
|
|
|
|
interface AgentToolRendererProbe {
|
|
toolName: string | null | undefined;
|
|
displayName?: string | null | undefined;
|
|
callType: string | null | undefined;
|
|
input?: Record<string, unknown> | null;
|
|
output?: Record<string, unknown> | null;
|
|
metadata?: Record<string, unknown> | null;
|
|
}
|
|
|
|
export function resolveAgentToolRendererKind(
|
|
call: AgentToolRendererProbe,
|
|
approval: AgentToolCallVM["approval"] = null,
|
|
askUserQuestion: AgentAskUserQuestionItemVM | null = null,
|
|
planMode: AgentPlanModeItemVM | null = null,
|
|
task: AgentTaskItemVM | null = null
|
|
): AgentToolRendererKind {
|
|
const normalizedToolName = normalizeToolName(call.toolName);
|
|
const normalizedCallType = normalizeCallType(call.callType);
|
|
if (approval) {
|
|
return "approval";
|
|
}
|
|
if (askUserQuestion) {
|
|
return "ask-user";
|
|
}
|
|
if (normalizedToolName === "askuserquestion") {
|
|
return "ask-user";
|
|
}
|
|
if (planMode?.kind === "enter") {
|
|
return "plan-enter";
|
|
}
|
|
if (normalizedToolName === "enterplanmode") {
|
|
return "plan-enter";
|
|
}
|
|
if (planMode?.kind === "exit") {
|
|
return "plan-exit";
|
|
}
|
|
if (normalizedToolName === "exitplanmode") {
|
|
return "plan-exit";
|
|
}
|
|
if (normalizedCallType === "approval" || normalizedToolName === "approval") {
|
|
return "approval";
|
|
}
|
|
if (task) {
|
|
return "task";
|
|
}
|
|
if (
|
|
["task", "subagent", "delegatetask", "delegateagent", "agent"].includes(
|
|
normalizedToolName
|
|
)
|
|
) {
|
|
return "task";
|
|
}
|
|
if (
|
|
isImageGenerationToolCall({
|
|
toolName: call.toolName,
|
|
displayName: call.displayName,
|
|
outputSavedPath: call.output?.savedPath,
|
|
outputSavedPaths: call.output?.savedPaths,
|
|
outputMimeType: call.output?.imageMimeType,
|
|
outputText: call.output?.text,
|
|
inputPrompt: call.input?.prompt
|
|
})
|
|
) {
|
|
return "image-generation";
|
|
}
|
|
switch (normalizedToolName) {
|
|
case "read":
|
|
case "readfile":
|
|
return "read";
|
|
case "write":
|
|
case "writefile":
|
|
return "write";
|
|
case "edit":
|
|
case "editfile":
|
|
case "multiedit":
|
|
return "edit";
|
|
case "bash":
|
|
case "shell":
|
|
case "exec":
|
|
case "execcommand":
|
|
return "bash";
|
|
case "grep":
|
|
case "glob":
|
|
case "search":
|
|
case "searchfiles":
|
|
return "search";
|
|
case "websearch":
|
|
return "web-search";
|
|
case "webfetch":
|
|
return "web-fetch";
|
|
case "todowrite":
|
|
return "todo-write";
|
|
case "toolsearch":
|
|
return "tool-search";
|
|
case "skill":
|
|
return "skill";
|
|
default:
|
|
if (
|
|
normalizedCallType === "mcp" ||
|
|
normalizedToolName.startsWith("mcp") ||
|
|
hasMcpMetadata(call.metadata)
|
|
) {
|
|
return "mcp";
|
|
}
|
|
return "default";
|
|
}
|
|
}
|
|
|
|
export function inferToolCallType(toolName: string | null | undefined): string {
|
|
const normalizedToolName = normalizeToolName(toolName);
|
|
if (normalizedToolName === "approval") {
|
|
return "approval";
|
|
}
|
|
if (
|
|
["askuserquestion", "enterplanmode", "exitplanmode"].includes(
|
|
normalizedToolName
|
|
)
|
|
) {
|
|
return "interactive";
|
|
}
|
|
if (normalizedToolName.startsWith("mcp")) {
|
|
return "mcp";
|
|
}
|
|
return "tool";
|
|
}
|
|
|
|
export function isApprovalToolCall(call: {
|
|
toolName: string | null | undefined;
|
|
callType: string | null | undefined;
|
|
}): boolean {
|
|
return (
|
|
normalizeCallType(call.callType) === "approval" ||
|
|
normalizeToolName(call.toolName) === "approval"
|
|
);
|
|
}
|
|
|
|
export function normalizeToolName(value: string | null | undefined): string {
|
|
return (value ?? "")
|
|
.replace(/[_\s-]+/g, "")
|
|
.trim()
|
|
.toLowerCase();
|
|
}
|
|
|
|
function hasMcpMetadata(
|
|
metadata: Record<string, unknown> | null | undefined
|
|
): boolean {
|
|
return Boolean(
|
|
stringValue(metadata?.server) ??
|
|
stringValue(metadata?.serverName) ??
|
|
stringValue(metadata?.mcpServer)
|
|
);
|
|
}
|
|
|
|
function normalizeCallType(value: string | null | undefined): string {
|
|
return (value ?? "").trim().toLowerCase();
|
|
}
|
|
|
|
function stringValue(value: unknown): string | null {
|
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
}
|