Skip to content

Commit cf4c30a

Browse files
Show skill reads as ACP read tool calls
1 parent c516b9a commit cf4c30a

3 files changed

Lines changed: 108 additions & 1 deletion

File tree

src/CodexToolCallMapper.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,23 @@ export function createCommandActionEvent(
427427
): AcpToolCallEvent {
428428
const acpStatus = toAcpStatus(status);
429429
switch (commandAction.type) {
430-
case "read":
430+
case "read": {
431+
const skillName = skillNameFromSkillPath(commandAction.path);
432+
if (skillName) {
433+
return {
434+
sessionUpdate: "tool_call",
435+
toolCallId: id,
436+
status: acpStatus,
437+
kind: "read",
438+
title: `Read ${formatSkillName(skillName)} skill`,
439+
locations: [{ path: commandAction.path }],
440+
rawInput: {
441+
type: "skill",
442+
name: skillName,
443+
path: commandAction.path,
444+
},
445+
};
446+
}
431447
return {
432448
sessionUpdate: "tool_call",
433449
toolCallId: id,
@@ -436,6 +452,7 @@ export function createCommandActionEvent(
436452
title: `Read file '${commandAction.path}'`,
437453
locations: [{ path: commandAction.path }],
438454
};
455+
}
439456
case "search":
440457
return {
441458
sessionUpdate: "tool_call",
@@ -471,6 +488,34 @@ export function createCommandActionEvent(
471488
}
472489
}
473490

491+
function skillNameFromSkillPath(filePath: string): string | null {
492+
const normalized = filePath.replace(/[\\/]+/g, "/");
493+
const segments = normalized.split("/").filter(segment => segment.length > 0);
494+
if (segments.at(-1) !== "SKILL.md") {
495+
return null;
496+
}
497+
498+
const skillDirectory = segments.at(-2);
499+
if (!skillDirectory) {
500+
return null;
501+
}
502+
503+
const parent = segments.at(-3);
504+
if (parent !== "skills") {
505+
return null;
506+
}
507+
508+
return skillDirectory;
509+
}
510+
511+
function formatSkillName(skillName: string): string {
512+
return skillName
513+
.split(/[-_\s]+/g)
514+
.filter(part => part.length > 0)
515+
.map(part => part.length <= 3 ? part.toUpperCase() : `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`)
516+
.join(" ");
517+
}
518+
474519
export function commandExecutionUsesTerminalOutput(item: CommandExecutionItem): boolean {
475520
const commandAction = item.commandActions.length === 1 ? item.commandActions[0] : undefined;
476521
return commandAction === undefined || commandAction.type === "unknown";

src/__tests__/CodexACPAgent/command-action-events.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,43 @@ describe('CodexEventHandler - command action events', () => {
128128
);
129129
});
130130

131+
it('should render skill instruction reads as skill read tool calls', async () => {
132+
const readSkillNotification: ServerNotification = {
133+
method: 'item/started',
134+
params: {
135+
threadId: sessionId,
136+
turnId: 'turn-1',
137+
startedAtMs: 0,
138+
item: {
139+
type: 'commandExecution',
140+
id: 'command-read-skill',
141+
command: "sed -n '1,240p' /test/project/.agents/skills/ui-accessibility/SKILL.md",
142+
cwd: '/test/project',
143+
processId: null,
144+
source: 'agent',
145+
status: 'inProgress',
146+
commandActions: [
147+
{
148+
type: 'read',
149+
command: "sed -n '1,240p' /test/project/.agents/skills/ui-accessibility/SKILL.md",
150+
name: 'SKILL.md',
151+
path: '/test/project/.agents/skills/ui-accessibility/SKILL.md',
152+
},
153+
],
154+
aggregatedOutput: null,
155+
exitCode: null,
156+
durationMs: null,
157+
},
158+
},
159+
};
160+
161+
await setupPromptAndSendNotifications(mockFixture, sessionId, sessionState, [readSkillNotification]);
162+
163+
await expect(mockFixture.getAcpConnectionDump([])).toMatchFileSnapshot(
164+
'data/command-read-skill.json'
165+
);
166+
});
167+
131168
it('should handle search command with query and path', async () => {
132169
const searchNotification: ServerNotification = {
133170
method: 'item/started',
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"method": "sessionUpdate",
3+
"args": [
4+
{
5+
"sessionId": "test-session-id",
6+
"update": {
7+
"sessionUpdate": "tool_call",
8+
"toolCallId": "command-read-skill",
9+
"status": "in_progress",
10+
"kind": "read",
11+
"title": "Read UI Accessibility skill",
12+
"locations": [
13+
{
14+
"path": "/test/project/.agents/skills/ui-accessibility/SKILL.md"
15+
}
16+
],
17+
"rawInput": {
18+
"type": "skill",
19+
"name": "ui-accessibility",
20+
"path": "/test/project/.agents/skills/ui-accessibility/SKILL.md"
21+
}
22+
}
23+
}
24+
]
25+
}

0 commit comments

Comments
 (0)