Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 68 additions & 6 deletions src/acp-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,6 @@ export class ClaudeAcpAgent implements Agent {
cachedReadTokens: 0,
cachedWriteTokens: 0,
};

let lastAssistantTotalUsage: number | null = null;
let lastAssistantModel: string | null = null;
let lastContextWindowSize: number = 200000;
Expand Down Expand Up @@ -602,9 +601,26 @@ export class ClaudeAcpAgent implements Agent {
case "task_notification":
case "task_progress":
case "elicitation_complete":
case "api_retry":
// Todo: process via status api: https://docs.claude.com/en/docs/claude-code/hooks#hook-output
break;
case "api_retry": {
// Forward API retry events via extNotification so clients can observe
// transient failures including HTTP status code and typed error category.
const retryMsg = message as any;
this.logger.error(
`API retry: attempt=${retryMsg.attempt}/${retryMsg.max_retries}, ` +
`httpStatus=${retryMsg.error_status}, error=${retryMsg.error}, ` +
`delay=${retryMsg.retry_delay_ms}ms`,
);
await this.client.extNotification("_claude/api-retry", {
sessionId: params.sessionId,
httpStatus: retryMsg.error_status ?? null,
errorType: retryMsg.error ?? "unknown",
attempt: retryMsg.attempt ?? 0,
maxRetries: retryMsg.max_retries ?? 0,
retryDelayMs: retryMsg.retry_delay_ms ?? 0,
});
break;
}
default:
unreachable(message, this.logger);
break;
Expand Down Expand Up @@ -835,11 +851,57 @@ export class ClaudeAcpAgent implements Agent {
}
break;
}
case "tool_progress":
case "tool_use_summary":
case "tool_progress": {
// Forward tool execution progress via extNotification so clients can
// show elapsed time for long-running tools without polluting tool output.
const toolUseId = "tool_use_id" in message ? (message as any).tool_use_id : undefined;
if (toolUseId) {
await this.client.extNotification("_claude/tool-progress", {
sessionId: params.sessionId,
toolUseId,
toolName: (message as any).tool_name ?? null,
elapsedTimeSeconds: (message as any).elapsed_time_seconds ?? 0,
});
}
break;
}
case "tool_use_summary": {
// Forward collapsed tool-use summaries via extNotification so clients
// can display a high-level overview of tool activity.
const summary = "summary" in message ? (message as any).summary : undefined;
if (summary) {
await this.client.extNotification("_claude/tool-use-summary", {
sessionId: params.sessionId,
summary,
precedingToolUseIds:
"preceding_tool_use_ids" in message
? (message as any).preceding_tool_use_ids ?? []
: [],
});
}
break;
}
case "rate_limit_event": {
// Forward rate limit info via extNotification so clients can detect
// approaching limits and rejections without parsing error message strings.
const info = "rate_limit_info" in message ? (message as any).rate_limit_info : undefined;
if (info) {
await this.client.extNotification("_claude/rate-limit", {
sessionId: params.sessionId,
status: info.status ?? "unknown",
resetsAt: info.resetsAt ?? null,
rateLimitType: info.rateLimitType ?? null,
utilization: info.utilization ?? null,
overageStatus: info.overageStatus ?? null,
overageDisabledReason: info.overageDisabledReason ?? null,
isUsingOverage: info.isUsingOverage ?? false,
surpassedThreshold: info.surpassedThreshold ?? null,
});
}
break;
}
case "auth_status":
case "prompt_suggestion":
case "rate_limit_event":
break;
default:
unreachable(message);
Expand Down
4 changes: 4 additions & 0 deletions src/tests/acp-agent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1337,6 +1337,7 @@ describe("stop reason propagation", () => {
availableModels: [],
},
settingsManager: { dispose: vi.fn() } as any,

accumulatedUsage: {
inputTokens: 0,
outputTokens: 0,
Expand Down Expand Up @@ -1476,6 +1477,7 @@ describe("stop reason propagation", () => {
availableModels: [],
},
settingsManager: { dispose: vi.fn() } as any,

accumulatedUsage: {
inputTokens: 0,
outputTokens: 0,
Expand Down Expand Up @@ -1549,6 +1551,7 @@ describe("session/close", () => {
availableModels: [],
},
settingsManager: { dispose: vi.fn() } as any,

accumulatedUsage: {
inputTokens: 0,
outputTokens: 0,
Expand Down Expand Up @@ -1719,6 +1722,7 @@ describe("usage_update computation", () => {
availableModels: [],
},
settingsManager: {} as any,

accumulatedUsage: {
inputTokens: 0,
outputTokens: 0,
Expand Down