mirror of
https://github.com/agentclientprotocol/claude-agent-acp.git
synced 2026-10-27 04:30:59 +00:00
feat: Update to claude agent sdk v0.3.220 (#921)
- **feat: Update to claude-agent-sdk 0.3.220** - **Explain unavailable Fast mode reasons**
This commit is contained in:
130
package-lock.json
generated
130
package-lock.json
generated
@@ -10,22 +10,22 @@
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@agentclientprotocol/sdk": "1.3.0",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.3.219",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.3.220",
|
||||
"zod": "^3.25.0 || ^4.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"claude-agent-acp": "dist/index.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@anthropic-ai/sdk": "0.114.0",
|
||||
"@anthropic-ai/sdk": "0.115.0",
|
||||
"@eslint/js": "10.0.1",
|
||||
"@tsconfig/node22": "22.0.5",
|
||||
"@types/node": "26.1.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.65.0",
|
||||
"@typescript-eslint/parser": "8.65.0",
|
||||
"eslint": "10.7.0",
|
||||
"eslint": "10.8.0",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"globals": "17.7.0",
|
||||
"globals": "17.8.0",
|
||||
"prettier": "3.9.6",
|
||||
"ts-node": "10.9.2",
|
||||
"typescript": "6.0.3",
|
||||
@@ -45,22 +45,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk": {
|
||||
"version": "0.3.219",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.3.219.tgz",
|
||||
"integrity": "sha512-dJjzKxoyCQSEEEo9a0g3wBQprRMCpsqjmsNOZaGOWw+W+JHZsolDBhoYfoZ9BA8EdwgaJmbQUvhkAZjROUsBnQ==",
|
||||
"version": "0.3.220",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.3.220.tgz",
|
||||
"integrity": "sha512-glc7SdwPkOkLw8oxwLo9PKTdLJGqW/PIR4urWXFoRtX9YllwozsEVc5Tc1+EvLSkfrsxPJqQWqOgpjUOQXf1oA==",
|
||||
"license": "SEE LICENSE IN README.md",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.219",
|
||||
"@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.219",
|
||||
"@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.219",
|
||||
"@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.219",
|
||||
"@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.219",
|
||||
"@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.219",
|
||||
"@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.219",
|
||||
"@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.219"
|
||||
"@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.220",
|
||||
"@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.220",
|
||||
"@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.220",
|
||||
"@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.220",
|
||||
"@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.220",
|
||||
"@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.220",
|
||||
"@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.220",
|
||||
"@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.220"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@anthropic-ai/sdk": ">=0.93.0",
|
||||
@@ -69,9 +69,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk-darwin-arm64": {
|
||||
"version": "0.3.219",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-arm64/-/claude-agent-sdk-darwin-arm64-0.3.219.tgz",
|
||||
"integrity": "sha512-TQhGAlbMsOGXi03dwf4nD274Lc5BOJg4QFJTuXcQyhLhx0hUqzxCmtvpXt6S70K6yl1Zgc+2n5W/r1Dgt8G8iw==",
|
||||
"version": "0.3.220",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-arm64/-/claude-agent-sdk-darwin-arm64-0.3.220.tgz",
|
||||
"integrity": "sha512-7VxlbEosK7DODiOnsjoVd0DSJzbnaPrM2jelMHI0y8zx1UnLS3WC6EFUXbvy74F2sXqEznh2tzn7EKWInaRN6Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -82,9 +82,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk-darwin-x64": {
|
||||
"version": "0.3.219",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-x64/-/claude-agent-sdk-darwin-x64-0.3.219.tgz",
|
||||
"integrity": "sha512-zA/wHN+os4yqXASXJxvGGNSD1p7LZ6BMN71CCphoy5u+d6IpNOCtATnZwINEc2fGFHpv/QDci6jhywJ2O9Flbw==",
|
||||
"version": "0.3.220",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-x64/-/claude-agent-sdk-darwin-x64-0.3.220.tgz",
|
||||
"integrity": "sha512-X9RwDsSmbF6ultKZroaip+DL8WRgC64gHbrAwrRlAFSPNZV7zmJyP2ur8rW7KrxqmtuehdMMkw8+SAC/6hD2PA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -95,9 +95,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk-linux-arm64": {
|
||||
"version": "0.3.219",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64/-/claude-agent-sdk-linux-arm64-0.3.219.tgz",
|
||||
"integrity": "sha512-lizasky9Xj0ouYrz/Akst573Sm8NO3k/0iGCeCDBoQKLnONbVFwc7sHq9x426Pfcllgb4C2Xyc79/1iOALh/9g==",
|
||||
"version": "0.3.220",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64/-/claude-agent-sdk-linux-arm64-0.3.220.tgz",
|
||||
"integrity": "sha512-WkROPwWskqhKR9XgnmseHQ6rLi9zM9qt57IWoToIjL/eXOqDWipp7JXZ1L5ud+LrA42dunHPZfBwD/vXZ+A7LA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -111,9 +111,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk-linux-arm64-musl": {
|
||||
"version": "0.3.219",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64-musl/-/claude-agent-sdk-linux-arm64-musl-0.3.219.tgz",
|
||||
"integrity": "sha512-yiZo+UBCp42FAYqSakgVj/g6LfTH0AklWqIZNEHfVDPaofledXdSu0QJM5yScWNg0hVMaNRXPt0DmuS1oIWW6g==",
|
||||
"version": "0.3.220",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64-musl/-/claude-agent-sdk-linux-arm64-musl-0.3.220.tgz",
|
||||
"integrity": "sha512-OHoZOZ8Cf2TBr6oXIXPwyvUxj9jrq2w8E4poA8dMpacXszcPSPiCQCMuuOh4aWJzfeJE1+TtWxhKMVb2csXyZQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -127,9 +127,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk-linux-x64": {
|
||||
"version": "0.3.219",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64/-/claude-agent-sdk-linux-x64-0.3.219.tgz",
|
||||
"integrity": "sha512-yzXhEsT5XcKa8Dc3sM4D1CQ92/6YGmsBbAhRAdw0PYNkG8x6wbHqfzYZS491Bdjry4tSWemNFtGPNkHiWVo3Hg==",
|
||||
"version": "0.3.220",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64/-/claude-agent-sdk-linux-x64-0.3.220.tgz",
|
||||
"integrity": "sha512-tkTJFnpR9VifvWX2fmkCAPkT6+8Wk/gVu8B5jsVekKZPiZoWRHmMXO30BnZn+f0TZhgYP+82PSX3S8crH1kn+w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -143,9 +143,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk-linux-x64-musl": {
|
||||
"version": "0.3.219",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64-musl/-/claude-agent-sdk-linux-x64-musl-0.3.219.tgz",
|
||||
"integrity": "sha512-IhfG57/XorWOQTB6BVdjEFPGH0LwOWO6HnAi+FNuCeiC+XRFl9QI9AKY43opS0gbvJWRobZO865tHX5j7Ou+ow==",
|
||||
"version": "0.3.220",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64-musl/-/claude-agent-sdk-linux-x64-musl-0.3.220.tgz",
|
||||
"integrity": "sha512-K+FWj+LcGhC1Z7wqeWoLxm1iemcba5xKpLLFVwYm4V6HyMx3ruYd/2r2TiQtjT+JWeNFWIys0ScHiItR6vWAiA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -159,9 +159,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk-win32-arm64": {
|
||||
"version": "0.3.219",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-arm64/-/claude-agent-sdk-win32-arm64-0.3.219.tgz",
|
||||
"integrity": "sha512-L/cAT27t3FGP4GlJ16WpXMtaeqDu9olpOlIaqqmjElQp5Lknd8alJ3NIY/SlRAtHDvm4WXug74wnfBOSlwppkg==",
|
||||
"version": "0.3.220",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-arm64/-/claude-agent-sdk-win32-arm64-0.3.220.tgz",
|
||||
"integrity": "sha512-rIwgq0UwQExWl6KrHUyC4w5KwpL9l6nd95aUTx6RitexaAuEw//xtfTVLnuE4hDDQZFkzEwpdKc3nxDWoGcUbA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -172,9 +172,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk-win32-x64": {
|
||||
"version": "0.3.219",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-x64/-/claude-agent-sdk-win32-x64-0.3.219.tgz",
|
||||
"integrity": "sha512-Fl8Rb9K64jbpC/omIF9y828LIvwRmm1zhZgO8zjalTpjZR/0C31Kl+5FwAS9KkXXUXwmdHSY+82e9dyvBrbIRw==",
|
||||
"version": "0.3.220",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-x64/-/claude-agent-sdk-win32-x64-0.3.220.tgz",
|
||||
"integrity": "sha512-MuOuXhbr66HlGaWXD2f3w0k2PsvmnbkwcUZ0dAe2poFLdl72GC2dapwwOBefxm9QmoNqk9+jmv/dSKGOVWyvLw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -185,9 +185,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@anthropic-ai/sdk": {
|
||||
"version": "0.114.0",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.114.0.tgz",
|
||||
"integrity": "sha512-zRFGTVMFEm77gt70Q0B+CDRKa9AcguydCcp6bD/dXWv8UkfsVFqCbaqU8+4B/pob3+Vy434LgtrBmwSvxfKr3g==",
|
||||
"version": "0.115.0",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.115.0.tgz",
|
||||
"integrity": "sha512-BJrFIVyjNuU8lfDyIJTvlRYzgQg+zEl78BxE7fq8esULsGz9IRQvGtW5spq3tydmtjQb/GFdooKGdGsetpx+lQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"json-schema-to-ts": "^3.1.1",
|
||||
@@ -306,9 +306,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/config-helpers": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.6.0.tgz",
|
||||
"integrity": "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==",
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz",
|
||||
"integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@@ -377,9 +377,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@hono/node-server": {
|
||||
"version": "1.19.15",
|
||||
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.15.tgz",
|
||||
"integrity": "sha512-Za2ai6TLdKjUvnur+eenO6nuYYipVAEhyCAdaV8IRvmU9kK8crOZUSYvIXn72E4f8fJqyAbpcJuTsYYmZp9Deg==",
|
||||
"version": "1.19.17",
|
||||
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.17.tgz",
|
||||
"integrity": "sha512-dSneS5qhiauZWGDCeK4o695Xd9nUNjviSZCMQrj10eetr8Uln1ucn6bbphOM6UynAMMtNIzZNSpL9vnASJwrPQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
@@ -1741,9 +1741,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "10.7.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-10.7.0.tgz",
|
||||
"integrity": "sha512-GVTD7s1vdIl6UYvAfriOPeY1Df8LIZjfofLvHwde+erDHGGuHyuM6xoxRxmHiebhYuD2p1vN4wWh0XzPARSGDQ==",
|
||||
"version": "10.8.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-10.8.0.tgz",
|
||||
"integrity": "sha512-nuKKvN+oIBO0koN7Tm7dlkmnkc21mtt0QJLwAKzjLq14y6lRTdVG36MZHJ8eQHwdJMwZbQNMlPOYedMq/oVJvQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
@@ -1753,7 +1753,7 @@
|
||||
"@eslint-community/eslint-utils": "^4.8.0",
|
||||
"@eslint-community/regexpp": "^4.12.2",
|
||||
"@eslint/config-array": "^0.23.5",
|
||||
"@eslint/config-helpers": "^0.6.0",
|
||||
"@eslint/config-helpers": "^0.7.0",
|
||||
"@eslint/core": "^1.2.1",
|
||||
"@eslint/plugin-kit": "^0.7.2",
|
||||
"@humanfs/node": "^0.16.6",
|
||||
@@ -1777,7 +1777,7 @@
|
||||
"imurmurhash": "^0.1.4",
|
||||
"is-glob": "^4.0.0",
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"minimatch": "^10.2.4",
|
||||
"minimatch": "^10.2.5",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.9.3"
|
||||
},
|
||||
@@ -2069,9 +2069,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/express-rate-limit": {
|
||||
"version": "8.6.0",
|
||||
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.6.0.tgz",
|
||||
"integrity": "sha512-XKJXDsASUOo0LLtFwW5hCcQGH0N4WQc/Rn8/Pvoia+TJFOkkFPvrtW9lZOeeNcxQJspvOIERMwiRLsVFlhHEkA==",
|
||||
"version": "8.6.1",
|
||||
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.6.1.tgz",
|
||||
"integrity": "sha512-0D493aP61w0TJ2A0wy27riRsO7FMQ7FK+KUHOKCSfPvYo0R55aiC6emCVgFUeShH0fq0ICPVzNcgoS+BsbXQCA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
@@ -2320,9 +2320,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/globals": {
|
||||
"version": "17.7.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-17.7.0.tgz",
|
||||
"integrity": "sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==",
|
||||
"version": "17.8.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-17.8.0.tgz",
|
||||
"integrity": "sha512-Zz/LMDZScFmkakeL2cTHzf+PbWKdpU3uclqkZT7TjDG58j5WPt0PpA+n9uPI24fZtlw07q0OtEi84K+umsRzqQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -2447,9 +2447,9 @@
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/ip-address": {
|
||||
"version": "10.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz",
|
||||
"integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==",
|
||||
"version": "10.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.3.1.tgz",
|
||||
"integrity": "sha512-1e9d3kb97NHJTIJDZW9rKqW2h6+dFa50Dy0fpPSMQp2ADje5gvKsXmdiK6dwY5t76TaTt5+P5N1Y/LoToIxP6g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
@@ -3193,9 +3193,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.22",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.22.tgz",
|
||||
"integrity": "sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==",
|
||||
"version": "8.5.23",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz",
|
||||
"integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
||||
@@ -64,19 +64,19 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@agentclientprotocol/sdk": "1.3.0",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.3.219",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.3.220",
|
||||
"zod": "^3.25.0 || ^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@anthropic-ai/sdk": "0.114.0",
|
||||
"@anthropic-ai/sdk": "0.115.0",
|
||||
"@eslint/js": "10.0.1",
|
||||
"@tsconfig/node22": "22.0.5",
|
||||
"@types/node": "26.1.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.65.0",
|
||||
"@typescript-eslint/parser": "8.65.0",
|
||||
"eslint": "10.7.0",
|
||||
"eslint": "10.8.0",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"globals": "17.7.0",
|
||||
"globals": "17.8.0",
|
||||
"prettier": "3.9.6",
|
||||
"ts-node": "10.9.2",
|
||||
"typescript": "6.0.3",
|
||||
|
||||
128
src/acp-agent.ts
128
src/acp-agent.ts
@@ -60,6 +60,7 @@ import {
|
||||
CanUseTool,
|
||||
deleteSession,
|
||||
EffortLevel,
|
||||
FastModeDisabledReason,
|
||||
FastModeState,
|
||||
getSessionInfo,
|
||||
getSessionMessages,
|
||||
@@ -438,6 +439,13 @@ type Session = {
|
||||
* user's intent so it persists across model switches; the Fast mode config
|
||||
* option is only surfaced while the selected model supports it. */
|
||||
fastModeEnabled: boolean;
|
||||
/** Why the SDK currently can't serve Fast mode, when the reason is one worth
|
||||
* telling the user about (see {@link FAST_MODE_UNAVAILABLE_EXPLANATIONS} —
|
||||
* routine states like the SDK's own opt-in requirement normalize to
|
||||
* `undefined`). Refreshed from every `fast_mode_disabled_reason` the SDK
|
||||
* reports on `system`/init and user-turn `result`s; surfaced in the Fast mode
|
||||
* option's description so a toggle that snaps back off explains itself. */
|
||||
fastModeDisabledReason?: FastModeDisabledReason;
|
||||
abortController: AbortController;
|
||||
/** Signal the consumer races `query.next()` against. Aborted by cancel()
|
||||
* (after a grace period) to force the active turn to settle "cancelled" when
|
||||
@@ -2501,7 +2509,12 @@ export class ClaudeAcpAgent {
|
||||
// A fresh `system`/init (e.g. after reinitialize) can carry an
|
||||
// updated Fast mode state; reconcile it with what we seeded at
|
||||
// session creation.
|
||||
await this.syncFastModeState(message.session_id, session, message.fast_mode_state);
|
||||
await this.syncFastModeState(
|
||||
message.session_id,
|
||||
session,
|
||||
message.fast_mode_state,
|
||||
message.fast_mode_disabled_reason,
|
||||
);
|
||||
break;
|
||||
case "status": {
|
||||
// These banners count as delivered text (via sendUpdate), so
|
||||
@@ -3011,7 +3024,12 @@ export class ClaudeAcpAgent {
|
||||
// an autonomous cycle's state lands on the next user turn's
|
||||
// result. Runs even when the turn errors or was cancelled.
|
||||
if (!isAutonomousResult) {
|
||||
await this.syncFastModeState(params.sessionId, session, message.fast_mode_state);
|
||||
await this.syncFastModeState(
|
||||
params.sessionId,
|
||||
session,
|
||||
message.fast_mode_state,
|
||||
message.fast_mode_disabled_reason,
|
||||
);
|
||||
}
|
||||
|
||||
// A user-turn result needs an active turn so its stop reason is
|
||||
@@ -4902,6 +4920,14 @@ export class ClaudeAcpAgent {
|
||||
session.modes = { ...session.modes, availableModes: newAvailableModes };
|
||||
}
|
||||
|
||||
// `model_not_allowed` described the model we just left, so it must not
|
||||
// follow us onto the new one; the remaining reasons are account- or
|
||||
// environment-scoped and stay true across a switch. Either way the next
|
||||
// init/result report refreshes this.
|
||||
if (session.fastModeDisabledReason === "model_not_allowed") {
|
||||
session.fastModeDisabledReason = undefined;
|
||||
}
|
||||
|
||||
// Rebuild config options since effort levels depend on the selected model
|
||||
const effortOpt = session.configOptions.find((o) => o.id === EFFORT_CONFIG_ID);
|
||||
const currentEffort =
|
||||
@@ -4920,6 +4946,7 @@ export class ClaudeAcpAgent {
|
||||
supported: newModelInfo?.supportsFastMode ?? false,
|
||||
enabled: session.fastModeEnabled,
|
||||
useBooleanOption: clientSupportsBooleanConfigOptions(this.clientCapabilities),
|
||||
disabledReason: session.fastModeDisabledReason,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -5018,6 +5045,7 @@ export class ClaudeAcpAgent {
|
||||
const refreshed = createFastModeConfigOption(
|
||||
enabled,
|
||||
clientSupportsBooleanConfigOptions(this.clientCapabilities),
|
||||
session.fastModeDisabledReason,
|
||||
);
|
||||
session.configOptions = session.configOptions.map((o) =>
|
||||
o.id === FAST_MODE_CONFIG_ID ? refreshed : o,
|
||||
@@ -5051,11 +5079,19 @@ export class ClaudeAcpAgent {
|
||||
* here).
|
||||
* - `cooldown`: a transient suspension of an already-enabled fast mode.
|
||||
* Leave the toggle as-is rather than flapping it — and never let a stray
|
||||
* cooldown spuriously enable a toggle the user has off. */
|
||||
* cooldown spuriously enable a toggle the user has off.
|
||||
*
|
||||
* `reason` is the SDK's `fast_mode_disabled_reason`, reported alongside the
|
||||
* state. Only explainable reasons are retained (see
|
||||
* {@link normalizeFastModeDisabledReason}), so the comparison below tracks
|
||||
* exactly what the user can see: a routine `sdk_opt_in_required` report on
|
||||
* every turn's result can't churn the option, while a real blocker updates
|
||||
* the description even when the toggle's own value is unchanged. */
|
||||
private async syncFastModeState(
|
||||
sessionId: string,
|
||||
session: Session,
|
||||
state: FastModeState | undefined,
|
||||
reason?: FastModeDisabledReason,
|
||||
): Promise<void> {
|
||||
if (state === undefined) {
|
||||
return;
|
||||
@@ -5067,11 +5103,31 @@ export class ClaudeAcpAgent {
|
||||
return;
|
||||
}
|
||||
const enabled = state === "on";
|
||||
if (enabled === session.fastModeEnabled) {
|
||||
// A reason only describes an off state; drop any that rides an `on` report
|
||||
// so it can't decorate the option the next time fast mode goes off.
|
||||
const nextReason = enabled ? undefined : normalizeFastModeDisabledReason(reason);
|
||||
if (enabled === session.fastModeEnabled && nextReason === session.fastModeDisabledReason) {
|
||||
return;
|
||||
}
|
||||
// The user asked for Fast mode and the SDK is telling us it can't serve it.
|
||||
// The description carries the same explanation, but a toggle silently
|
||||
// snapping back is the case worth saying out loud once, at the flip.
|
||||
const explain = session.fastModeEnabled && !enabled && nextReason !== undefined;
|
||||
session.fastModeEnabled = enabled;
|
||||
session.fastModeDisabledReason = nextReason;
|
||||
this.refreshFastModeOption(session, enabled);
|
||||
if (explain) {
|
||||
await this.client.sessionUpdate({
|
||||
sessionId,
|
||||
update: {
|
||||
sessionUpdate: "agent_message_chunk",
|
||||
content: {
|
||||
type: "text",
|
||||
text: `**Fast mode turned off:** ${FAST_MODE_UNAVAILABLE_EXPLANATIONS[nextReason]}.`,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
await this.client.sessionUpdate({
|
||||
sessionId,
|
||||
update: {
|
||||
@@ -5581,10 +5637,18 @@ export class ClaudeAcpAgent {
|
||||
const fastModeEnabled =
|
||||
initializationResult.fast_mode_state !== undefined &&
|
||||
fastModeStateEnabled(initializationResult.fast_mode_state);
|
||||
// `fast_mode_disabled_reason` reflects the post-switch model since SDK
|
||||
// 0.3.219 (the initialize response used to answer from the spawn-time
|
||||
// model). A fresh SDK session reports `sdk_opt_in_required` — the toggle IS
|
||||
// the opt-in — which normalizes away, so only real blockers are retained.
|
||||
const fastModeDisabledReason = fastModeEnabled
|
||||
? undefined
|
||||
: normalizeFastModeDisabledReason(initializationResult.fast_mode_disabled_reason);
|
||||
const fastMode: FastModeOptionState = {
|
||||
supported: currentModelInfo?.supportsFastMode ?? false,
|
||||
enabled: fastModeEnabled,
|
||||
useBooleanOption: clientSupportsBooleanConfigOptions(this.clientCapabilities),
|
||||
disabledReason: fastModeDisabledReason,
|
||||
};
|
||||
|
||||
const configOptions = buildConfigOptions(
|
||||
@@ -5660,6 +5724,7 @@ export class ClaudeAcpAgent {
|
||||
agents,
|
||||
currentAgent,
|
||||
fastModeEnabled,
|
||||
fastModeDisabledReason,
|
||||
abortController,
|
||||
emitRawSDKMessages: sessionMeta?.claudeCode?.emitRawSDKMessages ?? false,
|
||||
forwardSubagentText,
|
||||
@@ -5967,6 +6032,36 @@ export function fastModeStateEnabled(state: FastModeState): boolean {
|
||||
return state !== "off";
|
||||
}
|
||||
|
||||
/** User-facing explanations for the SDK's `fast_mode_disabled_reason` values
|
||||
* that a user can act on (or at least wants to know about). Deliberately
|
||||
* partial — the omitted reasons are not worth surfacing:
|
||||
* - `sdk_opt_in_required`: every SDK session starts here (the toggle IS the
|
||||
* opt-in), so it describes the default, not a problem.
|
||||
* - `preference`: the user turned Fast mode off themselves.
|
||||
* - `pending`: eligibility is still resolving; the next report supersedes it.
|
||||
* - `unknown`: nothing meaningful to say.
|
||||
* Unknown future reasons fall through the same way (open set — the SDK's docs
|
||||
* say to ignore values you don't handle). */
|
||||
const FAST_MODE_UNAVAILABLE_EXPLANATIONS: Partial<Record<FastModeDisabledReason, string>> = {
|
||||
free: "not available on the free plan",
|
||||
extra_usage_disabled: "requires extra usage to be enabled for this account",
|
||||
model_not_allowed: "not available for the selected model",
|
||||
not_first_party: "not available on this API provider",
|
||||
disabled_by_env: "disabled by environment configuration",
|
||||
network_error: "eligibility could not be verified (network error)",
|
||||
};
|
||||
|
||||
/** Normalize an SDK-reported `fast_mode_disabled_reason` to the one we retain:
|
||||
* a reason we have an explanation for, else `undefined`. Keeping only
|
||||
* explainable reasons means state comparisons (see `syncFastModeState`) track
|
||||
* exactly what the user can see, so routine reports like
|
||||
* `sdk_opt_in_required` never churn the config option. */
|
||||
export function normalizeFastModeDisabledReason(
|
||||
reason: FastModeDisabledReason | undefined,
|
||||
): FastModeDisabledReason | undefined {
|
||||
return reason && FAST_MODE_UNAVAILABLE_EXPLANATIONS[reason] ? reason : undefined;
|
||||
}
|
||||
|
||||
/** Whether the Client advertised support for boolean session config options
|
||||
* (`session.configOptions.boolean`). Agents MUST only send `type: "boolean"`
|
||||
* config options to Clients that opt in; otherwise we fall back to a `select`.
|
||||
@@ -5980,15 +6075,25 @@ export function clientSupportsBooleanConfigOptions(
|
||||
/** Build the Fast mode config option. When the Client supports boolean config
|
||||
* options we expose a native `type: "boolean"` toggle; otherwise we degrade to
|
||||
* a two-value `select` ("on"/"off") so older Clients still get a usable
|
||||
* control. */
|
||||
* control.
|
||||
*
|
||||
* `disabledReason` (the SDK's `fast_mode_disabled_reason`) is folded into the
|
||||
* description while the toggle reads off, so a user whose account or provider
|
||||
* can't serve Fast mode sees why instead of a switch that silently refuses to
|
||||
* stay on. Ignored while enabled: a reason reported alongside an `on`/`cooldown`
|
||||
* state isn't blocking anything right now. */
|
||||
export function createFastModeConfigOption(
|
||||
enabled: boolean,
|
||||
useBooleanOption: boolean,
|
||||
disabledReason?: FastModeDisabledReason,
|
||||
): SessionConfigOption {
|
||||
const explanation = enabled
|
||||
? undefined
|
||||
: disabledReason && FAST_MODE_UNAVAILABLE_EXPLANATIONS[disabledReason];
|
||||
const base = {
|
||||
id: FAST_MODE_CONFIG_ID,
|
||||
name: "Fast mode",
|
||||
description: FAST_MODE_DESCRIPTION,
|
||||
description: explanation ? `${FAST_MODE_DESCRIPTION} — ${explanation}` : FAST_MODE_DESCRIPTION,
|
||||
category: "model_config",
|
||||
} as const;
|
||||
|
||||
@@ -6031,6 +6136,9 @@ export type FastModeOptionState = {
|
||||
enabled: boolean;
|
||||
/** Whether the Client opted into boolean config options. */
|
||||
useBooleanOption: boolean;
|
||||
/** Latest explainable `fast_mode_disabled_reason`, folded into the option's
|
||||
* description while the toggle reads off. */
|
||||
disabledReason?: FastModeDisabledReason;
|
||||
};
|
||||
|
||||
export function buildConfigOptions(
|
||||
@@ -6108,7 +6216,13 @@ export function buildConfigOptions(
|
||||
// option renders as a native boolean toggle for Clients that opted in, and a
|
||||
// two-value select otherwise.
|
||||
if (fastMode?.supported) {
|
||||
options.push(createFastModeConfigOption(fastMode.enabled, fastMode.useBooleanOption));
|
||||
options.push(
|
||||
createFastModeConfigOption(
|
||||
fastMode.enabled,
|
||||
fastMode.useBooleanOption,
|
||||
fastMode.disabledReason,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Only surface the Agent picker when there's a real choice — i.e. the user
|
||||
|
||||
@@ -975,6 +975,7 @@ describe("tool conversions", () => {
|
||||
inference_geo: null,
|
||||
iterations: null,
|
||||
output_tokens_details: null,
|
||||
fallback_credit: null,
|
||||
speed: null,
|
||||
},
|
||||
context_management: null,
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import type { ClientCapabilities, SessionNotification } from "@agentclientprotocol/sdk";
|
||||
import type { ModelInfo } from "@anthropic-ai/claude-agent-sdk";
|
||||
import type { FastModeDisabledReason, ModelInfo } from "@anthropic-ai/claude-agent-sdk";
|
||||
import {
|
||||
buildConfigOptions,
|
||||
clientSupportsBooleanConfigOptions,
|
||||
createFastModeConfigOption,
|
||||
fastModeStateEnabled,
|
||||
normalizeFastModeDisabledReason,
|
||||
resolveFastModeEnabled,
|
||||
FAST_MODE_CONFIG_ID,
|
||||
FAST_MODE_ON,
|
||||
@@ -42,6 +43,28 @@ describe("createFastModeConfigOption", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("explains a blocking disabled reason while the toggle reads off", () => {
|
||||
const option = createFastModeConfigOption(false, true, "free");
|
||||
expect(option.description).toBe(
|
||||
"Faster responses on supported models — not available on the free plan",
|
||||
);
|
||||
});
|
||||
|
||||
it("ignores routine and on-state reasons", () => {
|
||||
// Every SDK session starts at `sdk_opt_in_required` — the toggle IS the
|
||||
// opt-in, so it must not read as a blocker.
|
||||
expect(createFastModeConfigOption(false, true, "sdk_opt_in_required").description).toBe(
|
||||
"Faster responses on supported models",
|
||||
);
|
||||
expect(createFastModeConfigOption(false, true, "preference").description).toBe(
|
||||
"Faster responses on supported models",
|
||||
);
|
||||
// A reason riding an `on` state isn't blocking anything right now.
|
||||
expect(createFastModeConfigOption(true, true, "free").description).toBe(
|
||||
"Faster responses on supported models",
|
||||
);
|
||||
});
|
||||
|
||||
it("falls back to an on/off select when the client did not opt in", () => {
|
||||
const option = createFastModeConfigOption(false, false);
|
||||
expect(option).toMatchObject({
|
||||
@@ -104,6 +127,28 @@ describe("fastModeStateEnabled", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("normalizeFastModeDisabledReason", () => {
|
||||
it("retains only reasons we have an explanation for", () => {
|
||||
expect(normalizeFastModeDisabledReason("free")).toBe("free");
|
||||
expect(normalizeFastModeDisabledReason("extra_usage_disabled")).toBe("extra_usage_disabled");
|
||||
expect(normalizeFastModeDisabledReason("model_not_allowed")).toBe("model_not_allowed");
|
||||
expect(normalizeFastModeDisabledReason("not_first_party")).toBe("not_first_party");
|
||||
expect(normalizeFastModeDisabledReason("disabled_by_env")).toBe("disabled_by_env");
|
||||
expect(normalizeFastModeDisabledReason("network_error")).toBe("network_error");
|
||||
});
|
||||
|
||||
it("drops routine states and unknown values", () => {
|
||||
expect(normalizeFastModeDisabledReason("sdk_opt_in_required")).toBeUndefined();
|
||||
expect(normalizeFastModeDisabledReason("preference")).toBeUndefined();
|
||||
expect(normalizeFastModeDisabledReason("pending")).toBeUndefined();
|
||||
expect(normalizeFastModeDisabledReason("unknown")).toBeUndefined();
|
||||
expect(normalizeFastModeDisabledReason(undefined)).toBeUndefined();
|
||||
expect(
|
||||
normalizeFastModeDisabledReason("some_future_reason" as FastModeDisabledReason),
|
||||
).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildConfigOptions Fast mode", () => {
|
||||
it("omits the Fast mode option when the model does not support it", () => {
|
||||
const options = buildConfigOptions(MODES, MODELS, MODEL_INFOS, undefined, [], "default", {
|
||||
@@ -249,6 +294,7 @@ describe("syncFastModeState (SDK-driven state changes)", () => {
|
||||
const session = {
|
||||
query: {},
|
||||
fastModeEnabled: opts.fastModeEnabled,
|
||||
fastModeDisabledReason: undefined as FastModeDisabledReason | undefined,
|
||||
configOptions: opts.withOption
|
||||
? [createFastModeConfigOption(opts.fastModeEnabled, true)]
|
||||
: [],
|
||||
@@ -261,6 +307,7 @@ describe("syncFastModeState (SDK-driven state changes)", () => {
|
||||
sessionId: string,
|
||||
session: unknown,
|
||||
state: string | undefined,
|
||||
reason?: FastModeDisabledReason,
|
||||
) => Promise<void>;
|
||||
}
|
||||
).syncFastModeState.bind(agent);
|
||||
@@ -319,10 +366,65 @@ describe("syncFastModeState (SDK-driven state changes)", () => {
|
||||
|
||||
await sync(SESSION_ID, session, undefined);
|
||||
await sync(SESSION_ID, session, "off");
|
||||
// A routine reason normalizes away, so it's still "unchanged" — an
|
||||
// `sdk_opt_in_required` on every turn's result must not churn the option.
|
||||
await sync(SESSION_ID, session, "off", "sdk_opt_in_required");
|
||||
|
||||
expect(sessionUpdates).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("explains a blocking reason once when the SDK refuses a toggle the user turned on", async () => {
|
||||
const { sync, session, sessionUpdates } = setup({ fastModeEnabled: true, withOption: true });
|
||||
|
||||
await sync(SESSION_ID, session, "off", "extra_usage_disabled");
|
||||
|
||||
expect(session.fastModeEnabled).toBe(false);
|
||||
expect(session.fastModeDisabledReason).toBe("extra_usage_disabled");
|
||||
expect(sessionUpdates).toHaveLength(2);
|
||||
expect(sessionUpdates[0].update).toEqual({
|
||||
sessionUpdate: "agent_message_chunk",
|
||||
content: {
|
||||
type: "text",
|
||||
text: "**Fast mode turned off:** requires extra usage to be enabled for this account.",
|
||||
},
|
||||
});
|
||||
expect(sessionUpdates[1].update).toMatchObject({ sessionUpdate: "config_option_update" });
|
||||
expect(session.configOptions).toContainEqual(
|
||||
createFastModeConfigOption(false, true, "extra_usage_disabled"),
|
||||
);
|
||||
|
||||
// The same report again changes nothing the user can see: no repeat notice.
|
||||
await sync(SESSION_ID, session, "off", "extra_usage_disabled");
|
||||
expect(sessionUpdates).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("updates the description when only the reason changes", async () => {
|
||||
const { sync, session, sessionUpdates } = setup({ fastModeEnabled: false, withOption: true });
|
||||
|
||||
await sync(SESSION_ID, session, "off", "not_first_party");
|
||||
|
||||
expect(session.fastModeEnabled).toBe(false);
|
||||
// The toggle was already off, so the flip-time notice doesn't fire — only
|
||||
// the description carries the explanation.
|
||||
expect(sessionUpdates).toHaveLength(1);
|
||||
expect(sessionUpdates[0].update).toMatchObject({ sessionUpdate: "config_option_update" });
|
||||
expect(session.configOptions).toContainEqual(
|
||||
createFastModeConfigOption(false, true, "not_first_party"),
|
||||
);
|
||||
});
|
||||
|
||||
it("drops a retained reason once fast mode comes back on", async () => {
|
||||
const { sync, session } = setup({ fastModeEnabled: false, withOption: true });
|
||||
|
||||
await sync(SESSION_ID, session, "off", "network_error");
|
||||
expect(session.fastModeDisabledReason).toBe("network_error");
|
||||
|
||||
await sync(SESSION_ID, session, "on");
|
||||
expect(session.fastModeEnabled).toBe(true);
|
||||
expect(session.fastModeDisabledReason).toBeUndefined();
|
||||
expect(session.configOptions).toContainEqual(createFastModeConfigOption(true, true));
|
||||
});
|
||||
|
||||
it("preserves the retained setting (no clobber) when the model has no Fast mode option", async () => {
|
||||
// Model without fast support: the SDK reports a capability-driven state, not
|
||||
// the user's intent. We must leave session.fastModeEnabled untouched so it's
|
||||
|
||||
Reference in New Issue
Block a user