Skip to content

Commit 3465709

Browse files
committed
feat(provider): add file_read item type to distinguish read operations f
- Classify read operations (read, glob, grep, search, list, find, view, ls, cat) as file_read type - Add titleForReadTool() for contextual titles based on tool name - Update exploration card and timeline to recognize file_read type - File operations now correctly distinguished in UI by operation type
1 parent d1e8671 commit 3465709

5 files changed

Lines changed: 44 additions & 6 deletions

File tree

apps/server/src/provider/Layers/ClaudeAdapter.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,7 @@ describe("ClaudeAdapterLive", () => {
919919
const toolStarted = runtimeEvents.find((event) => event.type === "item.started");
920920
assert.equal(toolStarted?.type, "item.started");
921921
if (toolStarted?.type === "item.started") {
922-
assert.equal(toolStarted.payload.itemType, "dynamic_tool_call");
922+
assert.equal(toolStarted.payload.itemType, "file_read");
923923
}
924924

925925
const toolInputUpdated = runtimeEvents.find(

apps/server/src/provider/Layers/ClaudeAdapter.ts

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -418,14 +418,30 @@ function classifyToolItemType(toolName: string): CanonicalItemType {
418418
if (
419419
normalized.includes("edit") ||
420420
normalized.includes("write") ||
421-
normalized.includes("file") ||
422421
normalized.includes("patch") ||
423422
normalized.includes("replace") ||
424423
normalized.includes("create") ||
425-
normalized.includes("delete")
424+
normalized.includes("delete") ||
425+
normalized.includes("notebookedit")
426426
) {
427427
return "file_change";
428428
}
429+
if (
430+
normalized === "read" ||
431+
normalized.includes("glob") ||
432+
normalized.includes("grep") ||
433+
normalized.includes("search") ||
434+
normalized.includes("list") ||
435+
normalized.includes("find") ||
436+
normalized.includes("view") ||
437+
normalized.includes("ls") ||
438+
normalized.includes("cat")
439+
) {
440+
return "file_read";
441+
}
442+
if (normalized.includes("file")) {
443+
return "file_change";
444+
}
429445
if (normalized.includes("mcp")) {
430446
return "mcp_tool_call";
431447
}
@@ -476,12 +492,14 @@ function summarizeToolRequest(toolName: string, input: Record<string, unknown>):
476492
return `${toolName}: ${serialized.slice(0, 397)}...`;
477493
}
478494

479-
function titleForTool(itemType: CanonicalItemType): string {
495+
function titleForTool(itemType: CanonicalItemType, toolName?: string): string {
480496
switch (itemType) {
481497
case "command_execution":
482498
return "Command run";
483499
case "file_change":
484500
return "File change";
501+
case "file_read":
502+
return titleForReadTool(toolName);
485503
case "mcp_tool_call":
486504
return "MCP tool call";
487505
case "collab_agent_tool_call":
@@ -497,6 +515,19 @@ function titleForTool(itemType: CanonicalItemType): string {
497515
}
498516
}
499517

518+
function titleForReadTool(toolName?: string): string {
519+
if (!toolName) return "Read";
520+
const normalized = toolName.toLowerCase();
521+
if (normalized === "read") return "Read file";
522+
if (normalized.includes("glob")) return "Glob search";
523+
if (normalized.includes("grep")) return "Grep search";
524+
if (normalized.includes("search")) return "Search";
525+
if (normalized.includes("list") || normalized.includes("ls")) return "List files";
526+
if (normalized.includes("find")) return "Find files";
527+
if (normalized.includes("view")) return "View file";
528+
return "Read";
529+
}
530+
500531
const SUPPORTED_CLAUDE_IMAGE_MIME_TYPES = new Set([
501532
"image/gif",
502533
"image/jpeg",
@@ -1652,7 +1683,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (
16521683
itemId,
16531684
itemType,
16541685
toolName,
1655-
title: titleForTool(itemType),
1686+
title: titleForTool(itemType, toolName),
16561687
detail,
16571688
input: toolInput,
16581689
partialInputJson: "",

apps/web/src/components/chat/ExplorationCard.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ interface ExplorationCardProps {
1111
const READ_LABEL_RE = /^Read\b/i;
1212

1313
function isReadEntry(entry: WorkLogEntry): boolean {
14-
return entry.requestKind === "file-read" || READ_LABEL_RE.test(entry.toolTitle ?? entry.label);
14+
return (
15+
entry.requestKind === "file-read" ||
16+
entry.itemType === "file_read" ||
17+
READ_LABEL_RE.test(entry.toolTitle ?? entry.label)
18+
);
1519
}
1620

1721
function explorationEntryHeading(entry: WorkLogEntry): string {

apps/web/src/components/chat/MessagesTimeline.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,7 @@ function isExplorationEntry(entry: TimelineWorkEntry): boolean {
10201020
if (entry.agentGroup) return false;
10211021

10221022
if (entry.requestKind === "file-read") return true;
1023+
if (entry.itemType === "file_read") return true;
10231024
if (entry.itemType === "image_view") return true;
10241025

10251026
const heading = (entry.toolTitle ?? entry.label).trim();
@@ -1057,6 +1058,7 @@ function workEntryIcon(workEntry: TimelineWorkEntry): LucideIcon {
10571058
if (workEntry.itemType === "file_change" || (workEntry.changedFiles?.length ?? 0) > 0) {
10581059
return SquarePenIcon;
10591060
}
1061+
if (workEntry.itemType === "file_read") return EyeIcon;
10601062
if (workEntry.itemType === "web_search") return GlobeIcon;
10611063
if (workEntry.itemType === "image_view") return EyeIcon;
10621064

packages/contracts/src/providerRuntime.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ export type RuntimeErrorClass = typeof RuntimeErrorClass.Type;
100100
export const TOOL_LIFECYCLE_ITEM_TYPES = [
101101
"command_execution",
102102
"file_change",
103+
"file_read",
103104
"mcp_tool_call",
104105
"dynamic_tool_call",
105106
"collab_agent_tool_call",

0 commit comments

Comments
 (0)