diff --git a/dist/acp-agent.js b/dist/acp-agent.js --- a/dist/acp-agent.js +++ b/dist/acp-agent.js @@ -2681,10 +2681,20 @@ cost: { amount: message.total_cost_usd, currency: "USD", }, - ...(message.origin && { - _meta: { "_claude/origin": message.origin }, - }), + _meta: { + ...(message.origin && { "_claude/origin": message.origin }), + // ACP's core Usage shape exposes context occupancy and + // cost, but not the billable input/output split. Keep the + // SDK's bounded aggregate in extension metadata so ACPX can + // normalize it without persisting a raw provider message. + usage: { + input_tokens: message.usage.input_tokens, + output_tokens: message.usage.output_tokens, + cache_read_input_tokens: message.usage.cache_read_input_tokens, + cache_creation_input_tokens: message.usage.cache_creation_input_tokens, + }, + }, }, }); } @@ -4866,8 +4876,12 @@ const options = { systemPrompt, settingSources: ["user", "project", "local"], ...(thinking !== undefined && { thinking }), ...userProvidedOptions, + // Paperclip Runner owns the complete session context. Its isolated + // user root contains only assigned skills; project/local settings + // would reintroduce host prompts, plugins, skills, and MCP servers. + ...(process.env.PAPERCLIP_ACPX_ISOLATED_CONTEXT === "1" && { settingSources: ["user"] }), ...(settings && { settings }), env, // Override certain fields that must be controlled by ACP @@ -4875,7 +4889,9 @@ includePartialMessages: true, forwardSubagentText, mcpServers: { - ...(userProvidedOptions?.mcpServers || {}), + ...(process.env.PAPERCLIP_ACPX_ISOLATED_CONTEXT === "1" + ? {} + : (userProvidedOptions?.mcpServers || {})), ...mcpServers, ...(fileChangeAuditSupport ? { [FILE_CHANGE_AUDIT_SERVER_NAME]: fileChangeAuditSupport.mcpServer } @@ -3776,6 +3776,11 @@ ? option.options.flatMap((o) => ("options" in o ? o.options : [o])) : []; let validValue = allValues.find((o) => o.value === params.value); + // Paperclip's model field is an exact provider request, not a fuzzy picker + // search. Forward custom IDs to the SDK and let the provider reject them. + if (params.configId === MODEL_CONFIG_ID && process.env.PAPERCLIP_ACPX_ISOLATED_CONTEXT === "1" && params.value.trim()) { + validValue = { value: params.value, name: params.value }; + } // The option's reported currentValue is always a valid target, even when // it has no options entry: a session running an out-of-picker model // (resumed onto an allowlist-excluded model, or a refusal fallback) diff --git a/package.json b/package.json --- a/package.json +++ b/package.json @@ -65,5 +65,5 @@ "dependencies": { "@agentclientprotocol/sdk": "1.3.0", - "@anthropic-ai/claude-agent-sdk": "0.3.232", + "@anthropic-ai/claude-agent-sdk": "0.3.263", "zod": "^3.25.0 || ^4.0.0" },