@agentclientprotocol/claude-agent-acp 0.52.0 → 0.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/acp-agent.d.ts +111 -3
- package/dist/acp-agent.d.ts.map +1 -1
- package/dist/acp-agent.js +348 -74
- package/dist/elicitation.d.ts.map +1 -1
- package/dist/index.js +8 -5
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +17 -0
- package/package.json +8 -8
package/dist/acp-agent.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AuthenticateRequest, CancelNotification, ClientCapabilities, CompleteElicitationNotification, CreateElicitationRequest, CreateElicitationResponse, ForkSessionRequest, ForkSessionResponse, InitializeRequest, InitializeResponse, ListSessionsRequest, ListSessionsResponse, LoadSessionRequest, LoadSessionResponse, NewSessionRequest, NewSessionResponse, PromptRequest, PromptResponse, ReadTextFileRequest, ReadTextFileResponse, RequestPermissionRequest, RequestPermissionResponse, ResumeSessionRequest, ResumeSessionResponse, SessionConfigOption, SessionModeState, SessionNotification, SetSessionConfigOptionRequest, SetSessionConfigOptionResponse, SetSessionModeRequest, SetSessionModeResponse, CloseSessionRequest, CloseSessionResponse, DeleteSessionRequest, DeleteSessionResponse, WriteTextFileRequest, WriteTextFileResponse } from "@agentclientprotocol/sdk";
|
|
2
|
-
import { AgentInfo, CanUseTool, ModelInfo, Options, PermissionMode, PermissionUpdate, Query, SDKMessageOrigin, SDKPartialAssistantMessage, SDKUserMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
1
|
+
import { AuthenticateRequest, CancelNotification, ClientCapabilities, CompleteElicitationNotification, CreateElicitationRequest, CreateElicitationResponse, ForkSessionRequest, ForkSessionResponse, InitializeRequest, InitializeResponse, ListSessionsRequest, ListSessionsResponse, LoadSessionRequest, LoadSessionResponse, LogoutRequest, NewSessionRequest, NewSessionResponse, PromptRequest, PromptResponse, ReadTextFileRequest, ReadTextFileResponse, RequestPermissionRequest, RequestPermissionResponse, ResumeSessionRequest, ResumeSessionResponse, SessionConfigOption, SessionModeState, SessionNotification, SetSessionConfigOptionRequest, SetSessionConfigOptionResponse, SetSessionModeRequest, SetSessionModeResponse, CloseSessionRequest, CloseSessionResponse, DeleteSessionRequest, DeleteSessionResponse, WriteTextFileRequest, WriteTextFileResponse } from "@agentclientprotocol/sdk";
|
|
2
|
+
import { AgentInfo, CanUseTool, FastModeState, ModelInfo, Options, PermissionMode, PermissionUpdate, Query, SDKMessageOrigin, SDKPartialAssistantMessage, SDKUserMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
3
3
|
import { ContentBlockParam } from "@anthropic-ai/sdk/resources";
|
|
4
4
|
import { BetaContentBlock, BetaRawContentBlockDelta } from "@anthropic-ai/sdk/resources/beta.mjs";
|
|
5
5
|
import { SettingsManager } from "./settings.js";
|
|
@@ -97,6 +97,10 @@ type Session = {
|
|
|
97
97
|
/** The currently selected main-thread agent name, or "default" for the
|
|
98
98
|
* standard Claude Code agent (no `agent` flag applied). */
|
|
99
99
|
currentAgent: string;
|
|
100
|
+
/** Whether Fast mode is currently enabled for this session. Tracked as the
|
|
101
|
+
* user's intent so it persists across model switches; the Fast mode config
|
|
102
|
+
* option is only surfaced while the selected model supports it. */
|
|
103
|
+
fastModeEnabled: boolean;
|
|
100
104
|
abortController: AbortController;
|
|
101
105
|
/** Signal the consumer races `query.next()` against. Aborted by cancel()
|
|
102
106
|
* (after a grace period) to force the active turn to settle "cancelled" when
|
|
@@ -131,6 +135,14 @@ type Session = {
|
|
|
131
135
|
* `tool_result` time so a long-running session doesn't accumulate every
|
|
132
136
|
* tool call for its whole lifetime. */
|
|
133
137
|
toolUseCache: ToolUseCache;
|
|
138
|
+
/** Tracks which tool_use ids we've already emitted a `tool_call` for, so the
|
|
139
|
+
* second source to encounter a tool call sends a `tool_call_update` instead
|
|
140
|
+
* of a duplicate `tool_call`. The SDK can invoke `canUseTool` (→ a permission
|
|
141
|
+
* request, which emits the tool_call eagerly so the client has it before
|
|
142
|
+
* being asked to approve it) either before or after the assistant message's
|
|
143
|
+
* tool_use block streams; this set makes the two paths converge regardless of
|
|
144
|
+
* order. Pruned at `tool_result` time alongside `toolUseCache`. */
|
|
145
|
+
emittedToolCalls: Set<string>;
|
|
134
146
|
/** Maps the ACP `messageId` we expose to clients (see `messageIdForGrouping`)
|
|
135
147
|
* to the SDK message uuid that the Agent SDK's rewind/resume APIs key on
|
|
136
148
|
* (`Query.rewindFiles` takes a user-message uuid; `resumeSessionAt` takes an
|
|
@@ -298,6 +310,7 @@ export declare class ClaudeAcpAgent {
|
|
|
298
310
|
* the title is best-effort and another turn will retry. */
|
|
299
311
|
private maybeUpdateSessionTitle;
|
|
300
312
|
authenticate(_params: AuthenticateRequest): Promise<void>;
|
|
313
|
+
logout(_params: LogoutRequest): Promise<void>;
|
|
301
314
|
prompt(params: PromptRequest): Promise<PromptResponse>;
|
|
302
315
|
/** Lazily start the per-session consumer that drains the SDK query stream for
|
|
303
316
|
* the session's whole life. Idempotent: only the first `prompt()` starts it. */
|
|
@@ -350,6 +363,14 @@ export declare class ClaudeAcpAgent {
|
|
|
350
363
|
* "Tool use aborted" the callers already expect, so a cancelled dialog no
|
|
351
364
|
* longer leaves the `await` hanging. */
|
|
352
365
|
private requestPermissionFromClient;
|
|
366
|
+
/** Emit the `tool_call` a permission request references if it hasn't been sent
|
|
367
|
+
* yet, so the client has the tool call before being asked to approve it. The
|
|
368
|
+
* matching streamed tool_use chunk later refines it with a `tool_call_update`
|
|
369
|
+
* instead of emitting a duplicate (see `emittedToolCalls`). Built via the same
|
|
370
|
+
* `toolCallNotification` helper as the streamed path so the two are identical.
|
|
371
|
+
* Tools the stream renders as a plan (TodoWrite) or suppresses (Task*) are
|
|
372
|
+
* skipped so a permission prompt for them never surfaces a stray tool_call. */
|
|
373
|
+
private ensureToolCallEmitted;
|
|
353
374
|
canUseTool(sessionId: string): CanUseTool;
|
|
354
375
|
/**
|
|
355
376
|
* Handle elicitation requests that originate from MCP servers by forwarding
|
|
@@ -366,6 +387,33 @@ export declare class ClaudeAcpAgent {
|
|
|
366
387
|
private sendAvailableCommandsUpdate;
|
|
367
388
|
private updateConfigOption;
|
|
368
389
|
private applyConfigOptionValue;
|
|
390
|
+
/** Replace the Fast mode option in `session.configOptions` so it reflects
|
|
391
|
+
* `enabled` (and the client's current boolean-capability). A no-op when the
|
|
392
|
+
* option isn't present, so callers must confirm the current model surfaces
|
|
393
|
+
* it first. */
|
|
394
|
+
private refreshFastModeOption;
|
|
395
|
+
/** Toggle Fast mode for a session: push the SDK flag, record the user's
|
|
396
|
+
* intent, and refresh the Fast mode config option in place. Only reached
|
|
397
|
+
* once the option exists (i.e. the current model supports fast mode), so the
|
|
398
|
+
* option is guaranteed to be present in `configOptions`. */
|
|
399
|
+
private applyFastMode;
|
|
400
|
+
/** Reconcile the session's Fast mode toggle with an SDK-reported
|
|
401
|
+
* `fast_mode_state` (delivered on `system`/init and on user-turn `result`s).
|
|
402
|
+
* The SDK can flip fast mode independently of the user — e.g. back to `on`
|
|
403
|
+
* once a rate-limit `cooldown` clears — so we mirror definitive on/off
|
|
404
|
+
* changes into the config option and notify the client.
|
|
405
|
+
*
|
|
406
|
+
* Guards, in order:
|
|
407
|
+
* - absent state: nothing to reconcile.
|
|
408
|
+
* - no Fast mode option: the current model doesn't support fast mode, so the
|
|
409
|
+
* reported state reflects capability, not the user's intent. Leave the
|
|
410
|
+
* retained setting untouched so it's correct when a supporting model is
|
|
411
|
+
* reselected (the source of the earlier intent-clobber bug was mutating it
|
|
412
|
+
* here).
|
|
413
|
+
* - `cooldown`: a transient suspension of an already-enabled fast mode.
|
|
414
|
+
* Leave the toggle as-is rather than flapping it — and never let a stray
|
|
415
|
+
* cooldown spuriously enable a toggle the user has off. */
|
|
416
|
+
private syncFastModeState;
|
|
369
417
|
private getOrCreateSession;
|
|
370
418
|
/**
|
|
371
419
|
* Ensures the requested `cwd` is an absolute path that points at an existing
|
|
@@ -383,7 +431,65 @@ export declare const DEFAULT_AGENT_ID = "default";
|
|
|
383
431
|
* list if discovery fails so a flaky control request never blocks session
|
|
384
432
|
* creation. */
|
|
385
433
|
export declare function discoverCustomAgents(q: Query): Promise<AgentInfo[]>;
|
|
386
|
-
|
|
434
|
+
/** Stable ids for the session config options surfaced via `configOptions`.
|
|
435
|
+
* Centralized so the option declarations in `buildConfigOptions` and the
|
|
436
|
+
* handlers in `setSessionConfigOption`/`applyConfigOptionValue` reference the
|
|
437
|
+
* same identifiers and can't drift apart. */
|
|
438
|
+
export declare const MODE_CONFIG_ID = "mode";
|
|
439
|
+
export declare const MODEL_CONFIG_ID = "model";
|
|
440
|
+
export declare const EFFORT_CONFIG_ID = "effort";
|
|
441
|
+
export declare const AGENT_CONFIG_ID = "agent";
|
|
442
|
+
export declare const FAST_MODE_CONFIG_ID = "fast";
|
|
443
|
+
/** Select-fallback values used when the client has not opted into boolean
|
|
444
|
+
* config options (see {@link createFastModeConfigOption}). */
|
|
445
|
+
export declare const FAST_MODE_ON = "on";
|
|
446
|
+
export declare const FAST_MODE_OFF = "off";
|
|
447
|
+
/** Map the SDK's tri-state `fast_mode_state` onto the boolean config toggle.
|
|
448
|
+
* `cooldown` (fast mode temporarily suspended after a rate limit, per the SDK
|
|
449
|
+
* docs) keeps the toggle on so it reflects the user's intent — only an
|
|
450
|
+
* explicit `off` clears it. */
|
|
451
|
+
export declare function fastModeStateEnabled(state: FastModeState): boolean;
|
|
452
|
+
/** Whether the Client advertised support for boolean session config options
|
|
453
|
+
* (`session.configOptions.boolean`). Agents MUST only send `type: "boolean"`
|
|
454
|
+
* config options to Clients that opt in; otherwise we fall back to a `select`.
|
|
455
|
+
* See https://agentclientprotocol.com/rfds/boolean-config-option. */
|
|
456
|
+
export declare function clientSupportsBooleanConfigOptions(clientCapabilities?: ClientCapabilities | null): boolean;
|
|
457
|
+
/** Build the Fast mode config option. When the Client supports boolean config
|
|
458
|
+
* options we expose a native `type: "boolean"` toggle; otherwise we degrade to
|
|
459
|
+
* a two-value `select` ("on"/"off") so older Clients still get a usable
|
|
460
|
+
* control. */
|
|
461
|
+
export declare function createFastModeConfigOption(enabled: boolean, useBooleanOption: boolean): SessionConfigOption;
|
|
462
|
+
/** Resolve the requested Fast mode value from a `session/set_config_option`
|
|
463
|
+
* request. Accepts a native boolean (boolean-capable Clients) or the
|
|
464
|
+
* "on"/"off" select-fallback strings. */
|
|
465
|
+
export declare function resolveFastModeEnabled(params: SetSessionConfigOptionRequest): boolean;
|
|
466
|
+
/** Per-model Fast mode state threaded into {@link buildConfigOptions}. The
|
|
467
|
+
* option is only surfaced when the current model `supported`s fast mode. */
|
|
468
|
+
export type FastModeOptionState = {
|
|
469
|
+
supported: boolean;
|
|
470
|
+
enabled: boolean;
|
|
471
|
+
/** Whether the Client opted into boolean config options. */
|
|
472
|
+
useBooleanOption: boolean;
|
|
473
|
+
};
|
|
474
|
+
export declare function buildConfigOptions(modes: SessionModeState, models: SessionModelState, modelInfos: ModelInfo[], currentEffortLevel?: string, agents?: AgentInfo[], currentAgent?: string, fastMode?: FastModeOptionState): SessionConfigOption[];
|
|
475
|
+
export declare function resolveModelPreference(models: ModelInfo[], preference: string): ModelInfo | null;
|
|
476
|
+
/**
|
|
477
|
+
* Restrict the SDK's model list to the user's `availableModels` allowlist
|
|
478
|
+
* (already merged-and-deduped across settings sources by `SettingsManager`).
|
|
479
|
+
* The user's exact entries become the model IDs surfaced via configOptions
|
|
480
|
+
* and passed to `setModel`, which prevents Claude Code from silently
|
|
481
|
+
* substituting a date-pinned variant (e.g. `haiku` →
|
|
482
|
+
* `claude-haiku-4-5-20251001`) that the user may not have access to.
|
|
483
|
+
*
|
|
484
|
+
* Display info and capability flags are copied from the closest SDK match so
|
|
485
|
+
* the UI still renders sensible names and effort levels.
|
|
486
|
+
*
|
|
487
|
+
* Semantics from https://code.claude.com/docs/en/model-config#restrict-model-selection:
|
|
488
|
+
* - `undefined` is handled by the caller (no allowlist applied).
|
|
489
|
+
* - The Default option is unaffected by `availableModels` — it always remains
|
|
490
|
+
* available, even when the allowlist is `[]`.
|
|
491
|
+
*/
|
|
492
|
+
export declare function applyAvailableModelsAllowlist(sdkModels: ModelInfo[], allowlist: string[]): ModelInfo[];
|
|
387
493
|
export declare function promptToClaude(prompt: PromptRequest): SDKUserMessage;
|
|
388
494
|
/**
|
|
389
495
|
* Resolves the ACP `messageId` for a Claude SDK message (live) or a persisted
|
|
@@ -411,12 +517,14 @@ export declare function toAcpNotifications(content: string | ContentBlockParam[]
|
|
|
411
517
|
parentToolUseId?: string | null;
|
|
412
518
|
cwd?: string;
|
|
413
519
|
taskState?: TaskState;
|
|
520
|
+
emittedToolCalls?: Set<string>;
|
|
414
521
|
messageId?: string;
|
|
415
522
|
}): SessionNotification[];
|
|
416
523
|
export declare function streamEventToAcpNotifications(message: SDKPartialAssistantMessage, sessionId: string, toolUseCache: ToolUseCache, client: AcpClient, logger: Logger, options?: {
|
|
417
524
|
clientCapabilities?: ClientCapabilities;
|
|
418
525
|
cwd?: string;
|
|
419
526
|
taskState?: TaskState;
|
|
527
|
+
emittedToolCalls?: Set<string>;
|
|
420
528
|
messageId?: string;
|
|
421
529
|
}): SessionNotification[];
|
|
422
530
|
/** Run a `session/prompt` while honoring `$/cancel_request` for it. ACP clients
|
package/dist/acp-agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"acp-agent.d.ts","sourceRoot":"","sources":["../src/acp-agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,mBAAmB,EAGnB,kBAAkB,EAClB,kBAAkB,EAClB,+BAA+B,EAC/B,wBAAwB,EACxB,yBAAyB,EACzB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,
|
|
1
|
+
{"version":3,"file":"acp-agent.d.ts","sourceRoot":"","sources":["../src/acp-agent.ts"],"names":[],"mappings":"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"}
|
package/dist/acp-agent.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { agent as acpAgent, methods, ndJsonStream, RequestError, } from "@agentclientprotocol/sdk";
|
|
2
2
|
import { deleteSession, getSessionInfo, getSessionMessages, listSessions, query, } from "@anthropic-ai/claude-agent-sdk";
|
|
3
|
+
import { execFile } from "node:child_process";
|
|
3
4
|
import { randomUUID } from "node:crypto";
|
|
4
5
|
import * as fs from "node:fs/promises";
|
|
5
6
|
import * as os from "node:os";
|
|
6
7
|
import * as path from "node:path";
|
|
8
|
+
import { promisify } from "node:util";
|
|
7
9
|
import packageJson from "../package.json" with { type: "json" };
|
|
8
10
|
import { applyAskElicitationResponse, askUserQuestionsToCreateRequest, createElicitationResponseToElicitResult, extractAskUserQuestions, mcpElicitationToCreateRequest, } from "./elicitation.js";
|
|
9
11
|
import { SettingsManager } from "./settings.js";
|
|
10
12
|
import { applyTaskCreate, applyTaskUpdate, createPostToolUseHook, createTaskHook, parseTaskCreateOutput, planEntries, registerHookCallback, taskStateToPlanEntries, toolInfoFromToolUse, toolUpdateFromDiffToolResponse, toolUpdateFromToolResult, } from "./tools.js";
|
|
11
13
|
import { nodeToWebReadable, nodeToWebWritable, Pushable, unreachable } from "./utils.js";
|
|
12
14
|
export const CLAUDE_CONFIG_DIR = process.env.CLAUDE_CONFIG_DIR ?? path.join(os.homedir(), ".claude");
|
|
15
|
+
const execFileAsync = promisify(execFile);
|
|
13
16
|
const MAX_TITLE_LENGTH = 256;
|
|
14
17
|
function sanitizeTitle(text) {
|
|
15
18
|
// Replace newlines and collapse whitespace
|
|
@@ -411,6 +414,9 @@ export class ClaudeAcpAgent {
|
|
|
411
414
|
http: true,
|
|
412
415
|
sse: true,
|
|
413
416
|
},
|
|
417
|
+
auth: {
|
|
418
|
+
logout: {},
|
|
419
|
+
},
|
|
414
420
|
loadSession: true,
|
|
415
421
|
sessionCapabilities: {
|
|
416
422
|
additionalDirectories: {},
|
|
@@ -534,6 +540,25 @@ export class ClaudeAcpAgent {
|
|
|
534
540
|
}
|
|
535
541
|
throw new Error("Method not implemented.");
|
|
536
542
|
}
|
|
543
|
+
async logout(_params) {
|
|
544
|
+
// Clear in-memory gateway credentials supplied via `authenticate`. The
|
|
545
|
+
// gateway method never touches the on-disk credential store, so dropping
|
|
546
|
+
// this reference is the whole logout for that path.
|
|
547
|
+
this.gatewayAuthRequest = undefined;
|
|
548
|
+
// For the Claude/Console login methods the credentials live in the native
|
|
549
|
+
// CLI's store (keychain or config dir), which only the binary can clear.
|
|
550
|
+
// `claude auth logout` is non-interactive and idempotent.
|
|
551
|
+
const cliPath = await claudeCliPath();
|
|
552
|
+
try {
|
|
553
|
+
await execFileAsync(cliPath, ["auth", "logout"]);
|
|
554
|
+
}
|
|
555
|
+
catch (error) {
|
|
556
|
+
const stderr = typeof error === "object" && error && "stderr" in error
|
|
557
|
+
? String(error.stderr).trim()
|
|
558
|
+
: undefined;
|
|
559
|
+
throw RequestError.internalError({ stderr: stderr || undefined }, `claude auth logout failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
537
562
|
async prompt(params) {
|
|
538
563
|
const session = this.sessions[params.sessionId];
|
|
539
564
|
if (!session) {
|
|
@@ -827,6 +852,10 @@ export class ClaudeAcpAgent {
|
|
|
827
852
|
case "system":
|
|
828
853
|
switch (message.subtype) {
|
|
829
854
|
case "init":
|
|
855
|
+
// A fresh `system`/init (e.g. after reinitialize) can carry an
|
|
856
|
+
// updated Fast mode state; reconcile it with what we seeded at
|
|
857
|
+
// session creation.
|
|
858
|
+
await this.syncFastModeState(message.session_id, session, message.fast_mode_state);
|
|
830
859
|
break;
|
|
831
860
|
case "status": {
|
|
832
861
|
if (message.status === "compacting") {
|
|
@@ -1081,6 +1110,7 @@ export class ClaudeAcpAgent {
|
|
|
1081
1110
|
case "api_retry":
|
|
1082
1111
|
case "thinking_tokens":
|
|
1083
1112
|
case "model_refusal_fallback":
|
|
1113
|
+
case "model_refusal_no_fallback":
|
|
1084
1114
|
// Todo: process via status api: https://docs.claude.com/en/docs/claude-code/hooks#hook-output
|
|
1085
1115
|
break;
|
|
1086
1116
|
default:
|
|
@@ -1094,6 +1124,13 @@ export class ClaudeAcpAgent {
|
|
|
1094
1124
|
// They should not influence the user-turn lifecycle (stop reason,
|
|
1095
1125
|
// slash-command output forwarding) but their cost is real.
|
|
1096
1126
|
const isTaskNotification = message.origin?.kind === "task-notification";
|
|
1127
|
+
// Reconcile the Fast mode toggle with the SDK's reported state.
|
|
1128
|
+
// Gated to user-driven turns like every other side effect below; a
|
|
1129
|
+
// background followup's state lands on the next user turn's result.
|
|
1130
|
+
// Runs even when the turn errors or was cancelled.
|
|
1131
|
+
if (!isTaskNotification) {
|
|
1132
|
+
await this.syncFastModeState(params.sessionId, session, message.fast_mode_state);
|
|
1133
|
+
}
|
|
1097
1134
|
// A user-turn result needs an active turn so its stop reason is
|
|
1098
1135
|
// attributed and the turn settles at idle. Local-only commands carry
|
|
1099
1136
|
// no user-message echo to promote them, so do it here from the head.
|
|
@@ -1342,6 +1379,7 @@ export class ClaudeAcpAgent {
|
|
|
1342
1379
|
clientCapabilities: this.clientCapabilities,
|
|
1343
1380
|
cwd: session.cwd,
|
|
1344
1381
|
taskState: session.taskState,
|
|
1382
|
+
emittedToolCalls: session.emittedToolCalls,
|
|
1345
1383
|
messageId: currentStreamMessageId,
|
|
1346
1384
|
})) {
|
|
1347
1385
|
await this.client.sessionUpdate(notification);
|
|
@@ -1537,6 +1575,7 @@ export class ClaudeAcpAgent {
|
|
|
1537
1575
|
parentToolUseId: message.parent_tool_use_id,
|
|
1538
1576
|
cwd: session.cwd,
|
|
1539
1577
|
taskState: session.taskState,
|
|
1578
|
+
emittedToolCalls: session.emittedToolCalls,
|
|
1540
1579
|
messageId: messageIdForGrouping(message),
|
|
1541
1580
|
})) {
|
|
1542
1581
|
await this.client.sessionUpdate(notification);
|
|
@@ -1761,7 +1800,7 @@ export class ClaudeAcpAgent {
|
|
|
1761
1800
|
throw RequestError.internalError(undefined, SESSION_ENDED_MESSAGE);
|
|
1762
1801
|
}
|
|
1763
1802
|
await this.applySessionMode(params.sessionId, params.modeId);
|
|
1764
|
-
await this.updateConfigOption(params.sessionId,
|
|
1803
|
+
await this.updateConfigOption(params.sessionId, MODE_CONFIG_ID, params.modeId);
|
|
1765
1804
|
return {};
|
|
1766
1805
|
}
|
|
1767
1806
|
async setSessionConfigOption(params) {
|
|
@@ -1776,13 +1815,20 @@ export class ClaudeAcpAgent {
|
|
|
1776
1815
|
if (session.queryClosed) {
|
|
1777
1816
|
throw RequestError.internalError(undefined, SESSION_ENDED_MESSAGE);
|
|
1778
1817
|
}
|
|
1779
|
-
if (typeof params.value !== "string") {
|
|
1780
|
-
throw new Error(`Invalid value for config option ${params.configId}: ${params.value}`);
|
|
1781
|
-
}
|
|
1782
1818
|
const option = session.configOptions.find((o) => o.id === params.configId);
|
|
1783
1819
|
if (!option) {
|
|
1784
1820
|
throw new Error(`Unknown config option: ${params.configId}`);
|
|
1785
1821
|
}
|
|
1822
|
+
// Fast mode carries a boolean value (for Clients that opted into boolean
|
|
1823
|
+
// config options) or the "on"/"off" select fallback, so it bypasses the
|
|
1824
|
+
// string-only validation the select-style options below rely on.
|
|
1825
|
+
if (params.configId === FAST_MODE_CONFIG_ID) {
|
|
1826
|
+
await this.applyFastMode(session, resolveFastModeEnabled(params));
|
|
1827
|
+
return { configOptions: session.configOptions };
|
|
1828
|
+
}
|
|
1829
|
+
if (typeof params.value !== "string") {
|
|
1830
|
+
throw new Error(`Invalid value for config option ${params.configId}: ${params.value}`);
|
|
1831
|
+
}
|
|
1786
1832
|
const allValues = "options" in option && Array.isArray(option.options)
|
|
1787
1833
|
? option.options.flatMap((o) => ("options" in o ? o.options : [o]))
|
|
1788
1834
|
: [];
|
|
@@ -1790,7 +1836,7 @@ export class ClaudeAcpAgent {
|
|
|
1790
1836
|
// For model options, fall back to resolveModelPreference when the exact
|
|
1791
1837
|
// value doesn't match. This lets callers use human-friendly aliases like
|
|
1792
1838
|
// "opus" or "sonnet" instead of full model IDs like "claude-opus-4-6".
|
|
1793
|
-
if (!validValue && params.configId ===
|
|
1839
|
+
if (!validValue && params.configId === MODEL_CONFIG_ID) {
|
|
1794
1840
|
const modelInfos = allValues.map((o) => ({
|
|
1795
1841
|
value: o.value,
|
|
1796
1842
|
displayName: o.name,
|
|
@@ -1807,7 +1853,7 @@ export class ClaudeAcpAgent {
|
|
|
1807
1853
|
// Use the canonical option value so downstream code always receives the
|
|
1808
1854
|
// model ID rather than the caller-supplied alias.
|
|
1809
1855
|
const resolvedValue = validValue.value;
|
|
1810
|
-
if (params.configId ===
|
|
1856
|
+
if (params.configId === MODE_CONFIG_ID) {
|
|
1811
1857
|
await this.applySessionMode(params.sessionId, resolvedValue);
|
|
1812
1858
|
await this.client.sessionUpdate({
|
|
1813
1859
|
sessionId: params.sessionId,
|
|
@@ -1817,7 +1863,7 @@ export class ClaudeAcpAgent {
|
|
|
1817
1863
|
},
|
|
1818
1864
|
});
|
|
1819
1865
|
}
|
|
1820
|
-
else if (params.configId ===
|
|
1866
|
+
else if (params.configId === MODEL_CONFIG_ID) {
|
|
1821
1867
|
await this.sessions[params.sessionId].query.setModel(resolvedValue);
|
|
1822
1868
|
}
|
|
1823
1869
|
// Effort SDK sync is handled inside applyConfigOptionValue so that direct
|
|
@@ -1912,7 +1958,14 @@ export class ClaudeAcpAgent {
|
|
|
1912
1958
|
* outcome or a `requestCancelled` rejection). Either way we surface the same
|
|
1913
1959
|
* "Tool use aborted" the callers already expect, so a cancelled dialog no
|
|
1914
1960
|
* longer leaves the `await` hanging. */
|
|
1915
|
-
async requestPermissionFromClient(params, signal) {
|
|
1961
|
+
async requestPermissionFromClient(params, toolName, signal) {
|
|
1962
|
+
// The SDK may invoke `canUseTool` (and therefore this permission request)
|
|
1963
|
+
// before the assistant message's tool_use block streams to us. Some ACP clients
|
|
1964
|
+
// expect the `tool_call` a permission request references to already exist,
|
|
1965
|
+
// so emit it now if it hasn't been sent yet. The streamed tool_use chunk
|
|
1966
|
+
// later refines it with a `tool_call_update` rather than emitting a
|
|
1967
|
+
// duplicate (see `emittedToolCalls` in `toAcpNotifications`).
|
|
1968
|
+
await this.ensureToolCallEmitted(params.sessionId, toolName, params.toolCall.toolCallId, params.toolCall.rawInput);
|
|
1916
1969
|
try {
|
|
1917
1970
|
return await this.client.requestPermission(params, signal);
|
|
1918
1971
|
}
|
|
@@ -1923,6 +1976,28 @@ export class ClaudeAcpAgent {
|
|
|
1923
1976
|
throw error;
|
|
1924
1977
|
}
|
|
1925
1978
|
}
|
|
1979
|
+
/** Emit the `tool_call` a permission request references if it hasn't been sent
|
|
1980
|
+
* yet, so the client has the tool call before being asked to approve it. The
|
|
1981
|
+
* matching streamed tool_use chunk later refines it with a `tool_call_update`
|
|
1982
|
+
* instead of emitting a duplicate (see `emittedToolCalls`). Built via the same
|
|
1983
|
+
* `toolCallNotification` helper as the streamed path so the two are identical.
|
|
1984
|
+
* Tools the stream renders as a plan (TodoWrite) or suppresses (Task*) are
|
|
1985
|
+
* skipped so a permission prompt for them never surfaces a stray tool_call. */
|
|
1986
|
+
async ensureToolCallEmitted(sessionId, toolName, toolCallId, toolInput) {
|
|
1987
|
+
const session = this.sessions[sessionId];
|
|
1988
|
+
if (!session || !shouldEmitToolCall(toolName)) {
|
|
1989
|
+
return;
|
|
1990
|
+
}
|
|
1991
|
+
if (session.emittedToolCalls.has(toolCallId)) {
|
|
1992
|
+
return;
|
|
1993
|
+
}
|
|
1994
|
+
session.emittedToolCalls.add(toolCallId);
|
|
1995
|
+
const supportsTerminalOutput = this.clientCapabilities?._meta?.["terminal_output"] === true;
|
|
1996
|
+
await this.client.sessionUpdate({
|
|
1997
|
+
sessionId,
|
|
1998
|
+
update: toolCallNotification({ id: toolCallId, name: toolName, input: toolInput }, toolInput, supportsTerminalOutput, session.cwd),
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
1926
2001
|
canUseTool(sessionId) {
|
|
1927
2002
|
return async (toolName, toolInput, { signal, suggestions, toolUseID }) => {
|
|
1928
2003
|
const alwaysAllowLabel = describeAlwaysAllow(suggestions, toolName);
|
|
@@ -1939,6 +2014,9 @@ export class ClaudeAcpAgent {
|
|
|
1939
2014
|
// than the interactive dialog). Present it as an ACP form elicitation and
|
|
1940
2015
|
// feed the answers back as updatedInput for the tool's own call() to read.
|
|
1941
2016
|
if (toolName === "AskUserQuestion" && this.clientCapabilities?.elicitation?.form) {
|
|
2017
|
+
// Like permission requests, the elicitation references this toolUseID, so
|
|
2018
|
+
// make sure the tool_call has surfaced to the client before we send it.
|
|
2019
|
+
await this.ensureToolCallEmitted(sessionId, toolName, toolUseID, toolInput);
|
|
1942
2020
|
return this.handleAskUserQuestion(sessionId, toolInput, toolUseID, signal);
|
|
1943
2021
|
}
|
|
1944
2022
|
if (toolName === "ExitPlanMode") {
|
|
@@ -1973,7 +2051,7 @@ export class ClaudeAcpAgent {
|
|
|
1973
2051
|
rawInput: toolInput,
|
|
1974
2052
|
...toolInfoFromToolUse({ name: toolName, input: toolInput, id: toolUseID }, supportsTerminalOutput, session?.cwd),
|
|
1975
2053
|
},
|
|
1976
|
-
}, signal);
|
|
2054
|
+
}, toolName, signal);
|
|
1977
2055
|
if (signal.aborted || response.outcome?.outcome === "cancelled") {
|
|
1978
2056
|
throw new Error("Tool use aborted");
|
|
1979
2057
|
}
|
|
@@ -1991,7 +2069,7 @@ export class ClaudeAcpAgent {
|
|
|
1991
2069
|
currentModeId: selectedMode,
|
|
1992
2070
|
},
|
|
1993
2071
|
});
|
|
1994
|
-
await this.updateConfigOption(sessionId,
|
|
2072
|
+
await this.updateConfigOption(sessionId, MODE_CONFIG_ID, selectedMode);
|
|
1995
2073
|
return {
|
|
1996
2074
|
behavior: "allow",
|
|
1997
2075
|
updatedInput: toolInput,
|
|
@@ -2032,7 +2110,7 @@ export class ClaudeAcpAgent {
|
|
|
2032
2110
|
rawInput: toolInput,
|
|
2033
2111
|
...toolInfoFromToolUse({ name: toolName, input: toolInput, id: toolUseID }, supportsTerminalOutput, session?.cwd),
|
|
2034
2112
|
},
|
|
2035
|
-
}, signal);
|
|
2113
|
+
}, toolName, signal);
|
|
2036
2114
|
if (signal.aborted || response.outcome?.outcome === "cancelled") {
|
|
2037
2115
|
throw new Error("Tool use aborted");
|
|
2038
2116
|
}
|
|
@@ -2159,11 +2237,11 @@ export class ClaudeAcpAgent {
|
|
|
2159
2237
|
});
|
|
2160
2238
|
}
|
|
2161
2239
|
async applyConfigOptionValue(sessionId, session, configId, value) {
|
|
2162
|
-
if (configId ===
|
|
2240
|
+
if (configId === MODE_CONFIG_ID) {
|
|
2163
2241
|
session.modes = { ...session.modes, currentModeId: value };
|
|
2164
2242
|
session.configOptions = session.configOptions.map((o) => o.id === configId && typeof o.currentValue === "string" ? { ...o, currentValue: value } : o);
|
|
2165
2243
|
}
|
|
2166
|
-
else if (configId ===
|
|
2244
|
+
else if (configId === MODEL_CONFIG_ID) {
|
|
2167
2245
|
// `ModelInfo.supportsAutoMode` is the canonical SDK signal for clamping
|
|
2168
2246
|
// modes below; its `displayName`/`description` also let us infer the
|
|
2169
2247
|
// context window for semantic aliases (e.g. `default`) whose ID alone
|
|
@@ -2206,11 +2284,18 @@ export class ClaudeAcpAgent {
|
|
|
2206
2284
|
session.modes = { ...session.modes, availableModes: newAvailableModes };
|
|
2207
2285
|
}
|
|
2208
2286
|
// Rebuild config options since effort levels depend on the selected model
|
|
2209
|
-
const effortOpt = session.configOptions.find((o) => o.id ===
|
|
2287
|
+
const effortOpt = session.configOptions.find((o) => o.id === EFFORT_CONFIG_ID);
|
|
2210
2288
|
const currentEffort = typeof effortOpt?.currentValue === "string" ? effortOpt.currentValue : undefined;
|
|
2211
|
-
session.configOptions = buildConfigOptions(session.modes, session.models, session.modelInfos, currentEffort, session.agents, session.currentAgent
|
|
2289
|
+
session.configOptions = buildConfigOptions(session.modes, session.models, session.modelInfos, currentEffort, session.agents, session.currentAgent, {
|
|
2290
|
+
// The toggle follows the newly selected model: it disappears when the
|
|
2291
|
+
// model lacks fast support and reappears (with the retained user
|
|
2292
|
+
// intent) when a supporting model is selected again.
|
|
2293
|
+
supported: newModelInfo?.supportsFastMode ?? false,
|
|
2294
|
+
enabled: session.fastModeEnabled,
|
|
2295
|
+
useBooleanOption: clientSupportsBooleanConfigOptions(this.clientCapabilities),
|
|
2296
|
+
});
|
|
2212
2297
|
// Sync effort with the SDK if it changed after the model switch
|
|
2213
|
-
const newEffortOpt = session.configOptions.find((o) => o.id ===
|
|
2298
|
+
const newEffortOpt = session.configOptions.find((o) => o.id === EFFORT_CONFIG_ID);
|
|
2214
2299
|
const newEffort = typeof newEffortOpt?.currentValue === "string" ? newEffortOpt.currentValue : undefined;
|
|
2215
2300
|
if (newEffort !== currentEffort) {
|
|
2216
2301
|
await session.query.applyFlagSettings({
|
|
@@ -2233,7 +2318,7 @@ export class ClaudeAcpAgent {
|
|
|
2233
2318
|
});
|
|
2234
2319
|
}
|
|
2235
2320
|
}
|
|
2236
|
-
else if (configId ===
|
|
2321
|
+
else if (configId === AGENT_CONFIG_ID) {
|
|
2237
2322
|
// Live agent switch — no subprocess restart needed. Apply the SDK flag
|
|
2238
2323
|
// first so a rejected control request leaves both `currentAgent` and the
|
|
2239
2324
|
// config option untouched (no UI/SDK desync). Passing `null` clears the
|
|
@@ -2247,13 +2332,72 @@ export class ClaudeAcpAgent {
|
|
|
2247
2332
|
}
|
|
2248
2333
|
else {
|
|
2249
2334
|
session.configOptions = session.configOptions.map((o) => o.id === configId && typeof o.currentValue === "string" ? { ...o, currentValue: value } : o);
|
|
2250
|
-
if (configId ===
|
|
2335
|
+
if (configId === EFFORT_CONFIG_ID) {
|
|
2251
2336
|
await session.query.applyFlagSettings({
|
|
2252
2337
|
effortLevel: toSdkEffortLevel(value),
|
|
2253
2338
|
});
|
|
2254
2339
|
}
|
|
2255
2340
|
}
|
|
2256
2341
|
}
|
|
2342
|
+
/** Replace the Fast mode option in `session.configOptions` so it reflects
|
|
2343
|
+
* `enabled` (and the client's current boolean-capability). A no-op when the
|
|
2344
|
+
* option isn't present, so callers must confirm the current model surfaces
|
|
2345
|
+
* it first. */
|
|
2346
|
+
refreshFastModeOption(session, enabled) {
|
|
2347
|
+
const refreshed = createFastModeConfigOption(enabled, clientSupportsBooleanConfigOptions(this.clientCapabilities));
|
|
2348
|
+
session.configOptions = session.configOptions.map((o) => o.id === FAST_MODE_CONFIG_ID ? refreshed : o);
|
|
2349
|
+
}
|
|
2350
|
+
/** Toggle Fast mode for a session: push the SDK flag, record the user's
|
|
2351
|
+
* intent, and refresh the Fast mode config option in place. Only reached
|
|
2352
|
+
* once the option exists (i.e. the current model supports fast mode), so the
|
|
2353
|
+
* option is guaranteed to be present in `configOptions`. */
|
|
2354
|
+
async applyFastMode(session, enabled) {
|
|
2355
|
+
// Apply the SDK flag first so a rejected control request leaves both the
|
|
2356
|
+
// session state and the config option untouched (no UI/SDK desync).
|
|
2357
|
+
await session.query.applyFlagSettings({ fastMode: enabled });
|
|
2358
|
+
session.fastModeEnabled = enabled;
|
|
2359
|
+
this.refreshFastModeOption(session, enabled);
|
|
2360
|
+
}
|
|
2361
|
+
/** Reconcile the session's Fast mode toggle with an SDK-reported
|
|
2362
|
+
* `fast_mode_state` (delivered on `system`/init and on user-turn `result`s).
|
|
2363
|
+
* The SDK can flip fast mode independently of the user — e.g. back to `on`
|
|
2364
|
+
* once a rate-limit `cooldown` clears — so we mirror definitive on/off
|
|
2365
|
+
* changes into the config option and notify the client.
|
|
2366
|
+
*
|
|
2367
|
+
* Guards, in order:
|
|
2368
|
+
* - absent state: nothing to reconcile.
|
|
2369
|
+
* - no Fast mode option: the current model doesn't support fast mode, so the
|
|
2370
|
+
* reported state reflects capability, not the user's intent. Leave the
|
|
2371
|
+
* retained setting untouched so it's correct when a supporting model is
|
|
2372
|
+
* reselected (the source of the earlier intent-clobber bug was mutating it
|
|
2373
|
+
* here).
|
|
2374
|
+
* - `cooldown`: a transient suspension of an already-enabled fast mode.
|
|
2375
|
+
* Leave the toggle as-is rather than flapping it — and never let a stray
|
|
2376
|
+
* cooldown spuriously enable a toggle the user has off. */
|
|
2377
|
+
async syncFastModeState(sessionId, session, state) {
|
|
2378
|
+
if (state === undefined) {
|
|
2379
|
+
return;
|
|
2380
|
+
}
|
|
2381
|
+
if (!session.configOptions.some((o) => o.id === FAST_MODE_CONFIG_ID)) {
|
|
2382
|
+
return;
|
|
2383
|
+
}
|
|
2384
|
+
if (state === "cooldown") {
|
|
2385
|
+
return;
|
|
2386
|
+
}
|
|
2387
|
+
const enabled = state === "on";
|
|
2388
|
+
if (enabled === session.fastModeEnabled) {
|
|
2389
|
+
return;
|
|
2390
|
+
}
|
|
2391
|
+
session.fastModeEnabled = enabled;
|
|
2392
|
+
this.refreshFastModeOption(session, enabled);
|
|
2393
|
+
await this.client.sessionUpdate({
|
|
2394
|
+
sessionId,
|
|
2395
|
+
update: {
|
|
2396
|
+
sessionUpdate: "config_option_update",
|
|
2397
|
+
configOptions: session.configOptions,
|
|
2398
|
+
},
|
|
2399
|
+
});
|
|
2400
|
+
}
|
|
2257
2401
|
async getOrCreateSession(params) {
|
|
2258
2402
|
const existingSession = this.sessions[params.sessionId];
|
|
2259
2403
|
if (existingSession) {
|
|
@@ -2464,7 +2608,7 @@ export class ClaudeAcpAgent {
|
|
|
2464
2608
|
currentModeId: "plan",
|
|
2465
2609
|
},
|
|
2466
2610
|
});
|
|
2467
|
-
await this.updateConfigOption(sessionId,
|
|
2611
|
+
await this.updateConfigOption(sessionId, MODE_CONFIG_ID, "plan");
|
|
2468
2612
|
},
|
|
2469
2613
|
}),
|
|
2470
2614
|
],
|
|
@@ -2606,9 +2750,20 @@ export class ClaudeAcpAgent {
|
|
|
2606
2750
|
const currentAgent = requestedAgent && agents.some((a) => a.name === requestedAgent)
|
|
2607
2751
|
? requestedAgent
|
|
2608
2752
|
: DEFAULT_AGENT_ID;
|
|
2609
|
-
|
|
2753
|
+
// Seed Fast mode from the SDK's reported state so the UI reflects reality
|
|
2754
|
+
// (the CLI may start a session with fast mode already on, or force it off
|
|
2755
|
+
// when `fastModePerSessionOptIn` is set). The toggle is only surfaced while
|
|
2756
|
+
// the resolved model advertises `supportsFastMode`.
|
|
2757
|
+
const fastModeEnabled = initializationResult.fast_mode_state !== undefined &&
|
|
2758
|
+
fastModeStateEnabled(initializationResult.fast_mode_state);
|
|
2759
|
+
const fastMode = {
|
|
2760
|
+
supported: currentModelInfo?.supportsFastMode ?? false,
|
|
2761
|
+
enabled: fastModeEnabled,
|
|
2762
|
+
useBooleanOption: clientSupportsBooleanConfigOptions(this.clientCapabilities),
|
|
2763
|
+
};
|
|
2764
|
+
const configOptions = buildConfigOptions(modes, models, allowedModels, settingsManager.getSettings().effortLevel, agents, currentAgent, fastMode);
|
|
2610
2765
|
// Apply the initial effort level to the SDK so it matches the UI default
|
|
2611
|
-
const initialEffort = configOptions.find((o) => o.id ===
|
|
2766
|
+
const initialEffort = configOptions.find((o) => o.id === EFFORT_CONFIG_ID);
|
|
2612
2767
|
if (initialEffort &&
|
|
2613
2768
|
typeof initialEffort.currentValue === "string" &&
|
|
2614
2769
|
initialEffort.currentValue !== "default") {
|
|
@@ -2635,11 +2790,13 @@ export class ClaudeAcpAgent {
|
|
|
2635
2790
|
configOptions,
|
|
2636
2791
|
agents,
|
|
2637
2792
|
currentAgent,
|
|
2793
|
+
fastModeEnabled,
|
|
2638
2794
|
abortController,
|
|
2639
2795
|
emitRawSDKMessages: sessionMeta?.claudeCode?.emitRawSDKMessages ?? false,
|
|
2640
2796
|
contextWindowSize: inferContextWindowFromModel(models.currentModelId, currentModelInfo?.displayName, currentModelInfo?.description) ?? DEFAULT_CONTEXT_WINDOW,
|
|
2641
2797
|
taskState,
|
|
2642
2798
|
toolUseCache: {},
|
|
2799
|
+
emittedToolCalls: new Set(),
|
|
2643
2800
|
messageIdToUuid: new Map(),
|
|
2644
2801
|
};
|
|
2645
2802
|
return {
|
|
@@ -2813,10 +2970,78 @@ export async function discoverCustomAgents(q) {
|
|
|
2813
2970
|
return [];
|
|
2814
2971
|
}
|
|
2815
2972
|
}
|
|
2816
|
-
|
|
2973
|
+
/** Stable ids for the session config options surfaced via `configOptions`.
|
|
2974
|
+
* Centralized so the option declarations in `buildConfigOptions` and the
|
|
2975
|
+
* handlers in `setSessionConfigOption`/`applyConfigOptionValue` reference the
|
|
2976
|
+
* same identifiers and can't drift apart. */
|
|
2977
|
+
export const MODE_CONFIG_ID = "mode";
|
|
2978
|
+
export const MODEL_CONFIG_ID = "model";
|
|
2979
|
+
export const EFFORT_CONFIG_ID = "effort";
|
|
2980
|
+
export const AGENT_CONFIG_ID = "agent";
|
|
2981
|
+
export const FAST_MODE_CONFIG_ID = "fast";
|
|
2982
|
+
/** Select-fallback values used when the client has not opted into boolean
|
|
2983
|
+
* config options (see {@link createFastModeConfigOption}). */
|
|
2984
|
+
export const FAST_MODE_ON = "on";
|
|
2985
|
+
export const FAST_MODE_OFF = "off";
|
|
2986
|
+
const FAST_MODE_DESCRIPTION = "Faster responses on supported models";
|
|
2987
|
+
/** Map the SDK's tri-state `fast_mode_state` onto the boolean config toggle.
|
|
2988
|
+
* `cooldown` (fast mode temporarily suspended after a rate limit, per the SDK
|
|
2989
|
+
* docs) keeps the toggle on so it reflects the user's intent — only an
|
|
2990
|
+
* explicit `off` clears it. */
|
|
2991
|
+
export function fastModeStateEnabled(state) {
|
|
2992
|
+
return state !== "off";
|
|
2993
|
+
}
|
|
2994
|
+
/** Whether the Client advertised support for boolean session config options
|
|
2995
|
+
* (`session.configOptions.boolean`). Agents MUST only send `type: "boolean"`
|
|
2996
|
+
* config options to Clients that opt in; otherwise we fall back to a `select`.
|
|
2997
|
+
* See https://agentclientprotocol.com/rfds/boolean-config-option. */
|
|
2998
|
+
export function clientSupportsBooleanConfigOptions(clientCapabilities) {
|
|
2999
|
+
return clientCapabilities?.session?.configOptions?.boolean != null;
|
|
3000
|
+
}
|
|
3001
|
+
/** Build the Fast mode config option. When the Client supports boolean config
|
|
3002
|
+
* options we expose a native `type: "boolean"` toggle; otherwise we degrade to
|
|
3003
|
+
* a two-value `select` ("on"/"off") so older Clients still get a usable
|
|
3004
|
+
* control. */
|
|
3005
|
+
export function createFastModeConfigOption(enabled, useBooleanOption) {
|
|
3006
|
+
const base = {
|
|
3007
|
+
id: FAST_MODE_CONFIG_ID,
|
|
3008
|
+
name: "Fast mode",
|
|
3009
|
+
description: FAST_MODE_DESCRIPTION,
|
|
3010
|
+
category: "model_config",
|
|
3011
|
+
};
|
|
3012
|
+
if (useBooleanOption) {
|
|
3013
|
+
return { ...base, type: "boolean", currentValue: enabled };
|
|
3014
|
+
}
|
|
3015
|
+
return {
|
|
3016
|
+
...base,
|
|
3017
|
+
type: "select",
|
|
3018
|
+
currentValue: enabled ? FAST_MODE_ON : FAST_MODE_OFF,
|
|
3019
|
+
options: [
|
|
3020
|
+
{ value: FAST_MODE_ON, name: "On" },
|
|
3021
|
+
{ value: FAST_MODE_OFF, name: "Off" },
|
|
3022
|
+
],
|
|
3023
|
+
};
|
|
3024
|
+
}
|
|
3025
|
+
/** Resolve the requested Fast mode value from a `session/set_config_option`
|
|
3026
|
+
* request. Accepts a native boolean (boolean-capable Clients) or the
|
|
3027
|
+
* "on"/"off" select-fallback strings. */
|
|
3028
|
+
export function resolveFastModeEnabled(params) {
|
|
3029
|
+
const value = params.value;
|
|
3030
|
+
if (typeof value === "boolean") {
|
|
3031
|
+
return value;
|
|
3032
|
+
}
|
|
3033
|
+
if (value === FAST_MODE_ON) {
|
|
3034
|
+
return true;
|
|
3035
|
+
}
|
|
3036
|
+
if (value === FAST_MODE_OFF) {
|
|
3037
|
+
return false;
|
|
3038
|
+
}
|
|
3039
|
+
throw new Error(`Invalid value for config option ${FAST_MODE_CONFIG_ID}: ${value}`);
|
|
3040
|
+
}
|
|
3041
|
+
export function buildConfigOptions(modes, models, modelInfos, currentEffortLevel, agents = [], currentAgent = DEFAULT_AGENT_ID, fastMode) {
|
|
2817
3042
|
const options = [
|
|
2818
3043
|
{
|
|
2819
|
-
id:
|
|
3044
|
+
id: MODE_CONFIG_ID,
|
|
2820
3045
|
name: "Mode",
|
|
2821
3046
|
description: "Session permission mode",
|
|
2822
3047
|
category: "mode",
|
|
@@ -2829,7 +3054,7 @@ export function buildConfigOptions(modes, models, modelInfos, currentEffortLevel
|
|
|
2829
3054
|
})),
|
|
2830
3055
|
},
|
|
2831
3056
|
{
|
|
2832
|
-
id:
|
|
3057
|
+
id: MODEL_CONFIG_ID,
|
|
2833
3058
|
name: "Model",
|
|
2834
3059
|
description: "AI model to use",
|
|
2835
3060
|
category: "model",
|
|
@@ -2861,7 +3086,7 @@ export function buildConfigOptions(modes, models, modelInfos, currentEffortLevel
|
|
|
2861
3086
|
const includes = (l) => l === "default" || supportedLevels.includes(l);
|
|
2862
3087
|
const validEffort = currentEffortLevel && includes(currentEffortLevel) ? currentEffortLevel : "default";
|
|
2863
3088
|
options.push({
|
|
2864
|
-
id:
|
|
3089
|
+
id: EFFORT_CONFIG_ID,
|
|
2865
3090
|
name: "Effort",
|
|
2866
3091
|
description: "Available effort levels for this model",
|
|
2867
3092
|
category: "thought_level",
|
|
@@ -2870,13 +3095,19 @@ export function buildConfigOptions(modes, models, modelInfos, currentEffortLevel
|
|
|
2870
3095
|
options: effortOptions,
|
|
2871
3096
|
});
|
|
2872
3097
|
}
|
|
3098
|
+
// Surface the Fast mode toggle only when the current model supports it. The
|
|
3099
|
+
// option renders as a native boolean toggle for Clients that opted in, and a
|
|
3100
|
+
// two-value select otherwise.
|
|
3101
|
+
if (fastMode?.supported) {
|
|
3102
|
+
options.push(createFastModeConfigOption(fastMode.enabled, fastMode.useBooleanOption));
|
|
3103
|
+
}
|
|
2873
3104
|
// Only surface the Agent picker when there's a real choice — i.e. the user
|
|
2874
3105
|
// has configured at least one custom agent (built-ins are filtered out in
|
|
2875
3106
|
// discoverCustomAgents). With none configured, "Default" would be the only
|
|
2876
3107
|
// entry, so we omit the option entirely.
|
|
2877
3108
|
if (agents.length > 0) {
|
|
2878
3109
|
options.push({
|
|
2879
|
-
id:
|
|
3110
|
+
id: AGENT_CONFIG_ID,
|
|
2880
3111
|
name: "Agent",
|
|
2881
3112
|
description: "Main-thread agent persona",
|
|
2882
3113
|
type: "select",
|
|
@@ -2896,13 +3127,17 @@ export function buildConfigOptions(modes, models, modelInfos, currentEffortLevel
|
|
|
2896
3127
|
// Claude Code CLI persists display strings like "opus[1m]" in settings,
|
|
2897
3128
|
// but the SDK model list uses IDs like "claude-opus-4-6-1m".
|
|
2898
3129
|
const MODEL_CONTEXT_HINT_PATTERN = /\[(\d+m)\]$/i;
|
|
2899
|
-
// Captures a model family version
|
|
2900
|
-
// `
|
|
2901
|
-
//
|
|
2902
|
-
const MODEL_FAMILY_VERSION_PATTERN = /\b(\d+)[-.](\d+)
|
|
3130
|
+
// Captures a model family version: `4-6`/`4.7` for dated generations, or a
|
|
3131
|
+
// bare `5` for single-number ones like "Sonnet 5". Used to keep a pinned
|
|
3132
|
+
// `claude-opus-4-6` from matching the `opus` alias once it points at 4.7.
|
|
3133
|
+
const MODEL_FAMILY_VERSION_PATTERN = /\b(\d+)(?:[-.](\d+))?\b/;
|
|
2903
3134
|
function extractModelFamilyVersion(s) {
|
|
2904
|
-
|
|
2905
|
-
|
|
3135
|
+
// Strip "[1m]"-style context hints first — that digit is context window
|
|
3136
|
+
// size, not a model generation version.
|
|
3137
|
+
const match = s.replace(/\[\d+m\]/gi, "").match(MODEL_FAMILY_VERSION_PATTERN);
|
|
3138
|
+
if (!match)
|
|
3139
|
+
return null;
|
|
3140
|
+
return match[2] ? `${match[1]}.${match[2]}` : match[1];
|
|
2906
3141
|
}
|
|
2907
3142
|
function modelVersionsCompatible(preference, candidate) {
|
|
2908
3143
|
const preferred = extractModelFamilyVersion(preference);
|
|
@@ -2947,7 +3182,7 @@ function scoreModelMatch(model, tokens, contextHint) {
|
|
|
2947
3182
|
return 0;
|
|
2948
3183
|
return score;
|
|
2949
3184
|
}
|
|
2950
|
-
function resolveModelPreference(models, preference) {
|
|
3185
|
+
export function resolveModelPreference(models, preference) {
|
|
2951
3186
|
const trimmed = preference.trim();
|
|
2952
3187
|
if (!trimmed)
|
|
2953
3188
|
return null;
|
|
@@ -2958,6 +3193,15 @@ function resolveModelPreference(models, preference) {
|
|
|
2958
3193
|
model.displayName.toLowerCase() === lower);
|
|
2959
3194
|
if (directMatch)
|
|
2960
3195
|
return directMatch;
|
|
3196
|
+
// Exact match on the alias's canonical resolved id (e.g. a pinned
|
|
3197
|
+
// "claude-sonnet-5" against the "sonnet" row's `resolvedModel`). SDK-
|
|
3198
|
+
// reported and unambiguous, so it's tried before the fuzzier tiers below.
|
|
3199
|
+
// "default" is skipped first since it shares a resolvedModel with
|
|
3200
|
+
// whichever alias the CLI currently recommends — a specific pin should
|
|
3201
|
+
// land on that named alias, not "default".
|
|
3202
|
+
const resolvedMatch = models.find((model) => model.value !== "default" && model.resolvedModel?.toLowerCase() === lower) ?? models.find((model) => model.resolvedModel?.toLowerCase() === lower);
|
|
3203
|
+
if (resolvedMatch)
|
|
3204
|
+
return resolvedMatch;
|
|
2961
3205
|
// Substring match
|
|
2962
3206
|
const includesMatch = models.find((model) => {
|
|
2963
3207
|
if (!modelVersionsCompatible(trimmed, model))
|
|
@@ -3012,7 +3256,7 @@ function resolveSettingsModel(models, settingsModel, logger) {
|
|
|
3012
3256
|
* - The Default option is unaffected by `availableModels` — it always remains
|
|
3013
3257
|
* available, even when the allowlist is `[]`.
|
|
3014
3258
|
*/
|
|
3015
|
-
function applyAvailableModelsAllowlist(sdkModels, allowlist) {
|
|
3259
|
+
export function applyAvailableModelsAllowlist(sdkModels, allowlist) {
|
|
3016
3260
|
// Default is always preserved per the docs. Synthesize one if the SDK
|
|
3017
3261
|
// didn't surface it so downstream code (e.g. `getAvailableModels` picking
|
|
3018
3262
|
// `models[0]` as a fallback) still has something to work with.
|
|
@@ -3262,6 +3506,53 @@ function applyMessageId(update, messageId) {
|
|
|
3262
3506
|
update.messageId = messageId;
|
|
3263
3507
|
}
|
|
3264
3508
|
}
|
|
3509
|
+
/** Built-in tools that drive the task list (headless/SDK sessions use these
|
|
3510
|
+
* instead of TodoWrite). Their tool_use/tool_result are surfaced as `plan`
|
|
3511
|
+
* snapshots rather than as tool_calls. */
|
|
3512
|
+
function isTaskTool(toolName) {
|
|
3513
|
+
return (toolName === "TaskCreate" ||
|
|
3514
|
+
toolName === "TaskUpdate" ||
|
|
3515
|
+
toolName === "TaskList" ||
|
|
3516
|
+
toolName === "TaskGet");
|
|
3517
|
+
}
|
|
3518
|
+
/** Whether a tool's tool_use surfaces to the client as a standalone
|
|
3519
|
+
* `tool_call`. TodoWrite is rendered as a `plan` and Task* tools are
|
|
3520
|
+
* suppressed (their plan snapshot is emitted at tool_result time), so neither
|
|
3521
|
+
* produces a tool_call. */
|
|
3522
|
+
function shouldEmitToolCall(toolName) {
|
|
3523
|
+
return toolName !== "TodoWrite" && !isTaskTool(toolName);
|
|
3524
|
+
}
|
|
3525
|
+
/** Build the `tool_call` (or, with `refine`, the `tool_call_update`)
|
|
3526
|
+
* notification for a tool_use. Shared by every site that surfaces a tool call:
|
|
3527
|
+
* the streamed tool_use path (first encounter → tool_call, later encounter →
|
|
3528
|
+
* refine) and the permission flow (`ensureToolCallEmitted`), so they can't
|
|
3529
|
+
* drift. The initial `tool_call` carries `status: "pending"` and, for Bash, the
|
|
3530
|
+
* `terminal_info` _meta that the later `terminal_output`/`terminal_exit`
|
|
3531
|
+
* updates key off of; a refining `tool_call_update` carries neither. */
|
|
3532
|
+
function toolCallNotification(toolUse, rawInput, supportsTerminalOutput, cwd, refine = false) {
|
|
3533
|
+
if (refine) {
|
|
3534
|
+
return {
|
|
3535
|
+
_meta: { claudeCode: { toolName: toolUse.name } },
|
|
3536
|
+
toolCallId: toolUse.id,
|
|
3537
|
+
sessionUpdate: "tool_call_update",
|
|
3538
|
+
rawInput,
|
|
3539
|
+
...toolInfoFromToolUse(toolUse, supportsTerminalOutput, cwd),
|
|
3540
|
+
};
|
|
3541
|
+
}
|
|
3542
|
+
return {
|
|
3543
|
+
_meta: {
|
|
3544
|
+
claudeCode: { toolName: toolUse.name },
|
|
3545
|
+
...(toolUse.name === "Bash" && supportsTerminalOutput
|
|
3546
|
+
? { terminal_info: { terminal_id: toolUse.id } }
|
|
3547
|
+
: {}),
|
|
3548
|
+
},
|
|
3549
|
+
toolCallId: toolUse.id,
|
|
3550
|
+
sessionUpdate: "tool_call",
|
|
3551
|
+
rawInput,
|
|
3552
|
+
status: "pending",
|
|
3553
|
+
...toolInfoFromToolUse(toolUse, supportsTerminalOutput, cwd),
|
|
3554
|
+
};
|
|
3555
|
+
}
|
|
3265
3556
|
/**
|
|
3266
3557
|
* Convert an SDKAssistantMessage (Claude) to a SessionNotification (ACP).
|
|
3267
3558
|
* Only handles text, image, and thinking chunks for now.
|
|
@@ -3344,10 +3635,7 @@ export function toAcpNotifications(content, role, sessionId, toolUseCache, clien
|
|
|
3344
3635
|
};
|
|
3345
3636
|
}
|
|
3346
3637
|
}
|
|
3347
|
-
else if (chunk.name
|
|
3348
|
-
chunk.name === "TaskUpdate" ||
|
|
3349
|
-
chunk.name === "TaskList" ||
|
|
3350
|
-
chunk.name === "TaskGet") {
|
|
3638
|
+
else if (isTaskTool(chunk.name)) {
|
|
3351
3639
|
// Task* tool_use is suppressed; the plan update is emitted at
|
|
3352
3640
|
// tool_result time once we have the task ID (for TaskCreate) and
|
|
3353
3641
|
// confirmation that the change took effect.
|
|
@@ -3399,40 +3687,25 @@ export function toAcpNotifications(content, role, sessionId, toolUseCache, clien
|
|
|
3399
3687
|
catch {
|
|
3400
3688
|
// ignore if we can't turn it to JSON
|
|
3401
3689
|
}
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
};
|
|
3690
|
+
// Emit a `tool_call` only the first time this id surfaces to the
|
|
3691
|
+
// client; afterwards refine it with a `tool_call_update`. The first
|
|
3692
|
+
// surface may be this stream chunk OR an earlier permission request
|
|
3693
|
+
// (see `ensureToolCallEmitted`), so emission is tracked separately
|
|
3694
|
+
// from `toolUseCache`. Without an `emittedToolCalls` set we fall back
|
|
3695
|
+
// to cache presence — the historical streaming-only behavior.
|
|
3696
|
+
const emittedToolCalls = options?.emittedToolCalls;
|
|
3697
|
+
const alreadyEmitted = emittedToolCalls ? emittedToolCalls.has(chunk.id) : alreadyCached;
|
|
3698
|
+
emittedToolCalls?.add(chunk.id);
|
|
3699
|
+
if (alreadyEmitted) {
|
|
3700
|
+
// Already surfaced (full assistant message after streaming, or a
|
|
3701
|
+
// permission request emitted it first) — refine with a
|
|
3702
|
+
// tool_call_update rather than emitting a duplicate tool_call.
|
|
3703
|
+
update = toolCallNotification(chunk, rawInput, supportsTerminalOutput, options?.cwd, true);
|
|
3417
3704
|
}
|
|
3418
3705
|
else {
|
|
3419
|
-
// First
|
|
3420
|
-
//
|
|
3421
|
-
update =
|
|
3422
|
-
_meta: {
|
|
3423
|
-
claudeCode: {
|
|
3424
|
-
toolName: chunk.name,
|
|
3425
|
-
},
|
|
3426
|
-
...(chunk.name === "Bash" && supportsTerminalOutput
|
|
3427
|
-
? { terminal_info: { terminal_id: chunk.id } }
|
|
3428
|
-
: {}),
|
|
3429
|
-
},
|
|
3430
|
-
toolCallId: chunk.id,
|
|
3431
|
-
sessionUpdate: "tool_call",
|
|
3432
|
-
rawInput,
|
|
3433
|
-
status: "pending",
|
|
3434
|
-
...toolInfoFromToolUse(chunk, supportsTerminalOutput, options?.cwd),
|
|
3435
|
-
};
|
|
3706
|
+
// First surface (streaming content_block_start or replay) — send as
|
|
3707
|
+
// tool_call (with terminal_info for Bash).
|
|
3708
|
+
update = toolCallNotification(chunk, rawInput, supportsTerminalOutput, options?.cwd);
|
|
3436
3709
|
}
|
|
3437
3710
|
}
|
|
3438
3711
|
break;
|
|
@@ -3445,15 +3718,13 @@ export function toAcpNotifications(content, role, sessionId, toolUseCache, clien
|
|
|
3445
3718
|
case "bash_code_execution_tool_result":
|
|
3446
3719
|
case "text_editor_code_execution_tool_result":
|
|
3447
3720
|
case "mcp_tool_result": {
|
|
3721
|
+
options?.emittedToolCalls?.delete(chunk.tool_use_id);
|
|
3448
3722
|
const toolUse = toolUseCache[chunk.tool_use_id];
|
|
3449
3723
|
if (!toolUse) {
|
|
3450
3724
|
logger.error(`[claude-agent-acp] Got a tool result for tool use that wasn't tracked: ${chunk.tool_use_id}`);
|
|
3451
3725
|
break;
|
|
3452
3726
|
}
|
|
3453
|
-
if (toolUse.name
|
|
3454
|
-
toolUse.name === "TaskUpdate" ||
|
|
3455
|
-
toolUse.name === "TaskList" ||
|
|
3456
|
-
toolUse.name === "TaskGet") {
|
|
3727
|
+
if (isTaskTool(toolUse.name)) {
|
|
3457
3728
|
// Headless/SDK sessions emit Task* tools instead of TodoWrite.
|
|
3458
3729
|
// TaskCreate / TaskUpdate mutate the accumulated task list; TaskList
|
|
3459
3730
|
// and TaskGet are read-only so we just suppress their tool_call /
|
|
@@ -3560,6 +3831,7 @@ export function streamEventToAcpNotifications(message, sessionId, toolUseCache,
|
|
|
3560
3831
|
parentToolUseId: message.parent_tool_use_id,
|
|
3561
3832
|
cwd: options?.cwd,
|
|
3562
3833
|
taskState: options?.taskState,
|
|
3834
|
+
emittedToolCalls: options?.emittedToolCalls,
|
|
3563
3835
|
messageId: options?.messageId,
|
|
3564
3836
|
});
|
|
3565
3837
|
case "content_block_delta":
|
|
@@ -3568,6 +3840,7 @@ export function streamEventToAcpNotifications(message, sessionId, toolUseCache,
|
|
|
3568
3840
|
parentToolUseId: message.parent_tool_use_id,
|
|
3569
3841
|
cwd: options?.cwd,
|
|
3570
3842
|
taskState: options?.taskState,
|
|
3843
|
+
emittedToolCalls: options?.emittedToolCalls,
|
|
3571
3844
|
messageId: options?.messageId,
|
|
3572
3845
|
});
|
|
3573
3846
|
// No content. `ping` is a Messages-API keep-alive event that the SDK's
|
|
@@ -3637,6 +3910,7 @@ export function runAcp() {
|
|
|
3637
3910
|
.onRequest(methods.agent.session.setMode, (ctx) => agent.setSessionMode(ctx.params))
|
|
3638
3911
|
.onRequest(methods.agent.session.setConfigOption, (ctx) => agent.setSessionConfigOption(ctx.params))
|
|
3639
3912
|
.onRequest(methods.agent.authenticate, (ctx) => agent.authenticate(ctx.params))
|
|
3913
|
+
.onRequest(methods.agent.logout, (ctx) => agent.logout(ctx.params))
|
|
3640
3914
|
.onRequest(methods.agent.session.prompt, (ctx) => runPromptWithCancellation(agent, ctx.params, ctx.signal))
|
|
3641
3915
|
.onNotification(methods.agent.session.cancel, (ctx) => agent.cancel(ctx.params))
|
|
3642
3916
|
.connect(stream);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"elicitation.d.ts","sourceRoot":"","sources":["../src/elicitation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,wBAAwB,EACxB,yBAAyB,EAI1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAC5F,OAAO,KAAK,EACV,oBAAoB,EAErB,MAAM,6CAA6C,CAAC;AAErD;;;;;;;;;;;;;GAaG;AAEH,yDAAyD;AACzD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAE,MAAM,GAChB,wBAAwB,GAAG,IAAI,CAyBjC;AAED;;;GAGG;AACH,wBAAgB,uCAAuC,CACrD,QAAQ,EAAE,yBAAyB,GAClC,iBAAiB,CAUnB;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,EAAE,GAAG,IAAI,CAUhG;AA4CD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,eAAe,EAAE,EAC5B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,wBAAwB,CAwD1B;AAED,+EAA+E;AAC/E,MAAM,MAAM,sBAAsB,
|
|
1
|
+
{"version":3,"file":"elicitation.d.ts","sourceRoot":"","sources":["../src/elicitation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,wBAAwB,EACxB,yBAAyB,EAI1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAC5F,OAAO,KAAK,EACV,oBAAoB,EAErB,MAAM,6CAA6C,CAAC;AAErD;;;;;;;;;;;;;GAaG;AAEH,yDAAyD;AACzD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAE,MAAM,GAChB,wBAAwB,GAAG,IAAI,CAyBjC;AAED;;;GAGG;AACH,wBAAgB,uCAAuC,CACrD,QAAQ,EAAE,yBAAyB,GAClC,iBAAiB,CAUnB;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,EAAE,GAAG,IAAI,CAUhG;AA4CD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,eAAe,EAAE,EAC5B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,wBAAwB,CAwD1B;AAED,+EAA+E;AAC/E,MAAM,MAAM,sBAAsB,GAChC;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEvF;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,yBAAyB,EACnC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,SAAS,EAAE,eAAe,EAAE,GAC3B,sBAAsB,CAkCxB"}
|
package/dist/index.js
CHANGED
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
import { resolveSettings } from "@anthropic-ai/claude-agent-sdk";
|
|
3
3
|
import { claudeCliPath, runAcp } from "./acp-agent.js";
|
|
4
4
|
import packageJson from "../package.json" with { type: "json" };
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
else if (process.argv.includes("--cli")) {
|
|
5
|
+
// `--cli` is checked first so that `--version`/`-v` (and any other flags) are
|
|
6
|
+
// forwarded to the wrapped native CLI rather than swallowed by our own version
|
|
7
|
+
// handler below. Our version flag only applies when not delegating.
|
|
8
|
+
if (process.argv.includes("--cli")) {
|
|
10
9
|
const { spawn } = await import("node:child_process");
|
|
11
10
|
const args = process.argv.slice(2).filter((arg) => arg !== "--cli");
|
|
12
11
|
const child = spawn(await claudeCliPath(), args, { stdio: "inherit" });
|
|
@@ -36,6 +35,10 @@ else if (process.argv.includes("--cli")) {
|
|
|
36
35
|
process.exit(1);
|
|
37
36
|
});
|
|
38
37
|
}
|
|
38
|
+
else if (process.argv.includes("--version") || process.argv.includes("-v")) {
|
|
39
|
+
console.log(packageJson.version);
|
|
40
|
+
process.exit(0);
|
|
41
|
+
}
|
|
39
42
|
else {
|
|
40
43
|
// Apply env vars from the managed-policy tier before any SDK call so the
|
|
41
44
|
// SDK subprocess inherits them. Going through resolveSettings (vs. a raw
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACT,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|
package/dist/tools.js
CHANGED
|
@@ -234,6 +234,23 @@ export function toolInfoFromToolUse(toolUse, supportsTerminalOutput = false, cwd
|
|
|
234
234
|
content: [],
|
|
235
235
|
};
|
|
236
236
|
}
|
|
237
|
+
case "ReportFindings": {
|
|
238
|
+
const input = toolUse.input;
|
|
239
|
+
const findings = input?.findings ?? [];
|
|
240
|
+
return {
|
|
241
|
+
title: findings.length === 0
|
|
242
|
+
? "Report findings: none found"
|
|
243
|
+
: `Report ${findings.length} finding${findings.length === 1 ? "" : "s"}`,
|
|
244
|
+
kind: "think",
|
|
245
|
+
content: findings.map((finding) => ({
|
|
246
|
+
type: "content",
|
|
247
|
+
content: {
|
|
248
|
+
type: "text",
|
|
249
|
+
text: `**${finding.file}${finding.line ? `:${finding.line}` : ""}** — ${finding.summary}`,
|
|
250
|
+
},
|
|
251
|
+
})),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
237
254
|
case "TaskCreate": {
|
|
238
255
|
const input = toolUse.input;
|
|
239
256
|
return {
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.54.0",
|
|
7
7
|
"description": "An ACP-compatible coding agent powered by the Claude Agent SDK (TypeScript)",
|
|
8
8
|
"main": "dist/lib.js",
|
|
9
9
|
"types": "dist/lib.d.ts",
|
|
@@ -63,21 +63,21 @@
|
|
|
63
63
|
"node": ">=22"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@agentclientprotocol/sdk": "1.
|
|
67
|
-
"@anthropic-ai/claude-agent-sdk": "0.3.
|
|
66
|
+
"@agentclientprotocol/sdk": "1.1.0",
|
|
67
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.197",
|
|
68
68
|
"zod": "^3.25.0 || ^4.0.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
|
-
"@anthropic-ai/sdk": "0.
|
|
71
|
+
"@anthropic-ai/sdk": "0.108.0",
|
|
72
72
|
"@eslint/js": "10.0.1",
|
|
73
73
|
"@tsconfig/node22": "22.0.5",
|
|
74
74
|
"@types/node": "26.0.1",
|
|
75
|
-
"@typescript-eslint/eslint-plugin": "8.62.
|
|
76
|
-
"@typescript-eslint/parser": "8.62.
|
|
77
|
-
"eslint": "10.
|
|
75
|
+
"@typescript-eslint/eslint-plugin": "8.62.1",
|
|
76
|
+
"@typescript-eslint/parser": "8.62.1",
|
|
77
|
+
"eslint": "10.6.0",
|
|
78
78
|
"eslint-config-prettier": "10.1.8",
|
|
79
79
|
"globals": "17.7.0",
|
|
80
|
-
"prettier": "3.
|
|
80
|
+
"prettier": "3.9.4",
|
|
81
81
|
"ts-node": "10.9.2",
|
|
82
82
|
"typescript": "6.0.3",
|
|
83
83
|
"vitest": "4.1.9"
|