diff --git a/content/.metadata.json b/content/.metadata.json index 63a53d3a59..6e71b58284 100644 --- a/content/.metadata.json +++ b/content/.metadata.json @@ -1,7 +1,7 @@ { "metadata": { "version": "2.0", - "fetch_date": "2026-11-02T20:33:15.763530Z", + "fetch_date": "2026-11-03T07:20:38.396726Z", "section": "all" }, "items": [ @@ -317,22 +317,22 @@ "url": "https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-sdk", "status": "success", "path": "en/agents-and-tools/tool-use/browser-use-sdk.md", - "sha256": "6c94dd90491c1907e981fe955c55d7f69bda0026c6b0acdc2482180d343bba3f", - "size": 83774 + "sha256": "fe65ddd97d764eaba93436644c68c1926929aa073b4f8b52c533eceba94c0c84", + "size": 85451 }, { "url": "https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool", "status": "success", "path": "en/agents-and-tools/tool-use/computer-use-tool.md", - "sha256": "13ef64fd327bce8918f8c4e12c3125e68cfdf479b2f6ed887b45ab32067b8c98", - "size": 135234 + "sha256": "314c63f31ab78170a7fc7e7844aa51c17db09e49ee279107e663a24e46206eda", + "size": 128553 }, { "url": "https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool", "status": "success", "path": "en/agents-and-tools/tool-use/browser-use-tool.md", - "sha256": "01b03d70d229e7a9836396b8f1c98b30262fb3472c28b6bc1988236eeeba7983", - "size": 113809 + "sha256": "93423507861050df75a620e37a5c26e290a84fdfff2e03d63dbaed047f6f5ef2", + "size": 115258 }, { "url": "https://platform.claude.com/docs/en/agents-and-tools/tool-use/troubleshooting-tool-use", @@ -422,8 +422,8 @@ "url": "https://platform.claude.com/docs/en/build-with-claude/cache-diagnostics", "status": "success", "path": "en/build-with-claude/cache-diagnostics.md", - "sha256": "04b03be7e468842639f70899d8db6ed74b3912438201502c3423b3f2e1ae6ca8", - "size": 48841 + "sha256": "7d8137a4bbc941bee55c6592e8f9a96a48e00ded72bd57238dff96bd65ce5383", + "size": 48112 }, { "url": "https://platform.claude.com/docs/en/build-with-claude/token-counting", @@ -618,29 +618,29 @@ "url": "https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock", "status": "success", "path": "en/build-with-claude/claude-in-amazon-bedrock.md", - "sha256": "b6813ccaea317b78ffb97d6d05f4abb4985ac875821bcc2d760986faf709993d", - "size": 22790 + "sha256": "ef04bc5c03e4698a428ed0883f5cafebdfeae394212781a7d7e5dd16e5a8b1a7", + "size": 22524 }, { "url": "https://platform.claude.com/docs/en/build-with-claude/claude-on-amazon-bedrock-legacy", "status": "success", "path": "en/build-with-claude/claude-on-amazon-bedrock-legacy.md", - "sha256": "11b088c40d3b01f3fc0d48257d6bbde2357eee30e94a51e078addf41dd0a2513", - "size": 42331 + "sha256": "4964bd79258744efc81d294bad0249d10cadd597bbdcfd7ac593384cabd0cf92", + "size": 42594 }, { "url": "https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws", "status": "success", "path": "en/build-with-claude/claude-platform-on-aws.md", - "sha256": "67af475170fbfb339bb11b0917e07373c8605198320d5603e3b9c961f73a3203", - "size": 103219 + "sha256": "cffb688848cc1612b3a6917ee34628de6cd1ce1ac1e854516cd8bce401a4dc23", + "size": 102671 }, { "url": "https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry", "status": "success", "path": "en/build-with-claude/claude-in-microsoft-foundry.md", - "sha256": "b0a6ce98e1b59379f50dae61c262a7e143c81094cdc318a9574f9fd66ae0c794", - "size": 39024 + "sha256": "d3e73f3d4a4087e1b8422f1f06b780ce5cda38eb34368b589ea3ea1b88fd0786", + "size": 38500 }, { "url": "https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/overview", @@ -821,8 +821,8 @@ "url": "https://platform.claude.com/docs/en/managed-agents/events-and-streaming", "status": "success", "path": "en/managed-agents/events-and-streaming.md", - "sha256": "56654291d969e71f318ac212ae0083a8e265b113fd5a8e5e52fa6b461ebebe04", - "size": 65611 + "sha256": "cc905ce47321db01fcf8262771642e5325bff6eacced7bf464c50f2a5105ea59", + "size": 64769 }, { "url": "https://platform.claude.com/docs/en/managed-agents/event-deltas", @@ -905,22 +905,22 @@ "url": "https://platform.claude.com/docs/en/managed-agents/session-threads", "status": "success", "path": "en/managed-agents/session-threads.md", - "sha256": "bc7bc7cf6b17dde99396378fa331f39fe7103562825f46ef0397af3385251534", - "size": 39123 + "sha256": "7f5da58cea8de0b9c6b669a634947299c06c13b6369b13c1a9222bc2a3323ce3", + "size": 38927 }, { "url": "https://platform.claude.com/docs/en/managed-agents/workflow-runs", "status": "success", "path": "en/managed-agents/workflow-runs.md", - "sha256": "b7983a2c0e5d7361d657eb128f8594c8475356b600aab21bb1bd98792ac0c136", - "size": 78898 + "sha256": "33a8f337fcc8f7c03385b8ea6b915bdb1068f0e31ee4da385fe6b230990488a9", + "size": 78872 }, { "url": "https://platform.claude.com/docs/en/managed-agents/scheduled-deployments", "status": "success", "path": "en/managed-agents/scheduled-deployments.md", - "sha256": "3da531826aed9db23d6e0a2b197d315ecc446d945eea9ab1aeece663c75e2581", - "size": 32371 + "sha256": "b360760857e8436f6fb5a42f637d89137abe3a79c447b985a414f15a3f9d6d0f", + "size": 32137 }, { "url": "https://platform.claude.com/docs/en/managed-agents/secure-deployment", @@ -971,6 +971,13 @@ "sha256": "0f7eef2db1c0650072f8fdf2166e31f09c9e67d585c6c30699ba08a665d9539b", "size": 185502 }, + { + "url": "https://platform.claude.com/docs/en/manage-claude/claude-tag-api", + "status": "success", + "path": "en/manage-claude/claude-tag-api.md", + "sha256": "1e841031717938cc42839dba794f459c300b9bdb675f8e9e581c225fe49c3014", + "size": 127198 + }, { "url": "https://platform.claude.com/docs/en/manage-claude/workspaces", "status": "success", @@ -1206,7 +1213,7 @@ "url": "https://platform.claude.com/docs/en/manage-claude/cmek-coverage-claude-enterprise", "status": "success", "path": "en/manage-claude/cmek-coverage-claude-enterprise.md", - "sha256": "9cf379e614e2c92582c7019105d85742e279e1fbbd2f6725cf1ed1de7bc81ba2", + "sha256": "5f5b8a5db08d39997635cc1be609ed98825b92900475a08c4c7d70b7012258aa", "size": 11438 }, { @@ -1276,8 +1283,8 @@ "url": "https://platform.claude.com/docs/en/manage-claude/inference-hooks-configuration", "status": "success", "path": "en/manage-claude/inference-hooks-configuration.md", - "sha256": "4f31c952b42a4d31b2d2c2d5aaeab23afc05a8fe9f7bd5f7f61fe2709ac825f0", - "size": 24862 + "sha256": "49119570fa5b901ad09d2464776bd4ba127037c4aed44c646bd8b481e016864e", + "size": 24866 }, { "url": "https://platform.claude.com/docs/en/manage-claude/inference-hooks-endpoint", @@ -1311,15 +1318,15 @@ "url": "https://platform.claude.com/docs/en/manage-claude/compliance-content-data", "status": "success", "path": "en/manage-claude/compliance-content-data.md", - "sha256": "bdc1e8e499c2b3596659d09b221c340ee2c0e60a463867093aeae87cc2c78fdd", - "size": 26305 + "sha256": "9a07f45f4d4025fa75e44e14d7d945680085f2523d1b14837ae3c46496282dcd", + "size": 27124 }, { "url": "https://platform.claude.com/docs/en/manage-claude/compliance-sessions", "status": "success", "path": "en/manage-claude/compliance-sessions.md", - "sha256": "c766885ce9f20f78f22a6906fb7f4da0e231470ee27a6709dd1ef529a46deafd", - "size": 54757 + "sha256": "df79b4b8f8659196d19f23dc2c4cfded744a0a64af4f2872262a0a7571e04ef0", + "size": 54767 }, { "url": "https://platform.claude.com/docs/en/manage-claude/compliance-org-data", @@ -1339,15 +1346,15 @@ "url": "https://platform.claude.com/docs/en/manage-claude/compliance-errors", "status": "success", "path": "en/manage-claude/compliance-errors.md", - "sha256": "0ac10e4a68905714ea3f2adba078480d2f201fdbd2df0735a3d80ae1fb74cceb", - "size": 55988 + "sha256": "14e136c0368f6cf1f9f291506818d92f3474a4606c67d4911cf47e05c031c060", + "size": 57008 }, { "url": "https://platform.claude.com/docs/en/manage-claude/compliance-faq", "status": "success", "path": "en/manage-claude/compliance-faq.md", - "sha256": "c2dfc3762b02e2fd81b59ff293496ec554f0f9605f4c6cb64281cb8dfd5c1472", - "size": 27479 + "sha256": "5b913b1807a4e93579a5062e59dfbec662cfd36f83d1d3de7ee12a34e21d73a3", + "size": 27525 }, { "url": "https://platform.claude.com/docs/en/about-claude/use-case-guides/overview", @@ -1437,8 +1444,8 @@ "url": "https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-opus-4-8", "status": "success", "path": "en/build-with-claude/prompt-engineering/prompting-claude-opus-4-8.md", - "sha256": "7542c3f68ec38086ea9e72a62d3f941404bca4aa9a13911232142064349e5fc1", - "size": 16645 + "sha256": "5197c4ed9e4be7a9b3c56bdf52896d7cd3d7272f30dddb7c4a4c8a6fa7e09063", + "size": 16558 }, { "url": "https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-sonnet-5-5", @@ -1451,8 +1458,8 @@ "url": "https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-sonnet-5", "status": "success", "path": "en/build-with-claude/prompt-engineering/prompting-claude-sonnet-5.md", - "sha256": "2932ddb74855554cef42cbadf06e2550405b5bc45a799ce0a5ac90ce773af8db", - "size": 16081 + "sha256": "e066cc7bd1cdcb93696e3724882fc5b76999c0e29f0138ca83f2ded27e68d48c", + "size": 15994 }, { "url": "https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-haiku-5-5", @@ -1549,43 +1556,43 @@ "url": "https://platform.claude.com/docs/en/models/opus-5-5/overview", "status": "success", "path": "en/models/opus-5-5/overview.md", - "sha256": "54d74c77b6f8e9e7adf64511adc747de84ed98577964e093035eb52ed899a5da", - "size": 16221 + "sha256": "1318dc1003cf4e749364b7873ff22025c6209ebd664e8c8a208619be5ec8749a", + "size": 16144 }, { "url": "https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5", "status": "success", "path": "en/models/opus-5-5/whats-new-opus-5-5.md", - "sha256": "42360dc4cce9dd45364bcfa0c2c2c6d10c1fce846b9927a74b6907da196227e7", - "size": 22790 + "sha256": "12af9fc27b88efa7c99c09e733eddb78cc3a0b9eba0d6f96853be2b1200962ad", + "size": 21818 }, { "url": "https://platform.claude.com/docs/en/models/opus-5-5/migration-guide", "status": "success", "path": "en/models/opus-5-5/migration-guide.md", - "sha256": "6a1bff4d8f06ec1304752324f7d4469665f73fe179254daf7e45e0c1764cc5ed", - "size": 90758 + "sha256": "f8b86c7639c7ef4e741d5b30fe558a3deea1460a1cfea784d2353d03d860d6d6", + "size": 89911 }, { "url": "https://platform.claude.com/docs/en/models/sonnet-5-5/overview", "status": "success", "path": "en/models/sonnet-5-5/overview.md", - "sha256": "97d424f09d73bd096f7282d26d2da392f343ca4865d541226dc4c4e606979c2d", - "size": 16449 + "sha256": "464960f9ab69b638751ba5ffb17c0b5dd0d0f95b99c238d76fa777769262c28c", + "size": 16367 }, { "url": "https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5", "status": "success", "path": "en/models/sonnet-5-5/whats-new-sonnet-5-5.md", - "sha256": "08b0073077cbdf42c47b3165d6c444ca39f55f9a0ab7466854f3ee8bdbe5ac42", - "size": 23883 + "sha256": "3fe366f02f5728ea5ce4996b0343d99575eff4a356211e8d2e26f7884f8fdcea", + "size": 23042 }, { "url": "https://platform.claude.com/docs/en/models/sonnet-5-5/migration-guide", "status": "success", "path": "en/models/sonnet-5-5/migration-guide.md", - "sha256": "7f550855cb3d4f732c0e237ad0fb2caf001c430e10d318c0a9c52db5396efbbf", - "size": 55183 + "sha256": "ed9bce025122c829104274436308dd007fcc12807b6a1fe432f0016865c8b52b", + "size": 54317 }, { "url": "https://platform.claude.com/docs/en/models/haiku-5-5/overview", @@ -1598,15 +1605,15 @@ "url": "https://platform.claude.com/docs/en/models/haiku-5-5/whats-new-haiku-5-5", "status": "success", "path": "en/models/haiku-5-5/whats-new-haiku-5-5.md", - "sha256": "0de44c3c67e38f1001ff2d5e13e94a88a7b8d2d0e6322e48cc39a197fff8429a", - "size": 13035 + "sha256": "191496380d56ee22ef44187985209757b19caea79959f0c3a363873c5859b3e0", + "size": 12027 }, { "url": "https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide", "status": "success", "path": "en/models/haiku-5-5/migration-guide.md", - "sha256": "17df7559164e9e61043027dbed2805d05155b06c76fd748f34270e772bcd8828", - "size": 18800 + "sha256": "3791fe3b313b12eaa501077ae0f971cc3b0346edc225877afc9eef1f47b4689e", + "size": 18327 }, { "url": "https://platform.claude.com/docs/en/models/mythos-5-1/overview", @@ -1934,8 +1941,8 @@ "url": "https://platform.claude.com/docs/en/cli-sdks-libraries/cli/using", "status": "success", "path": "en/cli-sdks-libraries/cli/using.md", - "sha256": "a804fbda5ae924554fa50832b0632a92903781eaaa2a077b3a1d8b0e462fdf7f", - "size": 14067 + "sha256": "0b626973b5583e74801e78a5cc017e89adc57326727dfcfbddbd5e93c574b4df", + "size": 14106 }, { "url": "https://platform.claude.com/docs/en/cli-sdks-libraries/cli/scripting", @@ -2046,8 +2053,8 @@ "url": "https://platform.claude.com/docs/en/api/errors", "status": "success", "path": "en/api/errors.md", - "sha256": "47fe2413900d447a711e786ea814c81491c29c783f13e389c19ea60bf3424856", - "size": 33857 + "sha256": "a292d24bf93cf4c8ab2e9e8ef7816b4e686cfa79c33e8344c5d50c12f22aa856", + "size": 34088 }, { "url": "https://platform.claude.com/docs/en/api/opentelemetry/spans", @@ -2102,8 +2109,8 @@ "url": "https://platform.claude.com/docs/en/api/ip-addresses", "status": "success", "path": "en/api/ip-addresses.md", - "sha256": "a8d2aa1e5a61e7001ec23c9ff22ffaa5bd161c5668692a31d00bcb0fede046ff", - "size": 1458 + "sha256": "5e1e98b115594be6dda2b8070d8dfff0d5f47fdf47ffbfb299d91a018d72f98a", + "size": 1496 }, { "url": "https://platform.claude.com/docs/en/api/supported-regions", @@ -2130,8 +2137,8 @@ "url": "https://platform.claude.com/docs/en/release-notes/overview", "status": "success", "path": "en/release-notes/overview.md", - "sha256": "c684dadcf02c4ff5185d50dac64f1888bd4dd12fc59ccf6e60457747ec8f96b2", - "size": 136892 + "sha256": "ff0b057fa3d24c1096b1c9d2ffe311842bf56f6971c3c13147b550177ab431cc", + "size": 136891 }, { "url": "https://platform.claude.com/docs/en/api/completions", @@ -5920,13 +5927,6 @@ "sha256": "e89e8ca4f16ce31e01199fddba2d8b383a8dde38162f9ad03825fb92b04e3bf0", "size": 60128 }, - { - "url": "https://platform.claude.com/docs/en/manage-claude/claude-tag-api", - "status": "success", - "path": "en/manage-claude/claude-tag-api.md", - "sha256": "1e841031717938cc42839dba794f459c300b9bdb675f8e9e581c225fe49c3014", - "size": 127198 - }, { "url": "https://code.claude.com/docs/en/overview", "status": "success", @@ -5945,8 +5945,8 @@ "url": "https://code.claude.com/docs/en/changelog", "status": "success", "path": "en/docs/claude-code/changelog.md", - "sha256": "ec19d4b5c059d33f730995355a02b6e18ccd2cf4abcce0e77d875f8c5ed988ad", - "size": 1151295 + "sha256": "8169dacc3c468cb764d22bcfdc5031b8c75c93e8e626b05de88c6972c1a683b4", + "size": 1163665 }, { "url": "https://code.claude.com/docs/en/how-claude-code-works", @@ -5987,8 +5987,8 @@ "url": "https://code.claude.com/docs/en/memory", "status": "success", "path": "en/docs/claude-code/memory.md", - "sha256": "f19bb5aa909fe5588d523cf302a0e15ed5950ca689fbb73bd932c315ec764a49", - "size": 55180 + "sha256": "24b2a7235ba423a8a6994b6da1fc7ce33223bb03ab1b1c7c6b3f84eb1df7a5a2", + "size": 55247 }, { "url": "https://code.claude.com/docs/en/sessions", @@ -6029,8 +6029,8 @@ "url": "https://code.claude.com/docs/en/remote-control", "status": "success", "path": "en/docs/claude-code/remote-control.md", - "sha256": "8e9028c51562c4cd2d07508fd41ae51bd80751bbd8882f89aaaa477309835f34", - "size": 63856 + "sha256": "1e78d3071eb94a98f79150ae3dd01b99e40c2d3eee48841beff0849517236f59", + "size": 63820 }, { "url": "https://code.claude.com/docs/en/claude-projects", @@ -6071,8 +6071,8 @@ "url": "https://code.claude.com/docs/en/jetbrains", "status": "success", "path": "en/docs/claude-code/jetbrains.md", - "sha256": "1af2bb66618140841118e0cff7149bcf6223d1c003a6fbc1f934ff1377f9a1da", - "size": 12531 + "sha256": "488a0cba98c2e6dfcd168cbe39bff43c5e374e02b1889ec708a712ec38992a01", + "size": 12737 }, { "url": "https://code.claude.com/docs/en/slack", @@ -6099,8 +6099,8 @@ "url": "https://code.claude.com/docs/en/routines", "status": "success", "path": "en/docs/claude-code/routines.md", - "sha256": "a5798b95a676d1062c7dd2278d785583fc70690ef36f5e39a14090e759cf08d0", - "size": 50243 + "sha256": "197f51492cb353d49eae277a0797ed5cd52dcb9978c0b720b26b0f0df41ab7d2", + "size": 50325 }, { "url": "https://code.claude.com/docs/en/desktop-quickstart", @@ -6113,8 +6113,8 @@ "url": "https://code.claude.com/docs/en/desktop", "status": "success", "path": "en/docs/claude-code/desktop.md", - "sha256": "cac6a537e446076c84954dd7264ca62a5ffff40928db1cfa608adaf8c6e564d4", - "size": 211526 + "sha256": "f21b9a0e4de35eb5c415dd6e19ed263810e318ee62f03260d3359be3ce01f051", + "size": 213436 }, { "url": "https://code.claude.com/docs/en/desktop-linux", @@ -6253,8 +6253,8 @@ "url": "https://code.claude.com/docs/en/sub-agents", "status": "success", "path": "en/docs/claude-code/sub-agents.md", - "sha256": "0fc7d550f8580d12fefae642c4c74b84889817cb3c9f41501c38093016448532", - "size": 116225 + "sha256": "171391cec830f18874b1fd9b9125a4712ca10d6e34afdb53e2f0f8b2f643c392", + "size": 116352 }, { "url": "https://code.claude.com/docs/en/agent-view", @@ -6302,8 +6302,8 @@ "url": "https://code.claude.com/docs/en/mcp", "status": "success", "path": "en/docs/claude-code/mcp.md", - "sha256": "725767f77dd73cad71bb244070dec5ce36a7843bf0c4dea3b81e468c1012ec85", - "size": 154736 + "sha256": "4b3c2237229b454601119d2fd5d44228089ec3436b78edb395d357fc2bfe44d1", + "size": 155726 }, { "url": "https://code.claude.com/docs/en/skills", @@ -6393,8 +6393,8 @@ "url": "https://code.claude.com/docs/en/errors", "status": "success", "path": "en/docs/claude-code/errors.md", - "sha256": "e5b1b2852f2383c4cf492789160ebb4703b2ace2bbe630bb7510b9bc91008c71", - "size": 596941 + "sha256": "4e3ae04891bce5a010ff5dbecd7233401e59ad70b3706909285212ced1f4a866", + "size": 596477 }, { "url": "https://code.claude.com/docs/en/plugins/overview", @@ -6505,8 +6505,8 @@ "url": "https://code.claude.com/docs/en/plugins/mods/interface", "status": "success", "path": "en/docs/claude-code/plugins/mods/interface.md", - "sha256": "710f44f950e1888db8fa1ad2a2fde8e304ec703404deaf25dc10791614fd5fa6", - "size": 52794 + "sha256": "1deecedffc218c3507f30f63d73f931a65403990d16811a7e4c8b74d0e26a423", + "size": 52795 }, { "url": "https://code.claude.com/docs/en/plugins/mods/gallery", @@ -6526,8 +6526,8 @@ "url": "https://code.claude.com/docs/en/plugins/mods/api", "status": "success", "path": "en/docs/claude-code/plugins/mods/api.md", - "sha256": "6b125c4bfc154487f551e8e0e1920d981f17a3ddbc3d05d17ffde3d1d09de9be", - "size": 40697 + "sha256": "b64550f6fce51563796e5a54fa1e5eb2c66734fb59669f6e1736daa3e001a545", + "size": 40695 }, { "url": "https://code.claude.com/docs/en/plugins/mods/test", @@ -6617,8 +6617,8 @@ "url": "https://code.claude.com/docs/en/admin-setup", "status": "success", "path": "en/docs/claude-code/admin-setup.md", - "sha256": "21d215d6cad2ae26a118c87b9b0d90f8ddaced2d94c16ab56827facff4fe6a38", - "size": 29503 + "sha256": "5ad4e95cb97e50abce2bdeb1f932a1e61e5c925747cf336e047aadbda7182834", + "size": 29748 }, { "url": "https://code.claude.com/docs/en/setup", @@ -6631,15 +6631,15 @@ "url": "https://code.claude.com/docs/en/authentication", "status": "success", "path": "en/docs/claude-code/authentication.md", - "sha256": "e64aa011619a6a2d52191c26d30ebb9185911549a74930892f1ae78bc1fadb83", - "size": 36259 + "sha256": "86c28d9f9a994974ca6ad7bd6050fd0d9bc7fc5e7172ac79af7ca98bc7b92278", + "size": 36322 }, { "url": "https://code.claude.com/docs/en/managed-settings", "status": "success", "path": "en/docs/claude-code/managed-settings.md", - "sha256": "cf89a7fc97b4da0116a4ef3336739c1ceeaa987eab3f5bd9b6e66d837da5fd34", - "size": 64467 + "sha256": "a4c62e6cf3186beaa0101a9ba97bee3b9eaf90b46806377fd931f7663fabc5c3", + "size": 64744 }, { "url": "https://code.claude.com/docs/en/server-managed-settings", @@ -6680,8 +6680,8 @@ "url": "https://code.claude.com/docs/en/amazon-bedrock", "status": "success", "path": "en/docs/claude-code/amazon-bedrock.md", - "sha256": "a65334f1afaf7ad217a2780bf28d033fd1829a1b6510e093938eccd21b719906", - "size": 47137 + "sha256": "674f14e078cf670ffa0e35779ddd558010c0a7f2f343cc7f9f21e2acaad4abc3", + "size": 47520 }, { "url": "https://code.claude.com/docs/en/claude-platform-on-aws", @@ -6694,8 +6694,8 @@ "url": "https://code.claude.com/docs/en/google-vertex-ai", "status": "success", "path": "en/docs/claude-code/google-vertex-ai.md", - "sha256": "37fd6673fef06afbfd79de8b051bee766b78e8470c2f06e527483cbf65b3e92c", - "size": 22079 + "sha256": "55f58a5e8d6d021a1a90d032d9a9fbe1384356d6e02f772eb18f2d67bd38c157", + "size": 22505 }, { "url": "https://code.claude.com/docs/en/microsoft-foundry", @@ -6708,8 +6708,8 @@ "url": "https://code.claude.com/docs/en/network-config", "status": "success", "path": "en/docs/claude-code/network-config.md", - "sha256": "b19677a0236f0b0fd755bec414a8fddcd46c3f069b5bce9939bf581d16f8dfcc", - "size": 34534 + "sha256": "348db66ed5138aad4e5ddffd5904f67b833dc004af8c9a4dec713bdf6f2dd81b", + "size": 35149 }, { "url": "https://code.claude.com/docs/en/corporate-launcher", @@ -6792,36 +6792,36 @@ "url": "https://code.claude.com/docs/en/llm-gateway-rollout", "status": "success", "path": "en/docs/claude-code/llm-gateway-rollout.md", - "sha256": "d57cdfaca9576d993e43e1462e45b5164728b4f806b2590bae0e3f91b6804fdd", - "size": 31113 + "sha256": "877b078ee9a9cb2442ddf0836292f0a77cd19af9797e06eee1c19d66a29e4863", + "size": 31000 }, { "url": "https://code.claude.com/docs/en/llm-gateway-protocol", "status": "success", "path": "en/docs/claude-code/llm-gateway-protocol.md", - "sha256": "9b7af60f210a11db4fc8939734021ab08cb0706dc0fbb99fce844f2113f0d61e", - "size": 50259 + "sha256": "140aad701e56ba6849383bd1c0c8b00d6c199502408d37f162c39036109f7f33", + "size": 52739 }, { "url": "https://code.claude.com/docs/en/monitoring-usage", "status": "success", "path": "en/docs/claude-code/monitoring-usage.md", - "sha256": "3cecb1c69cad694cc313148398ea29581f84e39ad0f98e8f264b13e6f67f5f7f", - "size": 172751 + "sha256": "5309a4135df906dd8c4d28107c58f7266c5e477ad0fc3ca9fe8e946dd3c55df7", + "size": 172775 }, { "url": "https://code.claude.com/docs/en/costs", "status": "success", "path": "en/docs/claude-code/costs.md", - "sha256": "9dc47964e99b2d5ea3b0ae5c9f7a39661643a94caead7faace16fc77d1c1932f", - "size": 46832 + "sha256": "e07ef16eda379601114b810fce441f16db0fa0acd4cae0825629632d87ef1e37", + "size": 46819 }, { "url": "https://code.claude.com/docs/en/analytics", "status": "success", "path": "en/docs/claude-code/analytics.md", - "sha256": "17c37a237f885d1e29112ae4a6e521ebff938fa78cfa7c649bed5660a189d38f", - "size": 12075 + "sha256": "c7e7b4dd3e00babb286ecea1eb9ca50e229f67ba0a4d8e643a93a81b0b9823ba", + "size": 12236 }, { "url": "https://code.claude.com/docs/en/security", @@ -6869,15 +6869,15 @@ "url": "https://code.claude.com/docs/en/settings", "status": "success", "path": "en/docs/claude-code/settings.md", - "sha256": "1cd4ddf2f97f350d6e6e09d075902fbd3d12ac301ee3bee2a039cf727216fea0", - "size": 45051 + "sha256": "11ee1657254c1a5cafc20594056240cbb44172cf67a11ac0a72111bcccadfa87", + "size": 45521 }, { "url": "https://code.claude.com/docs/en/settings-reference", "status": "success", "path": "en/docs/claude-code/settings-reference.md", - "sha256": "c65e968f0e5a13a56f2232f390ecb3ace41f33e2d7aa8a2298e26579fe68a14e", - "size": 447747 + "sha256": "756701b303d66cf16d8132ee306de95e621cfff72e9ada76061c2a65c20d2a1e", + "size": 448145 }, { "url": "https://code.claude.com/docs/en/settings-example", @@ -6897,8 +6897,8 @@ "url": "https://code.claude.com/docs/en/permission-modes", "status": "success", "path": "en/docs/claude-code/permission-modes.md", - "sha256": "878df075ec0fdec78c5aff49acae0a41b005d0e27b5318490895f53e63baa9d3", - "size": 118834 + "sha256": "0914e337d801098dc83f9d0ddcd5946ba01b25f4e8027e0dbbb70509312d77cb", + "size": 118990 }, { "url": "https://code.claude.com/docs/en/auto-mode-classifier-billing", @@ -6911,8 +6911,8 @@ "url": "https://code.claude.com/docs/en/sandboxing", "status": "success", "path": "en/docs/claude-code/sandboxing.md", - "sha256": "40c54cdff30768ad1be7a02f4864bead3fe633cdcbfc13878dc5237636df8ac5", - "size": 107566 + "sha256": "75a0ec4a583c2e6009ee970c2925641ffe9e4d08c4cf3e714b26cf9b3135c5ef", + "size": 107874 }, { "url": "https://code.claude.com/docs/en/sandbox-environments", @@ -6925,8 +6925,8 @@ "url": "https://code.claude.com/docs/en/cloud-environments", "status": "success", "path": "en/docs/claude-code/cloud-environments.md", - "sha256": "e747891fad9b72865d0d67492a1b9a7c3276fba0ba76809d74df6701d187bbb4", - "size": 65991 + "sha256": "0a861ffd184ffa7a971ae952f08ea972fb371f85bb85a6d8c4ac9cc5d14096cb", + "size": 66118 }, { "url": "https://code.claude.com/docs/en/self-hosted-environments", @@ -6981,14 +6981,14 @@ "url": "https://code.claude.com/docs/en/model-config", "status": "success", "path": "en/docs/claude-code/model-config.md", - "sha256": "7180ba5975ee6529caebbd3a7847e4bcb5851d0a795efaba3a6f558d226b5842", - "size": 129830 + "sha256": "52e7629cad82ef0a8d185cdaa5ec0b043a39f3884f28bb363e6837f7914d80a9", + "size": 129763 }, { "url": "https://code.claude.com/docs/en/fast-mode", "status": "success", "path": "en/docs/claude-code/fast-mode.md", - "sha256": "15d801a2cad898f06cab1776d095638643af46f3536767e8daba27b3cf8ae7a6", + "sha256": "04d5d849bd37471e45728f790673e958736f0db9c0c74842eeacdcb1813e37fb", "size": 21818 }, { @@ -7051,36 +7051,36 @@ "url": "https://code.claude.com/docs/en/cli-reference", "status": "success", "path": "en/docs/claude-code/cli-reference.md", - "sha256": "9a68c8f3c42d6b42031f6b3080f9a6c32e86aac6fb3f2ffb1aaae1abeb3d4f07", - "size": 51769 + "sha256": "16beebe6f057f7372f36ab1379d8204bcad606b9d9ca58f87bbfda5221e894c5", + "size": 51739 }, { "url": "https://code.claude.com/docs/en/commands", "status": "success", "path": "en/docs/claude-code/commands.md", - "sha256": "ee726baa939a8676c77dc35f2eb9b97287634300d262e4f0f85418e10133c71c", - "size": 57550 + "sha256": "051898624506138e5c5a807aadcfd2776c9dfaae522cf1f3def2bd5985b74c22", + "size": 57489 }, { "url": "https://code.claude.com/docs/en/env-vars", "status": "success", "path": "en/docs/claude-code/env-vars.md", - "sha256": "c6af9335007280dfe50572702d0025e0d4bb8dc28554f607cb739614b7b5c096", - "size": 187070 + "sha256": "b9eca1b08f8ab647a553886627a52173acc93df8c695f1e023d58d9fbf56a0ce", + "size": 187247 }, { "url": "https://code.claude.com/docs/en/tools-reference", "status": "success", "path": "en/docs/claude-code/tools-reference.md", - "sha256": "52b12130dd11ccae423210b199028f1b5bc5ed244669f5c5adf349d052e6599a", - "size": 88892 + "sha256": "fa3802969f81cca7ef50e86b5104667fa69cedf0a299d384d3f209387b63d875", + "size": 88830 }, { "url": "https://code.claude.com/docs/en/interactive-mode", "status": "success", "path": "en/docs/claude-code/interactive-mode.md", - "sha256": "9c2363a6beec48c6340d2e266751387b41c857f34246be1915d4f20539777890", - "size": 78273 + "sha256": "7c1a1b53e6382f6382a6ded75e351225e4136cfeeda2797809b57e026157700e", + "size": 79219 }, { "url": "https://code.claude.com/docs/en/checkpointing", @@ -7093,8 +7093,8 @@ "url": "https://code.claude.com/docs/en/hooks", "status": "success", "path": "en/docs/claude-code/hooks.md", - "sha256": "8e4d5d8c03b5a4cd0e6fe15cc8d71d782a5acc29cf738c584337d024ff1e4ca1", - "size": 284268 + "sha256": "524960c086d43f6e23950bf9d98f513259e2b6fbfd88b38622a5d020698fbc6e", + "size": 284286 }, { "url": "https://code.claude.com/docs/en/channels-reference", @@ -7282,8 +7282,8 @@ "url": "https://code.claude.com/docs/en/agent-sdk/cost-tracking", "status": "success", "path": "en/docs/claude-code/agent-sdk/cost-tracking.md", - "sha256": "b01f78de868bf230af56931cfeedea5df6a1d0c859c254bf8734c36501ddeb5b", - "size": 27423 + "sha256": "0c4c84de2eaec4980d6ae66540984667cde68c7e3e9871aced02cc9f9ca507f6", + "size": 27364 }, { "url": "https://code.claude.com/docs/en/agent-sdk/observability", @@ -7317,8 +7317,8 @@ "url": "https://code.claude.com/docs/en/agent-sdk/typescript", "status": "success", "path": "en/docs/claude-code/agent-sdk/typescript.md", - "sha256": "2f620629329704487979447ba40ec35a9c04f9226e610e822da7f7bbd0040f7b", - "size": 329466 + "sha256": "b0b1dd58d02606cb478674e90f1cb76e75be2f6128570cd45a3ddcb097670584", + "size": 330089 }, { "url": "https://code.claude.com/docs/en/agent-sdk/typescript-v2-preview", @@ -8612,8 +8612,8 @@ "url": "https://modelcontextprotocol.io/extensions/client-matrix", "status": "success", "path": "mcp/extensions/client-matrix.md", - "sha256": "e06405ad21cc203c7e2a5b250af730374d1431e119c4898eb9ecfe3bfb6b29c9", - "size": 4661 + "sha256": "b274123c72c8a0db543fa96b121d417bd9d1098593ba104b0066f65380884389", + "size": 4707 }, { "url": "https://modelcontextprotocol.io/extensions/overview", @@ -10110,7 +10110,7 @@ "url": "https://support.claude.com/en/articles/8114491-get-started-with-claude", "status": "success", "path": "support/8114491-get-started-with-claude.md", - "sha256": "eea3dac9fc463b85e39811ab4aa288c3fda29c0d01e77a3f6f0f99441cad00da", + "sha256": "d9885f6501ce041109f9d321adfca672836668be837d5a32bc77281cd3335041", "size": 5210 }, { @@ -10187,8 +10187,8 @@ "url": "https://support.claude.com/en/articles/8230524-delete-or-rename-a-conversation", "status": "success", "path": "support/8230524-delete-or-rename-a-conversation.md", - "sha256": "110163c62aa3a0c88d70fa3a05a6bc27a4eb19839a43062bf008d67226f99457", - "size": 5893 + "sha256": "a8b56dda901597425c76be689af20d091db76039b5bbd3a3eb3b9cd117686a4f", + "size": 5879 }, { "url": "https://support.claude.com/en/articles/8241126-upload-files-to-claude", @@ -10257,8 +10257,8 @@ "url": "https://support.claude.com/en/articles/8325618-paid-plan-billing-faqs", "status": "success", "path": "support/8325618-paid-plan-billing-faqs.md", - "sha256": "f9ee8694c27fe1046f9b7b1e0a99a34b535a7af697b4e3ab68dc48916da79e99", - "size": 5020 + "sha256": "b3891a7cf711e03c36335109d2f0ab54383d0d5167c48435d7b09a5d17947e84", + "size": 5659 }, { "url": "https://support.claude.com/en/articles/8325621-i-would-like-to-input-sensitive-data-into-my-chats-with-claude-who-can-view-my-conversations", @@ -10320,8 +10320,8 @@ "url": "https://support.claude.com/en/articles/8887527-customizing-your-appearance-settings", "status": "success", "path": "support/8887527-customizing-your-appearance-settings.md", - "sha256": "08545010c59043bfd87ab8e11c15a3b3f467040d4cecad64648398cc9cc07402", - "size": 1912 + "sha256": "dbdbac2816659892cd66d28bf2fa4e92206717fcbc7729d6f8b039e40fc058b3", + "size": 1908 }, { "url": "https://support.claude.com/en/articles/8896518-does-anthropic-crawl-data-from-the-web-and-how-can-site-owners-block-the-crawler", @@ -10495,8 +10495,8 @@ "url": "https://support.claude.com/en/articles/9267400-move-your-personal-claude-account-to-a-team-or-enterprise-organization", "status": "success", "path": "support/9267400-move-your-personal-claude-account-to-a-team-or-enterprise-organization.md", - "sha256": "fdfcf8bc27ee9ec155aa2d88edd93dad5862508fd72350b52b8db87a4b3da0c4", - "size": 10464 + "sha256": "433123fed966ed6b5548417761341f5a87c02b09ee3963e565aed3d8ce7eeffc", + "size": 10462 }, { "url": "https://support.claude.com/en/articles/9301722-updates-to-our-acceptable-use-policy-now-usage-policy-consumer-terms-of-service-and-privacy-policy", @@ -10537,8 +10537,8 @@ "url": "https://support.claude.com/en/articles/9519177-how-can-i-create-and-manage-projects", "status": "success", "path": "support/9519177-how-can-i-create-and-manage-projects.md", - "sha256": "cd0b5299c69d1a45ad61aa707fdd14e8a645e7ce29e954e2a73589333798e4e9", - "size": 9204 + "sha256": "d42732409a9f80ea9d72743e4fb52972605aa7429236460d34274f000bb3bb93", + "size": 9206 }, { "url": "https://support.claude.com/en/articles/9519189-manage-project-visibility-and-sharing", @@ -10789,7 +10789,7 @@ "url": "https://support.claude.com/en/articles/10310342-how-do-i-log-out-of-all-active-sessions", "status": "success", "path": "support/10310342-how-do-i-log-out-of-all-active-sessions.md", - "sha256": "b4c91c474fbf282b3a59eef03d0f07b5347d6c740c5829546f361d593da8f7d2", + "sha256": "f79ebaad1227bf1faea085c6b7ae6a5005adb67e090077e6392812c530d9c191", "size": 3103 }, { @@ -10838,7 +10838,7 @@ "url": "https://support.claude.com/en/articles/10504844-manage-user-feedback-settings-on-team-and-enterprise-plans", "status": "success", "path": "support/10504844-manage-user-feedback-settings-on-team-and-enterprise-plans.md", - "sha256": "0fc88ec7a83b0282d793b7dce4c913370fb44d249a228d400e180fe77bfd90c3", + "sha256": "e3f57272c13bc762b3dcd6b947cd0f2eb6350fe6a28f1da76aa85a131450db0d", "size": 1034 }, { @@ -10859,7 +10859,7 @@ "url": "https://support.claude.com/en/articles/10593882-share-and-unshare-chats", "status": "success", "path": "support/10593882-share-and-unshare-chats.md", - "sha256": "d3d902c9a2b3794eda8110c0fcafe50e0095c779e076f8bb42e69d227fe2faba", + "sha256": "d11921ff56e6b36b35b3999aba6a1710ad090d2ecc56f72df6cf50a254e870c6", "size": 4019 }, { @@ -10887,7 +10887,7 @@ "url": "https://support.claude.com/en/articles/10949351-getting-started-with-local-mcp-servers-on-claude-desktop", "status": "success", "path": "support/10949351-getting-started-with-local-mcp-servers-on-claude-desktop.md", - "sha256": "cfa1510df03b2a7228894af6be4ec572efc87f5d142971b7ab2534a5e78b2754", + "sha256": "155311cc833b743b0a0befed7b2f23cafe1913564e8d117fde783de96c22210e", "size": 8957 }, { @@ -10922,8 +10922,8 @@ "url": "https://support.claude.com/en/articles/11101966-use-voice-mode", "status": "success", "path": "support/11101966-use-voice-mode.md", - "sha256": "c4e779aae3ae06f853f2f3ba03590f8e1b1ddb7225f2a3bab5dfb3cfaf95b502", - "size": 10646 + "sha256": "a853b679fe1af9d8d8891025c3d03267bcdf7b00e411ca291d2b9568fe8d5815", + "size": 10638 }, { "url": "https://support.claude.com/en/articles/11107691-why-is-a-coupon-or-promotion-not-available-for-my-account", @@ -11055,8 +11055,8 @@ "url": "https://support.claude.com/en/articles/11725453-set-up-the-claude-lti-in-canvas-by-instructure", "status": "success", "path": "support/11725453-set-up-the-claude-lti-in-canvas-by-instructure.md", - "sha256": "087c153cafcc1535c0f56b181806dabad98e939bc0fbe87a5425b6b46b16f473", - "size": 2752 + "sha256": "01f97edb108f1a1157ad1e20fa3fce548ed42a0ea3413e37f3478d1912cd8770", + "size": 2750 }, { "url": "https://support.claude.com/en/articles/11732894-who-owns-and-manages-the-data-of-my-claude-for-education-account", @@ -11076,8 +11076,8 @@ "url": "https://support.claude.com/en/articles/11818288-why-am-i-being-asked-to-verify-my-payment-method", "status": "success", "path": "support/11818288-why-am-i-being-asked-to-verify-my-payment-method.md", - "sha256": "2bd064f99ebd38865170d0ccdd5e5229ff51006bb78e7ae0914a320b013f4f87", - "size": 820 + "sha256": "0368696e9e4b553bba8881a498a1b81bbd3665d2a496bad7c99064ca82b43061", + "size": 816 }, { "url": "https://support.claude.com/en/articles/11825384-how-to-update-claude-for-ios", @@ -11111,7 +11111,7 @@ "url": "https://support.claude.com/en/articles/11869629-use-claude-with-android-apps", "status": "success", "path": "support/11869629-use-claude-with-android-apps.md", - "sha256": "d9761dcb9fa1e7116dac40dd1c1b1b36c2d748a73385b787d307435d0a17712c", + "sha256": "8594fe7d95a837f65303a4ab3ece873d111398bb4f5b7219e3396bd6ff3231cd", "size": 14023 }, { @@ -11146,15 +11146,15 @@ "url": "https://support.claude.com/en/articles/12005970-manage-usage-credits-for-team-and-seat-based-enterprise-plans", "status": "success", "path": "support/12005970-manage-usage-credits-for-team-and-seat-based-enterprise-plans.md", - "sha256": "6ad2d3dd2956d777c81fa917040cc8874ea48c159d84a0739da6a202c3da411c", - "size": 9713 + "sha256": "96d15f04f895401e9e895d7b7b739a8d77f9c0690c9c183f678d4a56fed1cfd9", + "size": 9711 }, { "url": "https://support.claude.com/en/articles/12012173-get-started-with-claude-in-chrome", "status": "success", "path": "support/12012173-get-started-with-claude-in-chrome.md", - "sha256": "b9a9ada458e1b23a56884bb58dc0d6c684c108e736712893a560a2a554dccd52", - "size": 14727 + "sha256": "3390aff49403d59b3dfaeafed991b4802bd5e936a631bb2dc093d39bdae4445a", + "size": 14729 }, { "url": "https://support.claude.com/en/articles/12053672-what-happens-to-a-user-s-data-when-they-are-removed-from-a-team-or-enterprise-organization", @@ -11181,8 +11181,8 @@ "url": "https://support.claude.com/en/articles/12111783-create-and-edit-files-with-claude", "status": "success", "path": "support/12111783-create-and-edit-files-with-claude.md", - "sha256": "12fcfb4038a1663f12d389d65796ec98f518c29340c60246d33a058cf65bc106", - "size": 18015 + "sha256": "c2423c3c158e1b764092defdafb1e15a8b24796e97091bcfdb37f11a136db000", + "size": 18011 }, { "url": "https://support.claude.com/en/articles/12119250-model-safety-bug-bounty-program", @@ -11209,21 +11209,21 @@ "url": "https://support.claude.com/en/articles/12157520-claude-code-usage-analytics", "status": "success", "path": "support/12157520-claude-code-usage-analytics.md", - "sha256": "94ba848cd40b7f3f9e1717509d9cf861155299ffb21cd5a96120d0da970c9286", - "size": 6374 + "sha256": "dcee5fd97ed4d530096fced612e58f584fd9ffb89744ee0168e5aeb9b096ef5f", + "size": 6382 }, { "url": "https://support.claude.com/en/articles/12260368-use-incognito-chats", "status": "success", "path": "support/12260368-use-incognito-chats.md", - "sha256": "f8b30108b4e2757558dfb28da37351a1816cc37b909311b4ac1afc5b9eee3090", - "size": 4388 + "sha256": "02983ad5688dd9a474c5c830a3526dc371b93c814cd37f96efba530f4897b2f4", + "size": 4390 }, { "url": "https://support.claude.com/en/articles/12293051-use-claude-in-xcode", "status": "success", "path": "support/12293051-use-claude-in-xcode.md", - "sha256": "8da84340b5fdbe1f7b8902fff9b8e1ed62e26a54c3ae8ba9bcb784ea2a62115a", + "sha256": "82b250a7fdaf95ecc44161384aa4ddc2a645c32de802c0761ba2bd3fe8ae6741", "size": 1915 }, { @@ -11293,8 +11293,8 @@ "url": "https://support.claude.com/en/articles/12512180-use-skills-in-claude", "status": "success", "path": "support/12512180-use-skills-in-claude.md", - "sha256": "b9c98ae6177626aa64c63254266be4255bf7b06b540817d1268f7a1e03107fbe", - "size": 19206 + "sha256": "f2d10983170ae2ec49cee062a849399e3a48d2bd6a15eed5d54e8cb49e4abacf", + "size": 19210 }, { "url": "https://support.claude.com/en/articles/12512198-how-to-create-custom-skills", @@ -11314,8 +11314,8 @@ "url": "https://support.claude.com/en/articles/12592343-enabling-and-using-the-desktop-extension-allowlist", "status": "success", "path": "support/12592343-enabling-and-using-the-desktop-extension-allowlist.md", - "sha256": "33fb7070706a1d7ebdfb833fd629c393bfd8f82a4252b71773b1d6b583dad4db", - "size": 5714 + "sha256": "06e8aac615f08c5c6e25337c5c4fcb21bcb50814e90a6ea9e2968b91a573ed4a", + "size": 5712 }, { "url": "https://support.claude.com/en/articles/12611117-deploy-claude-desktop-for-macos", @@ -11328,8 +11328,8 @@ "url": "https://support.claude.com/en/articles/12618689-use-claude-code-in-the-cloud", "status": "success", "path": "support/12618689-use-claude-code-in-the-cloud.md", - "sha256": "b9a4abe3a1e1ef3666ef9fd8ef02c06f076d680f10235b183b9bf3d9bbdb1f9f", - "size": 11117 + "sha256": "4e50d7246ad8957927a30e131e6d5be80ee57280629173ac0d2287353e8f6d52", + "size": 11121 }, { "url": "https://support.claude.com/en/articles/12622667-enterprise-configuration-for-claude-desktop", @@ -11384,8 +11384,8 @@ "url": "https://support.claude.com/en/articles/12883420-view-usage-analytics-for-team-and-enterprise-plans", "status": "success", "path": "support/12883420-view-usage-analytics-for-team-and-enterprise-plans.md", - "sha256": "26868b2478878f7ce61f07ccc1daf96757cad3fee630ab1bb28a0ce007eec019", - "size": 15097 + "sha256": "1e7d1e495be9003a9c06462f2b491441318f1fe7dc68c72ab972443ef80e0e94", + "size": 15103 }, { "url": "https://support.claude.com/en/articles/12902405-claude-in-chrome-troubleshooting", @@ -11405,8 +11405,8 @@ "url": "https://support.claude.com/en/articles/12902446-claude-in-chrome-permissions-guide", "status": "success", "path": "support/12902446-claude-in-chrome-permissions-guide.md", - "sha256": "ada9ac56b0fa7852c50ec23a84512a0d56098414c77bd412dbf2319cc63915ab", - "size": 9114 + "sha256": "4196c93bae5668a8daa2edbe7061778186efb498e08793ecdca95b0b45317fe6", + "size": 9110 }, { "url": "https://support.claude.com/en/articles/12938627-how-to-gift-a-claude-subscription", @@ -11433,8 +11433,8 @@ "url": "https://support.claude.com/en/articles/12997503-team-plan-billing-faqs", "status": "success", "path": "support/12997503-team-plan-billing-faqs.md", - "sha256": "92a2e14f6bfe085f9a7d245490c74f2ece0bf57e389f3ae27078d7b0db523c69", - "size": 5445 + "sha256": "f5a02a1262ef2c2272c947c40cf929def1447200ae9e6599834216a567838c2f", + "size": 5443 }, { "url": "https://support.claude.com/en/articles/13015708-access-the-compliance-api", @@ -11482,15 +11482,15 @@ "url": "https://support.claude.com/en/articles/13132885-set-up-single-sign-on-sso", "status": "success", "path": "support/13132885-set-up-single-sign-on-sso.md", - "sha256": "46a55ffdb8fcd5da8738b44f760e9b219a47f9e27544568656cb8417488f6f31", - "size": 13639 + "sha256": "1845b3d6b76d7a0e02e0141a4609cc0792f320e93163e35cbff31030f287b883", + "size": 13641 }, { "url": "https://support.claude.com/en/articles/13133195-set-up-jit-or-scim-provisioning", "status": "success", "path": "support/13133195-set-up-jit-or-scim-provisioning.md", - "sha256": "1e6c4e88cdc6ec8aa0545bd3fed998c942ef63806dceb72b7dab1384ba1ee290", - "size": 22519 + "sha256": "3125ebf8b25f18c8fc2dceb10514b8ecf444190d892d02ff5103c1d7e9f0459b", + "size": 22527 }, { "url": "https://support.claude.com/en/articles/13133750-manage-members-on-team-and-enterprise-plans", @@ -11517,7 +11517,7 @@ "url": "https://support.claude.com/en/articles/13163631-configuring-session-security-settings", "status": "success", "path": "support/13163631-configuring-session-security-settings.md", - "sha256": "baa4c40684d0274719584760c378f4bfa43d8b1582ba71e3f6944a0d8dbf48ed", + "sha256": "e862269329f8861be55f48ad5b034c7399fe6c1ddb16bfcfb43538079a24e0a6", "size": 3699 }, { @@ -11531,8 +11531,8 @@ "url": "https://support.claude.com/en/articles/13189465-log-in-to-your-claude-account", "status": "success", "path": "support/13189465-log-in-to-your-claude-account.md", - "sha256": "439730547d163473f576310b34a91583822f24cb2266db4f5effbc944d6868ff", - "size": 7046 + "sha256": "a51dd85360b65dae996e768db93300db6d7bbcdac622c765c6da967ad5740ad5", + "size": 7048 }, { "url": "https://support.claude.com/en/articles/13198485-enforce-network-level-access-control-with-tenant-restrictions", @@ -11559,14 +11559,14 @@ "url": "https://support.claude.com/en/articles/13325567-account-management-faqs", "status": "success", "path": "support/13325567-account-management-faqs.md", - "sha256": "cac06d568a50d50b8d276fc9a23f6fc21944a495372cb37539776b2d069bb809", + "sha256": "d130f086f3698d3e97d210ff4e16cce2c3d1635a9cbe602f0f80b0950fb23b52", "size": 2596 }, { "url": "https://support.claude.com/en/articles/13345190-get-started-with-claude-cowork", "status": "success", "path": "support/13345190-get-started-with-claude-cowork.md", - "sha256": "bb1dc229124143a993807c73e3340120c0e32c738bf83b6f754aadc4d32819f7", + "sha256": "d78e629513b70dd95178294010998ca1ee8b7c702512401293fc8a66284af053", "size": 22088 }, { @@ -11594,8 +11594,8 @@ "url": "https://support.claude.com/en/articles/13371040-log-in-to-your-console-account", "status": "success", "path": "support/13371040-log-in-to-your-console-account.md", - "sha256": "ca204de4852510ca321a8eeb227fab058817cdd092441f9c79152e2a7258e186", - "size": 4613 + "sha256": "303a18146c0565dad30d35558cdb5e718a0d31ed1f45a65f80989e8fc52f54b1", + "size": 4609 }, { "url": "https://support.claude.com/en/articles/13393991-purchase-and-manage-seats-on-enterprise-plans", @@ -11650,8 +11650,8 @@ "url": "https://support.claude.com/en/articles/13641943-visual-and-interactive-content", "status": "success", "path": "support/13641943-visual-and-interactive-content.md", - "sha256": "0957ee936fdd78a3d86054a0769d4325070d52e577ca5521b89ac5d498a0a71a", - "size": 6509 + "sha256": "dcd5974f2c3ca388b04a81e66150e15141df8c68c6303aea7c90963e9a67afed", + "size": 6513 }, { "url": "https://support.claude.com/en/articles/13663666-use-visual-and-interactive-content-on-team-and-enterprise-plans", @@ -11706,8 +11706,8 @@ "url": "https://support.claude.com/en/articles/13837440-use-plugins-in-claude", "status": "success", "path": "support/13837440-use-plugins-in-claude.md", - "sha256": "7434ec43ddd327bfe8b99a9510f06831edad56efd6065dab1011785d88fe5a9f", - "size": 15271 + "sha256": "3d74928b0fde4689f0f31e4308e7e422d3572ed7446e9275bdfd18015e64985b", + "size": 15263 }, { "url": "https://support.claude.com/en/articles/13854387-schedule-recurring-tasks-in-claude-cowork", @@ -11804,7 +11804,7 @@ "url": "https://support.claude.com/en/articles/13947068-assign-tasks-from-anywhere-in-claude-cowork", "status": "success", "path": "support/13947068-assign-tasks-from-anywhere-in-claude-cowork.md", - "sha256": "ac6f884924ca8ec7a064575fe6f9fa9cc94cd632e8f4b45f784b6f4c3492414b", + "sha256": "4ac6d05eec2a5b5f05d6f66722093d30216ba1a4398a63e2492e45cb0dbcc33d", "size": 8995 }, { @@ -11825,8 +11825,8 @@ "url": "https://support.claude.com/en/articles/14116274-organize-your-tasks-with-projects-in-claude-cowork", "status": "success", "path": "support/14116274-organize-your-tasks-with-projects-in-claude-cowork.md", - "sha256": "03f1b5c4f19b61519ce616c77e42035c24198bb97ab20b0a3bc4cfe98a234812", - "size": 7877 + "sha256": "3a3f9b77f53908efc373869a02308971fe5690243e3d1a735f2e11b878d4ca51", + "size": 7881 }, { "url": "https://support.claude.com/en/articles/14128542-let-claude-use-your-computer-in-cowork", @@ -11895,7 +11895,7 @@ "url": "https://support.claude.com/en/articles/14499648-how-scim-sync-works-for-enterprise-organizations", "status": "success", "path": "support/14499648-how-scim-sync-works-for-enterprise-organizations.md", - "sha256": "fb198df01b09cc70be31618f811eb6bdc7589efa070e605b06d7b8afeafb442c", + "sha256": "a1d35d22f01ee038eba2f0b93e2fe4b4e28eb2d8aecdaba28dfbced36cddca94", "size": 7670 }, { @@ -12007,8 +12007,8 @@ "url": "https://support.claude.com/en/articles/14604842-cyber-verification-program", "status": "success", "path": "support/14604842-cyber-verification-program.md", - "sha256": "16b6638ea613e0180e4fc97f10f1abe4a1b7a6a7e3233d7348ae0fdaf130fe70", - "size": 36007 + "sha256": "5fc48e0404f14c69fa55be0d432c1b27e023be5c1a92d36a71e59c8643eaad10", + "size": 37407 }, { "url": "https://support.claude.com/en/articles/14625619-claim-and-migrate-accounts-on-your-domain", @@ -12119,8 +12119,8 @@ "url": "https://support.claude.com/en/articles/15330088-set-a-default-model-for-your-organization", "status": "success", "path": "support/15330088-set-a-default-model-for-your-organization.md", - "sha256": "e36138b929866ddff4c32aae795f9c8fcdda75262e62369268106ad49385d694", - "size": 11311 + "sha256": "8e68d666a8312cf26aa52a084348e41ed01b2ca12b53837e2bcb94b9e4f20a58", + "size": 11309 }, { "url": "https://support.claude.com/en/articles/15330651-claude-enterprise-admin-api-reference-guide", @@ -12231,15 +12231,15 @@ "url": "https://support.claude.com/en/articles/15694740-manage-model-access-for-your-organization", "status": "success", "path": "support/15694740-manage-model-access-for-your-organization.md", - "sha256": "e79ad37ba7d13003b9a7266a30118708539a0b4c1f517858ebc58f8f7b99faf3", - "size": 10340 + "sha256": "7b79e1c9aa7081e560114e5d293934d5e29bb0b442d4d58f66de1a7f29e0c9ac", + "size": 10338 }, { "url": "https://support.claude.com/en/articles/15707726-using-claude-for-legal-work-privilege-confidentiality-and-how-to-think-about-configuration", "status": "success", "path": "support/15707726-using-claude-for-legal-work-privilege-confidentiality-and-how-to-think-about-configuration.md", - "sha256": "30bd2f279a500182656e4ac9e9281a2a19dedabbc5c2dde9b9ae7ff4ed4822b5", - "size": 9223 + "sha256": "ac637cd56cb1ac7581224d3bd08de41480cf456c37f345aa51e8e154f4b8b307", + "size": 9244 }, { "url": "https://support.claude.com/en/articles/15924927-use-claude-code-cli-with-a-screen-reader", @@ -12266,8 +12266,8 @@ "url": "https://support.claude.com/en/articles/15936181-get-started-with-1password-for-claude", "status": "success", "path": "support/15936181-get-started-with-1password-for-claude.md", - "sha256": "152fd032c466550d604b9e17c25e544c7f69b5a0ed1beed8d209cdf36c127928", - "size": 5067 + "sha256": "e4231e0649bdd3c42a46152fa819aae7b9926c0418d3faecc40b15f5490a902b", + "size": 5063 }, { "url": "https://support.claude.com/en/articles/16049681-why-claude-switched-models-in-your-conversation-with-opus-5-or-opus-5-5", @@ -12315,8 +12315,8 @@ "url": "https://support.claude.com/en/articles/16607638-understanding-your-pro-max-or-ultra-plan-invoices", "status": "success", "path": "support/16607638-understanding-your-pro-max-or-ultra-plan-invoices.md", - "sha256": "3d65a3dae923002f87d33f2ec6f996c342d6d25a10d17fe2505002f09b0f25ee", - "size": 5885 + "sha256": "79e45ae41432f75f70514a3a7d77d65e9567a6ab9eba6e5eaccf51ff600686b3", + "size": 5883 }, { "url": "https://support.claude.com/en/articles/16607668-understanding-your-team-plan-invoices", @@ -12399,8 +12399,8 @@ "url": "https://support.claude.com/en/articles/16893491-get-started-with-smart-reports", "status": "success", "path": "support/16893491-get-started-with-smart-reports.md", - "sha256": "5b850065a290669c45a5720ee7d89e053d628d5c5bd489ef50ac95206f733125", - "size": 17204 + "sha256": "928f21d11e9754d50fef845b5fafe8a842740607265ff82e320ef15fb2f1900b", + "size": 17208 }, { "url": "https://support.claude.com/en/articles/16923645-get-started-with-claude-docs", @@ -12420,8 +12420,8 @@ "url": "https://support.claude.com/en/articles/16951679-use-claude-in-google-docs-sheets-and-slides", "status": "success", "path": "support/16951679-use-claude-in-google-docs-sheets-and-slides.md", - "sha256": "782ffda05e156d7aa15a5f5952ba16fc4d1738fa66acefc0e447135329429e41", - "size": 21997 + "sha256": "2bc80e47396896cdd379126f9580dd602ef6f78615a853726cc71d78319e3ba2", + "size": 22001 }, { "url": "https://support.claude.com/en/articles/16952184-set-up-salesforce-in-claude-for-your-organization", @@ -12448,7 +12448,7 @@ "url": "https://support.claude.com/en/articles/17005973-manage-pooled-group-budgets-on-enterprise-plans", "status": "success", "path": "support/17005973-manage-pooled-group-budgets-on-enterprise-plans.md", - "sha256": "ec058f76e5d6269e48ceeb6dccd84cc06de78a55d0bf0f615d0d5d5a7b5e040c", + "sha256": "76224bffcebe82841c2534bb8dfc8e89c677675557f0d86096caf5c07a493141", "size": 7831 }, { @@ -12497,8 +12497,8 @@ "url": "https://support.claude.com/en/articles/17203415-set-up-claude-for-intune", "status": "success", "path": "support/17203415-set-up-claude-for-intune.md", - "sha256": "5bedbbe7a7fa4ee9378ddaa59a734cd72ce6d44845f334e626799e37d3e9bdc2", - "size": 11369 + "sha256": "95b0b1e8ec139d45f431a49ce7df1acca1c2047c947518152b9a4c9a87e993d3", + "size": 11375 }, { "url": "https://support.claude.com/en/articles/17318731-use-claude-code-local-mode-and-claude-cowork-local-mode-on-a-hipaa-ready-enterprise-plan", @@ -13477,8 +13477,8 @@ "url": "https://claude.com/docs/connectors/building/enterprise-managed-auth", "status": "success", "path": "claude/connectors/building/enterprise-managed-auth.md", - "sha256": "aa6ee44c27c4b438c6dd64c869782c8b1a8520903369e1c7243e7b90b7c5f7e8", - "size": 15384 + "sha256": "88a11e5a20df25d7942f8ad6229a83ab9c8c1ab2598f34a59bf075a51de8f5e8", + "size": 27820 }, { "url": "https://claude.com/docs/connectors/building", @@ -14002,8 +14002,8 @@ "url": "https://claude.com/docs/government/security/security-and-data-handling", "status": "success", "path": "claude/government/security/security-and-data-handling.md", - "sha256": "1d8ecd32275855a8a3df191021965b51414bfb3722d1db3e5da04a471e2a44a0", - "size": 46204 + "sha256": "8432d11f6ef065e2d5c15eb2ac69ae079953827acafb73b8db639b4cd2547157", + "size": 46338 }, { "url": "https://claude.com/docs/government/tenant-admin/admins", @@ -14310,8 +14310,8 @@ "url": "https://claude.com/docs/third-party/claude-desktop/chat", "status": "success", "path": "claude/third-party/claude-desktop/chat.md", - "sha256": "85413b761a06920f38cd25d006909fe44977d4411761ddf83291b0c8ba2166b3", - "size": 17304 + "sha256": "dee71c4cd1ce4f292432717cec05c03ecf02d79eaeb5c59e992683beab81d3b2", + "size": 17378 }, { "url": "https://claude.com/docs/third-party/claude-desktop/claude-api", @@ -14394,8 +14394,8 @@ "url": "https://claude.com/docs/third-party/claude-desktop/data-storage", "status": "success", "path": "claude/third-party/claude-desktop/data-storage.md", - "sha256": "1e6b8eb9307870bcd76b94426a0c17b6109a796b448d267d5ad9ac963c2bbb88", - "size": 31848 + "sha256": "4ad136d64da4a21daebad64e93afe0654061851d96466d2c79e8e5a3f2d447b1", + "size": 33540 }, { "url": "https://claude.com/docs/third-party/claude-desktop/entra-broker", @@ -14513,8 +14513,8 @@ "url": "https://claude.com/docs/third-party/claude-desktop/overview", "status": "success", "path": "claude/third-party/claude-desktop/overview.md", - "sha256": "1ca97b26f115f51ecc0363b57d87e172ef18c515eed8bb3bb991ff5746e8ad0c", - "size": 14156 + "sha256": "cd13c0d5d9acc4347344ddb5f76bb037a0ac3ebdbae08660aa53e51f06070353", + "size": 14244 }, { "url": "https://claude.com/docs/third-party/claude-desktop/ssh-remote-sessions", @@ -14534,8 +14534,8 @@ "url": "https://claude.com/docs/third-party/claude-desktop/telemetry", "status": "success", "path": "claude/third-party/claude-desktop/telemetry.md", - "sha256": "00f92b75d1081af44ade288d65434e6eb35994d0a56583e73107ac2c6123bbcf", - "size": 38259 + "sha256": "55d1c75aabf9a2c318002fa4d67d82dac2da1ddad2f8dd54309a9d5e1482f9d0", + "size": 38055 }, { "url": "https://claude.com/docs/third-party/claude-desktop/unified-claude", @@ -14562,8 +14562,8 @@ "url": "https://code.claude.com/docs/en/desktop-changelog", "status": "success", "path": "en/docs/claude-code/desktop-changelog.md", - "sha256": "cac6a537e446076c84954dd7264ca62a5ffff40928db1cfa608adaf8c6e564d4", - "size": 211526 + "sha256": "f21b9a0e4de35eb5c415dd6e19ed263810e318ee62f03260d3359be3ce01f051", + "size": 213436 }, { "url": "https://code.claude.com/docs/en/plugin-dependencies", @@ -14583,8 +14583,8 @@ "url": "https://code.claude.com/docs/en/iam", "status": "success", "path": "en/docs/claude-code/iam.md", - "sha256": "e64aa011619a6a2d52191c26d30ebb9185911549a74930892f1ae78bc1fadb83", - "size": 36259 + "sha256": "86c28d9f9a994974ca6ad7bd6050fd0d9bc7fc5e7172ac79af7ca98bc7b92278", + "size": 36322 }, { "url": "https://code.claude.com/docs/en/plugin-relevance", @@ -14604,8 +14604,8 @@ "url": "https://code.claude.com/docs/en/web-scheduled-tasks", "status": "success", "path": "en/docs/claude-code/web-scheduled-tasks.md", - "sha256": "a5798b95a676d1062c7dd2278d785583fc70690ef36f5e39a14090e759cf08d0", - "size": 50243 + "sha256": "197f51492cb353d49eae277a0797ed5cd52dcb9978c0b720b26b0f0df41ab7d2", + "size": 50325 }, { "url": "https://code.claude.com/docs/en/plugins-reference", @@ -23529,8 +23529,8 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/CLAUDE.md", "status": "success", "path": "github/claude-cookbooks/CLAUDE.md", - "sha256": "18715cc91f70b9a3a11cb0c66375c3eb9102e887fe215175cc239fd23ef81b9d", - "size": 3732 + "sha256": "1521c3e62badd9cf6b0761238cf19aea2d311a6d796a48bfef79d497d483dbe1", + "size": 3733 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/CONTRIBUTING.md", @@ -23543,8 +23543,8 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/README.md", "status": "success", "path": "github/claude-cookbooks/README.md", - "sha256": "5d5af555aff7b94e67b38478e20463c09aaa1c6d7202b75d91ee1eb49a262a41", - "size": 6083 + "sha256": "c163defae6a7d7d92b24d79f2817fdcf03c95a954d98305f28cd9dca87617bb0", + "size": 6250 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/capabilities/README.md", @@ -23613,8 +23613,8 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/capabilities/content_moderation/guide.ipynb", "status": "success", "path": "github/claude-cookbooks/capabilities/content_moderation/guide.ipynb", - "sha256": "ad6757f3e09950567ccda7abb6553e041824f2daef58e287efa1433369594ef0", - "size": 240901 + "sha256": "4a932b6b64713afe769d7a81e897d03781102c655342f294f1f25a7548adb836", + "size": 240869 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/capabilities/contextual-embeddings/README.md", @@ -23627,8 +23627,8 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/capabilities/contextual-embeddings/guide.ipynb", "status": "success", "path": "github/claude-cookbooks/capabilities/contextual-embeddings/guide.ipynb", - "sha256": "1ef3cc0ce6439dba5e8a30c8de20bf19e81e1d5bacae95df28be61b16932f02e", - "size": 79003 + "sha256": "c1d17d871e126e831b39de9271516c791a770d46b58ec6d295641f11e46700b1", + "size": 78915 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/capabilities/knowledge_graph/README.md", @@ -23690,8 +23690,8 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/capabilities/summarization/guide.ipynb", "status": "success", "path": "github/claude-cookbooks/capabilities/summarization/guide.ipynb", - "sha256": "b8111bb16bc1844ed201b9017a63edb77544e94d7fed113d82cbe7d036d40ab6", - "size": 187608 + "sha256": "8e19f607e65787038f5e0be6db71c3c2e166aa97259f24992d1cd02a6b3c5b43", + "size": 188007 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/capabilities/text_to_sql/README.md", @@ -23718,64 +23718,64 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/claude_agent_sdk/00_The_one_liner_research_agent.ipynb", "status": "success", "path": "github/claude-cookbooks/claude_agent_sdk/00_The_one_liner_research_agent.ipynb", - "sha256": "a147456907c514816a2d327a6b5172c05ca68caf23729a8bfe86193501197380", - "size": 70645 + "sha256": "fc634cb706e677408899584fda4bb4b75e2938fd497c51aad719934fe3b5604a", + "size": 70921 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/claude_agent_sdk/01_The_chief_of_staff_agent.ipynb", "status": "success", "path": "github/claude-cookbooks/claude_agent_sdk/01_The_chief_of_staff_agent.ipynb", - "sha256": "f8412aea2d656576a2f7b7a78d7ddb535b5e4e79e025370502290da61527b3ee", - "size": 115399 + "sha256": "03ab849d421a4128abb64a0fa4ecb52f3a945bc96b3e3ba89155fee3eb0c5f4e", + "size": 115683 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/claude_agent_sdk/02_The_observability_agent.ipynb", "status": "success", "path": "github/claude-cookbooks/claude_agent_sdk/02_The_observability_agent.ipynb", - "sha256": "ca8b7d153cdd4bfa7a2828cddebb7b30d0873f1d914f1a09d117a6393fa0d22c", - "size": 70190 + "sha256": "48e638aaac678f1303351f309d5c94066600e10746ddfb0f0034c116037af9ba", + "size": 70467 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/claude_agent_sdk/03_The_site_reliability_agent.ipynb", "status": "success", "path": "github/claude-cookbooks/claude_agent_sdk/03_The_site_reliability_agent.ipynb", - "sha256": "dd18059a4904f5d24457d28c329d6e08c6fe5eacd6956d3e6c3dd5dbc7709f15", - "size": 597888 + "sha256": "5c2096088fdbe2ed4cb245915e1d1737bb9a4163b141507a483ba5ac3efa740d", + "size": 598011 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/claude_agent_sdk/04_migrating_from_openai_agents_sdk.ipynb", "status": "success", "path": "github/claude-cookbooks/claude_agent_sdk/04_migrating_from_openai_agents_sdk.ipynb", - "sha256": "97d3e559302a09d33c2c743c9598988d956ec36a853f5ae141b3c56fa5efae76", - "size": 39171 + "sha256": "6c7e798857a247c062a11942b10a8f8c789439e3915f65efd9a87a16a07c96a3", + "size": 39581 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/claude_agent_sdk/05_Building_a_session_browser.ipynb", "status": "success", "path": "github/claude-cookbooks/claude_agent_sdk/05_Building_a_session_browser.ipynb", - "sha256": "a8fbad36ec1e301735b05d2894aa8f225b2d3e4fbdadff14f60ca3a03371c322", - "size": 21585 + "sha256": "9e32ad4c2a595c09358bcea43387cf7f9bf18901c6307e495b5b075f7ee4085e", + "size": 31478 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/claude_agent_sdk/06_The_vulnerability_detection_agent.ipynb", "status": "success", "path": "github/claude-cookbooks/claude_agent_sdk/06_The_vulnerability_detection_agent.ipynb", - "sha256": "21354a477757b56b22b7e443e19dafb1da204c72083794c09661f791f0c3bb51", - "size": 50322 + "sha256": "544390c84b1b9a19b539684500f9dbf459edfc3b5624573fa9d037fefd0a4ce1", + "size": 50746 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/claude_agent_sdk/07_Hosting_the_agent.ipynb", "status": "success", "path": "github/claude-cookbooks/claude_agent_sdk/07_Hosting_the_agent.ipynb", - "sha256": "d01272e82ed6b4f5ffa571b543011a87a8585b4c8b30182a226f3aa3a2759b88", - "size": 69243 + "sha256": "f198c5d38082267786fd83512ab3b3dc790f47357004deee7381e5a2f269af50", + "size": 69283 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/claude_agent_sdk/08_Dynamic_workflows.ipynb", "status": "success", "path": "github/claude-cookbooks/claude_agent_sdk/08_Dynamic_workflows.ipynb", - "sha256": "c9cb989d6f5db6317c65fa5b1e842152907686fb67b3265711153ca3413f7197", - "size": 52677 + "sha256": "7f289f3c42a97142f4778f3cf843d3a8ae48e9b3cef8d4273e6460f95e24b3e1", + "size": 50028 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/claude_agent_sdk/README.md", @@ -23914,8 +23914,8 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/claude_agent_sdk/scheduled_repository_reviewer/scheduled_repository_reviewer.ipynb", "status": "success", "path": "github/claude-cookbooks/claude_agent_sdk/scheduled_repository_reviewer/scheduled_repository_reviewer.ipynb", - "sha256": "4e0953a79660cfc5e7a07c12becf59dc4d11301eea2bf49af2763e8d0ac552b6", - "size": 68167 + "sha256": "e934c1e88ae65e193a63f9bfc3c9f00b7a684c9f157cf0d6c151320ad62da54c", + "size": 69325 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/coding/prompting_for_frontend_aesthetics.ipynb", @@ -23935,8 +23935,8 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/cost_optimization/cost_optimization.ipynb", "status": "success", "path": "github/claude-cookbooks/cost_optimization/cost_optimization.ipynb", - "sha256": "6b5955d79331c70a2a5c81c28cf7cd45891996aaf4d8a12da67a07967e33c4da", - "size": 1288468 + "sha256": "e0a393b04645599642ba5c9b92eea9df48839907b789e4671cd20c585d5f19e8", + "size": 1288491 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/evals/agentic_search/reproduce_agentic_search_benchmarks.ipynb", @@ -23973,6 +23973,41 @@ "sha256": "e0e8481d11d70fce3e21a8fb13365482b5f91a69e22bae1d6a93f215643a75c6", "size": 7401 }, + { + "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/latency_optimization/desk_agent/README.md", + "status": "success", + "path": "github/claude-cookbooks/latency_optimization/desk_agent/README.md", + "sha256": "3d97cb44bb26b3b8badf525834bd44a0d171f32e15d852dcbe551913fbdb08be", + "size": 5990 + }, + { + "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/latency_optimization/desk_agent/_gen/policy_manual.md", + "status": "success", + "path": "github/claude-cookbooks/latency_optimization/desk_agent/_gen/policy_manual.md", + "sha256": "dcd4ea4ae0615f8db656bb3fefa486a5e7bffcf45350fc3542472017356591b2", + "size": 29612 + }, + { + "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/latency_optimization/desk_agent/_gen/section9_desk_settlement.md", + "status": "success", + "path": "github/claude-cookbooks/latency_optimization/desk_agent/_gen/section9_desk_settlement.md", + "sha256": "88e6d38fe9fffd876ab58180013f6dc6562b6f465ffcc8ea9f20fd72d70f35e8", + "size": 8680 + }, + { + "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/latency_optimization/latency_optimization.ipynb", + "status": "success", + "path": "github/claude-cookbooks/latency_optimization/latency_optimization.ipynb", + "sha256": "d785d1c58ee343e08ca5babe8c698a7cab1e2e4badd2d61ab58a4b0a23c784af", + "size": 453655 + }, + { + "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/latency_optimization/results/README.md", + "status": "success", + "path": "github/claude-cookbooks/latency_optimization/results/README.md", + "sha256": "12fc591258abe77775ae91da57806b2790fbe7b5377e25a7147a9fdeaf6509d4", + "size": 3295 + }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/managed_agents/CMA_agent_security_review.ipynb", "status": "success", @@ -24047,29 +24082,29 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/managed_agents/CMA_plan_big_execute_small.ipynb", "status": "success", "path": "github/claude-cookbooks/managed_agents/CMA_plan_big_execute_small.ipynb", - "sha256": "4bbdb99d7373217cd2b73a4151b9b9eb1ad4b7745c9c4e5afd40c3fa43cfd8a6", - "size": 31213 + "sha256": "6e7096d557a0958c39a7ea56689f77c5abaf6763ec62d949115e33187d4a6848", + "size": 31212 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/managed_agents/CMA_prompt_versioning_and_rollback.ipynb", "status": "success", "path": "github/claude-cookbooks/managed_agents/CMA_prompt_versioning_and_rollback.ipynb", - "sha256": "baf82c909e6280632d40e95753edeb62cf8a411a9a909871623f6c5a93ce7227", - "size": 15828 + "sha256": "94972fed0bb47b185600a6c1fcd958db146e4bf2a416857ef03753a502a487f0", + "size": 15826 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/managed_agents/CMA_remember_user_preferences.ipynb", "status": "success", "path": "github/claude-cookbooks/managed_agents/CMA_remember_user_preferences.ipynb", - "sha256": "689dfcd0fd50b7af340d2d67c2eecae8eb40db64094dba151db7a69cb91e9fa2", - "size": 26774 + "sha256": "2dc019a6814f04a77a846669d180f18d4eea976079e7e2cdcc63081e7804d780", + "size": 26773 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/managed_agents/CMA_use_skills_from_a_repo.ipynb", "status": "success", "path": "github/claude-cookbooks/managed_agents/CMA_use_skills_from_a_repo.ipynb", - "sha256": "cb4933b61ecf3d2df482eab2461b40563508f0834b985837b87e768f07802a58", - "size": 15103 + "sha256": "1abf97572d83bef7cd9dc3e6f167918ed8aaba5d9bab5d9958669195938d0fee", + "size": 15101 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/managed_agents/CMA_verify_with_outcome_grader.ipynb", @@ -24082,22 +24117,22 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/managed_agents/CMA_watch_subagents_live.ipynb", "status": "success", "path": "github/claude-cookbooks/managed_agents/CMA_watch_subagents_live.ipynb", - "sha256": "3e96d2a651a64ac7f738829c0e049f8d7ffb727faefcfabc165660843df73bfb", - "size": 25405 + "sha256": "9e7abd41cff65177bd74bf17d8e65d64521dc4fca31ecce28f0751ada3b91071", + "size": 25403 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/managed_agents/CMA_with_mongodb_atlas.ipynb", "status": "success", "path": "github/claude-cookbooks/managed_agents/CMA_with_mongodb_atlas.ipynb", - "sha256": "b800154ac1342fcbb0aa8da2131d106926eb5fbe157a29077d5643f0f6b1a298", - "size": 75596 + "sha256": "b535b8e30efef0d5b147b09594b1e3f08ac1e619aa2dd5b47880c2882e3e7c89", + "size": 75594 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/managed_agents/README.md", "status": "success", "path": "github/claude-cookbooks/managed_agents/README.md", - "sha256": "f04d5b3c5b9cd621db04a1dc6e8bee59d482f940cfb74537f935aa8182932138", - "size": 10020 + "sha256": "dfa53a6d55fe1ffc396878ef95055102b4ca209a87709c5cc2a50d6169a3631a", + "size": 10361 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/managed_agents/cma-mcp/README.md", @@ -24110,8 +24145,8 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/managed_agents/data_analyst_agent.ipynb", "status": "success", "path": "github/claude-cookbooks/managed_agents/data_analyst_agent.ipynb", - "sha256": "80d157bb2c8b506881d6dcc2db474eba0f4f199357e1934b03816063ea7bcfd6", - "size": 15291 + "sha256": "58d9d058dafaf066c11d755ff4e6e5c56b25403c56044f3d35d60ff2278eba25", + "size": 15290 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/managed_agents/example_data/OVERVIEW.md", @@ -24215,21 +24250,21 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/managed_agents/slack_data_bot.ipynb", "status": "success", "path": "github/claude-cookbooks/managed_agents/slack_data_bot.ipynb", - "sha256": "ba89d44ec963226eb09ab6145e4fa997b339bdf33a5613308d2620762cee0624", - "size": 16064 + "sha256": "5685f8c9d17b32a978b8572ca110a418b9fa7df4c3c0d10e44f1d4af51ba440f", + "size": 16063 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/managed_agents/sre_incident_responder.ipynb", "status": "success", "path": "github/claude-cookbooks/managed_agents/sre_incident_responder.ipynb", - "sha256": "8ddc1527b9115b10d476d32cca33fa78d9aef6cd3be95a83edb155c194391bed", - "size": 37178 + "sha256": "b317da3818e07c98d0b0092604dda510fef38cbdfe5b1d4b31ddd853dd01f38a", + "size": 37143 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/misc/admin_api.ipynb", "status": "success", "path": "github/claude-cookbooks/misc/admin_api.ipynb", - "sha256": "4dc5ea27a0a93c4bf5b0769343f6c0130909efa1355b58f562bd9b6b32dfd7c1", + "sha256": "5dcf29ba952f8b0efdf716ed8cf19920f995b8b03a3cba794d8a5edd56b4b4e7", "size": 30008 }, { @@ -24257,8 +24292,8 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/misc/generate_test_cases.ipynb", "status": "success", "path": "github/claude-cookbooks/misc/generate_test_cases.ipynb", - "sha256": "177178c6a167cd598973aeb4100ac095509866994dc36f5555900de8f480acf8", - "size": 30445 + "sha256": "12196dd8085dcdea7ce65eb251593c457ad23dbc4bfdff4b0119d1a502771f99", + "size": 43971 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/misc/how_to_enable_json_mode.ipynb", @@ -24313,8 +24348,8 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/misc/session_memory_compaction.ipynb", "status": "success", "path": "github/claude-cookbooks/misc/session_memory_compaction.ipynb", - "sha256": "baf8dc1414987e719ff37e44e14aa509f45ff992a88255e6ae8b4aebdda49f31", - "size": 87028 + "sha256": "078a521585ff67249e81ec93c6abce334aa8fa3754b207fb5af97694c666e864", + "size": 91993 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/misc/speculative_prompt_caching.ipynb", @@ -24327,8 +24362,8 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/misc/using_citations.ipynb", "status": "success", "path": "github/claude-cookbooks/misc/using_citations.ipynb", - "sha256": "384910debe5e384d7944d071ce307a9c044b54b08057931690d17a07071f0697", - "size": 46005 + "sha256": "db2dfd23788536147c6d11ecf17421c379b18b1faee880fe14d39d24707abc77", + "size": 46012 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/multimodal/best_practices_for_vision.ipynb", @@ -24348,8 +24383,8 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/multimodal/getting_started_with_vision.ipynb", "status": "success", "path": "github/claude-cookbooks/multimodal/getting_started_with_vision.ipynb", - "sha256": "0da31cf3994fd188564a7c2c8d9c90be4b63bd4b9827bd5dc7633ae9f4657447", - "size": 1495906 + "sha256": "8795c8612f23749e462c52b3b9d0fcb2a77339a6341e2e1d9973a9cc00bb524e", + "size": 1496173 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/multimodal/how_to_transcribe_text.ipynb", @@ -24362,15 +24397,15 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/multimodal/reading_charts_graphs_powerpoints.ipynb", "status": "success", "path": "github/claude-cookbooks/multimodal/reading_charts_graphs_powerpoints.ipynb", - "sha256": "1c09519eb0c4e45dc0967f095c76724a41c7393e63058b1295bbd69620add470", - "size": 18059 + "sha256": "ee4a6017d63171639a08baa103d332449de111197228f20b6fcdb3b001b3ef58", + "size": 18730 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/multimodal/using_sub_agents.ipynb", "status": "success", "path": "github/claude-cookbooks/multimodal/using_sub_agents.ipynb", - "sha256": "536aea4539e118b42a643fc994f031e41b39a4cc9178fd195bbb162bc71bbffc", - "size": 19931 + "sha256": "4f094906f01dd5aaf13b4b088a39951695839f682131d71c71a7d892a5ed3b55", + "size": 51367 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/observability/opentelemetry_tracing.ipynb", @@ -24453,15 +24488,15 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/skills/CLAUDE.md", "status": "success", "path": "github/claude-cookbooks/skills/CLAUDE.md", - "sha256": "6ab9a994c77d36d244c93938407c67908496ca5a9347eb028fde69436d1205cc", - "size": 8202 + "sha256": "0455c49afc3625b9292db61fb9294aca899536bc401e88a752c10e998efcdc94", + "size": 8462 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/skills/README.md", "status": "success", "path": "github/claude-cookbooks/skills/README.md", - "sha256": "672a5958b74182fb2473bb02a9d7d3a4f7dd23ccd3ac3456ae6539c6f9b9ce60", - "size": 11698 + "sha256": "2cc2f1f4cc1f48c949db2599e3a164c1c6098d7d2caf7fed0240d69dcf83c534", + "size": 11813 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/skills/custom_skills/analyzing-financial-statements/SKILL.md", @@ -24495,22 +24530,22 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/skills/notebooks/01_skills_introduction.ipynb", "status": "success", "path": "github/claude-cookbooks/skills/notebooks/01_skills_introduction.ipynb", - "sha256": "276362eae5c9ae04035f099d042326858ade8dbedef89611d2bb824238489e92", - "size": 34927 + "sha256": "bae1b9b63919412e17954dd8310e3d8a5667d5c676451291ba0f4c5c4ee8523f", + "size": 34760 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/skills/notebooks/02_skills_financial_applications.ipynb", "status": "success", "path": "github/claude-cookbooks/skills/notebooks/02_skills_financial_applications.ipynb", - "sha256": "e78e508b64d4532835cc4a8cad1b761349be9e61c5bf656b9b30d4a98d7039d0", - "size": 37724 + "sha256": "f0308b7d8c40d5e91dec81bad2eb95107c1c2239e8acb7934d9c0f35d5a6f93d", + "size": 37751 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/skills/notebooks/03_skills_custom_development.ipynb", "status": "success", "path": "github/claude-cookbooks/skills/notebooks/03_skills_custom_development.ipynb", - "sha256": "30cd1581e209ef45c0379f140276ac355d2e7d384d1cbaba3c39cc25e9bc00cc", - "size": 48859 + "sha256": "3ea9a698218da068a4a173e17672c8d3de605b36ef7389d6b8164a9afe910eb9", + "size": 48543 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/third_party/Deepgram/README.md", @@ -24617,13 +24652,6 @@ "sha256": "af4cf0686ec5cba54d5f6492f73134d3a4004a6131029efbe2be395f65348d71", "size": 12995 }, - { - "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/third_party/Wikipedia/wikipedia-search-cookbook.ipynb", - "status": "success", - "path": "github/claude-cookbooks/third_party/Wikipedia/wikipedia-search-cookbook.ipynb", - "sha256": "d3bd4c4494763116ee9f1f9bcbd774561223c2a36b1ea95b067d287d8f2e69bb", - "size": 33119 - }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/third_party/WolframAlpha/using_llm_api.ipynb", "status": "success", @@ -24635,15 +24663,15 @@ "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/tool_evaluation/tool_evaluation.ipynb", "status": "success", "path": "github/claude-cookbooks/tool_evaluation/tool_evaluation.ipynb", - "sha256": "79f866c47380816cda5e25a004f3adc716988d7d15ee68c07a9d6d6fbafa3d33", - "size": 41405 + "sha256": "3dbfa3f52c034f50e7711ca26a073b21d5898b6ba80003987699f7b877863ba6", + "size": 34584 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/tool_use/automatic-context-compaction.ipynb", "status": "success", "path": "github/claude-cookbooks/tool_use/automatic-context-compaction.ipynb", - "sha256": "056b27aa1108bb775ed302bebaaca916e5da0f7e7f2efd40b6d1ba99685a0712", - "size": 60825 + "sha256": "51675584e68f3e1190752489cf5e480193481d3cd35c14c136d869104964e90f", + "size": 67665 }, { "url": "https://raw.githubusercontent.com/anthropics/claude-cookbooks/main/tool_use/calculator_tool.ipynb", @@ -31290,8 +31318,8 @@ } ], "summary": { - "total": 4598, - "downloaded": 4296, + "total": 4602, + "downloaded": 4300, "skipped": 0, "failed": 0, "dead": 302, diff --git a/content/CHANGELOG.md b/content/CHANGELOG.md index f160c851c1..9d784f1d3d 100644 --- a/content/CHANGELOG.md +++ b/content/CHANGELOG.md @@ -1,5 +1,95 @@ # Changelog +## 2.1.317 + +- Added a warning to `/schedule` when a new cloud scheduled task gets connectors you did not ask for, with how to remove them +- Added a check that asks before a web or shell tool call sends your account email address to the network +- Added `onFailure: "block"` for Agent SDK hook callbacks, so a callback that fails blocks the action instead of letting it run +- Added a notice in Claude Desktop's Code tab when your organization's remote managed settings haven't loaded for the session, and another once they do +- Added a notice when auto mode's check has no answer for a subagent's tool call, which used to leave nothing in the main view +- Added `anthropic.plan`, `anthropic.seat_type`, `anthropic.provider` and `anthropic.custom_base_url` to OTel metrics, events and spans +- Added a cost report to the Claude apps gateway admin API, `GET /v1/organizations/analytics/cost`, for reading past spend over a date range in total, per developer, per day or per IdP group +- Added a daily record of each developer's IdP groups on Claude apps gateways with `admin:` set, kept for `admin.identity_retention_days`, which the cost report groups by +- Added `CLAUDE_CODE_DISABLE_NESTED_SESSION_ID`: set it to `1` on a self-hosted runner to have `claude -p` run inside a session use that session's ID and transcript, as in earlier versions +- Fixed project and local MCP servers disconnecting after the first turn in some Claude desktop sessions +- Fixed auto mode failing every turn when an LLM gateway set as the base URL answers 403 or 422 to its server-side safety check (a 403 with an apiKeyHelper is unchanged) +- Fixed `claude auth status` exiting before a slow token refresh was saved, which could sign you out on the next run +- Fixed a project's `effortLevel` setting being ignored by sessions that an app starts ahead of time and then opens in the project, such as new sessions in the desktop app's Code tab +- Fixed `claude --from-pr` reporting "No conversations found" in projects with many sessions when the linked session was older than the first page +- Fixed the second of two simultaneous permission prompts showing no file path or command on claude.ai and the mobile apps +- Fixed Remote Control and SDK hosts offering "don't ask again" on a mod's tool calls +- Fixed session titles being lost in cloud and SDK sessions when a new message or Stop arrived while the title was generating +- Fixed self-paced `/loop` wakeups sometimes not being scheduled when Claude left a field out of its request +- Fixed auto mode in cloud sessions stopping for approval when the Artifact tool uploaded, wrote to a database or saved a file through the outputs folder +- Fixed skills synced from claude.ai being lost or downloaded again every ten minutes when they can't be written to disk +- Fixed `/schedule` leaving a cloud scheduled task's next run time and link out of its results after creating or updating it +- Fixed screen readers speaking a running subagent's elapsed time and token count on every change in screen reader mode +- Fixed a region or network block (HTTP 403) being shown as a sign-in failure; the error now explains the block +- Fixed Claude saying a working claude.ai connector needed authorization or had failed in cloud sessions when a synced plugin included the same server +- Fixed `claude -p` exiting 0 when a full disk or quota lost its transcript or ~/.claude.json writes; it now prints an error and, in text and json output, exits 1. Full NFS exports may be missed +- Fixed edits to settings files made in the first second or so after launch not taking effect until a settings file changed again +- Fixed old transcripts not being cleaned up on machines where some runs skip cleanup, such as runs using `--setting-sources` +- Fixed deleted agent team inboxes being re-created by a teammate's late message +- Fixed a re-created agent teammate being removed from its team by an earlier shutdown approval +- Fixed stored scheduled tasks being impossible to list or delete after scheduled tasks were turned off +- Fixed Claude deleting your most recently updated `/team-onboarding` guide when asked to delete one without naming which +- Fixed Claude saying a `/team-onboarding` guide was deleted when the server refused the delete +- Fixed the Claude apps gateway hiding Amazon Bedrock's "Input is too long." error, which left sessions failing every turn with "upstream rejected the request" instead of compacting +- Fixed self-hosted runner sessions losing recent turns or the whole conversation when restarted while a plan waited for approval +- Fixed "Prompt is too long" after automatic compaction in sessions whose very large CLAUDE.md changed since it was last sent +- Fixed high memory use and slow startup in headless sessions with many plugins that register commands +- Fixed stdio MCP servers receiving an empty `AWS_BEARER_TOKEN_BEDROCK` when their env config sets it to empty; the variable is now unset, so the server can use the machine's own AWS credentials +- Fixed API requests failing with "unable to get local issuer certificate" behind some TLS-inspecting proxies after a root certificate renewal +- Fixed very long conversations losing their earlier summary when compaction had to shorten its own request +- Fixed a PDF's own metadata being able to make Read and @-mentions under-count its pages +- Fixed `DISABLE_PROMPT_CACHING_OPUS` and `DISABLE_PROMPT_CACHING_SONNET` having no effect on `[1m]`, other-region and undated spellings of the default model +- Fixed `/artifacts` and the Artifact tool's shared list showing no shared artifacts when you have 200 or more of your own +- Fixed Claude treating partial Grep and Glob results as complete when a search hit its time limit +- Fixed OpenTelemetry exports to an `https://` endpoint through a proxy never being sent when they started while another export was still in progress +- Fixed a flood of connection attempts to a proxy that blocks (HTTP 403) OpenTelemetry exports to an `http://` endpoint +- Fixed OpenTelemetry exports hanging indefinitely behind a proxy that never answers; they now time out after 10 seconds, or `OTEL_EXPORTER_OTLP_TIMEOUT` up to 30 seconds +- Fixed resumed sessions telling Claude again about a file change it already knew about +- Fixed Claude sometimes not using a built-in tool in a resumed session after an earlier call failed because the tool was switched off +- Fixed `/remote-control` answering "Unknown command" instead of saying that Remote Control is turned off by the `disableRemoteControl` setting +- Fixed agent team teammates in tmux or iTerm2 panes starting in auto mode when the lead session was in manual mode +- Fixed a background session sometimes losing a just-made change of permission mode when it was upgraded or retired +- Fixed Ctrl+C stopping all running background agents when pressed to clear typed text at the prompt +- Fixed /feedback showing "Enter to confirm" while a report is being sent +- Fixed child processes of a stopped shell command sometimes being sent SIGTERM twice, which could make some programs skip their cleanup +- Fixed `claude -p` run inside a cloud or self-hosted runner session sharing that session's ID: it wrote into the session's transcript, and a restart could resume the wrong conversation +- Fixed `claude -p` run inside a cloud or self-hosted runner session generating a title of its own and sending it to that session +- Improved the error shown on Microsoft Foundry when Azure credentials can't be loaded: it now says to check or refresh them, and reports as `cloud_credential_error` +- Improved `/design-sync` to say up front when your design system has moved to Claude, and stop before building instead of failing at upload +- Improved the startup error when a required Claude apps gateway can't be reached: it points to the network instead of a sign-in, and says when the gateway's TLS certificate can't be verified +- Improved the "Resume this session with" hint shown at exit to repeat the flags you launched with (for example `--chrome --debug`) ahead of `--resume` +- Improved how self-hosted runners recover from server errors: after a 5xx other than 501 or 529, a runner's next poll now opens a new connection instead of reusing the one that failed +- Improved how self-hosted runner sessions recover from server errors: after a 5xx other than 501 or 529, a session now opens new connections instead of reusing the one that failed +- Improved how self-hosted runner sessions recover when connections stop answering: after a heartbeat gets no answer, a session now opens new connections instead of trying each idle one in turn +- Changed SendMessage so a message to a running background agent arrives earlier: its running command moves to the background, without being stopped +- Changed subagents and teammates on a different model from the main conversation to use that model's saved effort level or its default, instead of the session's effort level +- Changed exit to skip the "Background work is running" prompt for plugin monitors +- Changed the built-in `plugin-authoring` skill to offer once, after a mod you built works, to help share the mod +- Removed the Read tool's "file unchanged since your last Read" stub: reading an unchanged file again returns its content +- Windows: Fixed every tool call being refused on some volumes where the native path lookup fails; the working-directory check now compares the folder's identity instead +- Windows: Fixed the session scratchpad and other temporary paths growing with your project's path length in sessions not started by Claude Desktop, which made repositories cloned into them hit the 260-character path limit +- Gateway: Fixed the status line and `/usage` showing a developer's own spend limit as 100% used after their group's pooled budget ran out +- Self-hosted runner: Fixed Claude not seeing the interrupted tool call when a session moves to a new runner and the turn is older than `CLAUDE_CODE_RESUME_INTERRUPTED_TURN_MAX_AGE_MS` +- Self-hosted runner: Fixed an MCP server that was switched off coming back on after the session moved to a new machine, when the session service had refused to save the switch +- Remote Control: Improved fork names when the app doesn't set one: a long name keeps its "(fork)" ending, and in sessions started with `claude remote-control` a fork of "Name (fork)" is "Name (fork 2)" +- [VSCode] Fixed forked conversations dropping messages: only one of the tool calls Claude ran in parallel was kept, and the last messages a compaction kept were lost, which could leave Claude's answer without the question it answered +- [VSCode] Fixed a message being lost when Claude did not finish starting in time: the extension now starts Claude once more before showing the error +- [VSCode] Fixed the sign-in screen opening when a request is blocked for its region or network +- [VSCode] Fixed the Account panel showing the plan name with a lower-cased second word +- [VSCode] Fixed file links in a Claude tab opening on top of the chat instead of in another editor group +- [VSCode] Fixed attachment chips, menus, banners and dialogs in the Claude panel staying small when `chat.fontSize` is raised +- [VSCode] Fixed `ultrathink` not raising effort for its turn or showing its rainbow when telemetry is off +- [Cloud sessions] Added a link card to cloud sessions, so you can open or decline a link an MCP server asks you to visit instead of the request going unseen +- [Cloud sessions] Changed the organization environment dialog in admin settings to the personal dialogs' short layout: each section opens from a row, and unsaved input asks before closing +- [Cloud sessions] Fixed adding a network secret for a host that already has one silently replacing it; the Add secret form now refuses and points you to the existing secret +- [Cloud sessions] Fixed new scheduled tasks ignoring your organization's default environment: the form now starts on the one an admin chose instead of the Anthropic-hosted default +- [Remote Control] Fixed the next message to an idle session going unanswered after you restart `claude remote-control`, when you sent it within a minute of your previous message +- [Claude Tag] Changed newly pasted artifact links in Slack to show a simpler card with an Open button that opens the artifact in Claude, instead of Slack's side panel + ## 2.1.316 - Added `CLAUDE_CODE_DISABLE_ULTRATHINK`, which turns the `ultrathink` keyword off diff --git a/content/claude-code-manifest.json b/content/claude-code-manifest.json index f770dba6a4..16ced8141c 100644 --- a/content/claude-code-manifest.json +++ b/content/claude-code-manifest.json @@ -6,25 +6,25 @@ "url": "https://github.com/anthropics/claude-code/issues" }, "dist": { - "shasum": "6b2759942982d4f2fe4102e34c879fb34a8f3157", - "tarball": "https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-2.1.316.tgz", + "shasum": "e0940e4de0a4ea860e41af8af01248a11e85a1db", + "tarball": "https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-2.1.317.tgz", "fileCount": 7, - "integrity": "sha512-i3BpzyDkcCPnsa0CSkWgxGPs7WMsyqDkxkqT0SDxyEC5XMIxEmcUmluWRHG9VSeBY8Vyv+l9X34JvJ/Bj54nBQ==", + "integrity": "sha512-k467+KT/LcqJXr3Ye/C4lXnfRNmxOa/TZcIiWKoiyc/XbZGzAR0fxiI/IEOkpic+BFhYRP6BiXa7cvTx4fsOSg==", "signatures": [ { - "sig": "MEUCICXEbuxU4HVm4rtVjal/3VZHOW7rjw6/ISFC8P/ddyBJAiEAqQFbe9GS8tKqXjZ+0qtKoHHMrs+xdjpjUZ2mOkEhNf0=", + "sig": "MEUCIGMLUe8oLGZypixFf6CrPUHFzlxbUcV4gn3Rj2tYmy/dAiEA5VLcb4pYrkaUBAvpMA0LzWozBQz6anIeeY97+WPdrkg=", "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" }, { - "sig": "MEUCIQC+tvmmREe5I2Vv6HM0jo2OpAw3XGAYopDHsuEcbVyTigIgOBmpgF3K4UTvqE4Fk2eqQUT5hRmOi7dzwl7XvsvH4bo=", + "sig": "MEUCIQD/9T169QBiGHkdK2FAltt8NIzm4Zy4xuyLeo+Q+j0CXAIgJ1aBCvvkWpbhynS82ufunzGQ2Wsu7W/ZQSM68HuLnWg=", "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" } ], - "unpackedSize": 190269 + "unpackedSize": 190569 }, "name": "@anthropic-ai/claude-code", "type": "module", - "_from": "file:staged-npm/anthropic-ai-claude-code-2.1.316.tgz", + "_from": "file:staged-npm/anthropic-ai-claude-code-2.1.317.tgz", "author": { "name": "Anthropic", "email": "support@anthropic.com" @@ -46,8 +46,8 @@ } }, "homepage": "https://github.com/anthropics/claude-code", - "_resolved": "/home/runner/work/claude-cli-internal/claude-cli-internal/staged-npm/anthropic-ai-claude-code-2.1.316.tgz", - "_integrity": "sha512-i3BpzyDkcCPnsa0CSkWgxGPs7WMsyqDkxkqT0SDxyEC5XMIxEmcUmluWRHG9VSeBY8Vyv+l9X34JvJ/Bj54nBQ==", + "_resolved": "/home/runner/work/claude-cli-internal/claude-cli-internal/staged-npm/anthropic-ai-claude-code-2.1.317.tgz", + "_integrity": "sha512-k467+KT/LcqJXr3Ye/C4lXnfRNmxOa/TZcIiWKoiyc/XbZGzAR0fxiI/IEOkpic+BFhYRP6BiXa7cvTx4fsOSg==", "_npmVersion": "11.19.1", "description": "Use Claude, Anthropic's AI assistant, right from your terminal. Claude can understand your codebase, edit files, run terminal commands, and handle entire workflows for you.", "directories": {}, @@ -118,19 +118,19 @@ "_hasShrinkwrap": false, "readmeFilename": "README.md", "optionalDependencies": { - "@anthropic-ai/claude-code-linux-x64": "2.1.316", - "@anthropic-ai/claude-code-win32-x64": "2.1.316", - "@anthropic-ai/claude-code-darwin-x64": "2.1.316", - "@anthropic-ai/claude-code-linux-arm64": "2.1.316", - "@anthropic-ai/claude-code-win32-arm64": "2.1.316", - "@anthropic-ai/claude-code-darwin-arm64": "2.1.316", - "@anthropic-ai/claude-code-linux-x64-musl": "2.1.316", - "@anthropic-ai/claude-code-linux-arm64-musl": "2.1.316" + "@anthropic-ai/claude-code-linux-x64": "2.1.317", + "@anthropic-ai/claude-code-win32-x64": "2.1.317", + "@anthropic-ai/claude-code-darwin-x64": "2.1.317", + "@anthropic-ai/claude-code-linux-arm64": "2.1.317", + "@anthropic-ai/claude-code-win32-arm64": "2.1.317", + "@anthropic-ai/claude-code-darwin-arm64": "2.1.317", + "@anthropic-ai/claude-code-linux-x64-musl": "2.1.317", + "@anthropic-ai/claude-code-linux-arm64-musl": "2.1.317" }, "_npmOperationalInternal": { - "tmp": "tmp/claude-code_2.1.316_1793407325632_0.2126345631060963", + "tmp": "tmp/claude-code_2.1.317_1793663872972_0.711556673961046", "host": "s3://npm-registry-packages-npm-production" }, - "_id": "@anthropic-ai/claude-code@2.1.316", - "version": "2.1.316" + "_id": "@anthropic-ai/claude-code@2.1.317", + "version": "2.1.317" } \ No newline at end of file diff --git a/content/claude/connectors/building/enterprise-managed-auth.md b/content/claude/connectors/building/enterprise-managed-auth.md index 0e1cb3baeb..03df0ff022 100644 --- a/content/claude/connectors/building/enterprise-managed-auth.md +++ b/content/claude/connectors/building/enterprise-managed-auth.md @@ -4,13 +4,13 @@ # Enterprise Managed Auth for connectors -> Accept identity assertions from enterprise SSO so users connect to your MCP server without a separate OAuth consent step. +> Accept identity assertions from a customer's identity provider or Claude so users connect to your MCP server without an OAuth consent step. > [!NOTE] > > Enterprise Managed Auth is available on Claude Team and Enterprise plans. After your authorization server supports it, email `mcp-review@anthropic.com` to have [your directory listing](https://claude.com/docs/connectors/building/managing-your-listing.md) marked as supporting Enterprise Managed Auth. -Enterprise Managed Auth (EMA) lets a user connect to your MCP server silently, using the single sign-on session they already have with their organization. Instead of showing each user an OAuth consent screen, Claude presents your authorization server with an identity assertion: a signed JSON Web Token (JWT), issued by the customer's identity provider, that vouches for the user's identity. +Enterprise Managed Auth (EMA) lets organizations connect their users to your MCP server without sending each user through an OAuth consent screen. Claude presents your authorization server with an identity assertion instead: a signed JSON Web Token (JWT) that vouches for the user's identity. Either the customer's identity provider or Claude signs the assertion, depending on [how the customer set up Enterprise Managed Auth](#who-issues-the-identity-assertion). Your authorization server validates the assertion and returns an access token in a single back-channel request. There is no browser redirect and no per-connector consent page. From the user's point of view, the connector is available as soon as their administrator enables it. @@ -20,11 +20,18 @@ This page is for connector developers who need their authorization server to acc When a user whose organization has Enterprise Managed Auth configured invokes your connector, Claude obtains a signed identity assertion for that user and exchanges it directly at your token endpoint for an access token. The user never sees a browser redirect or a consent screen, and your MCP server receives the same kind of bearer token it would after the interactive OAuth flow. The diagram shows the exchange between Claude, your authorization server, and your MCP server. -![Sequence diagram with three participants: Claude, your authorization server, and your MCP server. The user is already signed in to Claude through their organization's single sign-on. 1, Claude sends POST /token to your authorization server with the jwt-bearer grant and the signed JWT assertion. 2, your authorization server fetches the issuer's JWKS and verifies the signature. 3, it validates iss, aud, exp, sub, and client\_id. 4, it returns an access\_token to Claude. 5, Claude sends the tool call to your MCP server with the Bearer access\_token. 6, your MCP server returns the tool result to Claude. Requests are solid arrows and responses are dashed arrows.](https://mintcdn.com/claude-ai/-njlLvrWxFCRdJVz/images/connectors/enterprise-managed-auth-exchange.svg?fit=max\&auto=format\&n=-njlLvrWxFCRdJVz\&q=85\&s=2bdd0b680bda337b37632516b8dc5e84) +![Sequence diagram with three participants: Claude, your authorization server, and your MCP server. The user is already signed in to Claude. 1, Claude sends POST /token to your authorization server with the jwt-bearer grant and the signed JWT assertion. 2, your authorization server checks that iss is the issuer registered for the workspace, fetches that issuer's keys, and verifies the signature. 3, it validates typ, aud, client\_id, exp, and jti. 4, it returns an access\_token to Claude. 5, Claude sends the tool call to your MCP server with the Bearer access\_token. 6, your MCP server returns the tool result to Claude. Requests are solid arrows and responses are dashed arrows.](https://mintcdn.com/claude-ai/sb_HHLiaouvnOmRA/images/connectors/enterprise-managed-auth-exchange.svg?fit=max\&auto=format\&n=sb_HHLiaouvnOmRA\&q=85\&s=14077dd8e8d93a01f20bd21b1c031029) -Two parties are involved in this exchange: the customer's identity provider signs the assertion, and your authorization server verifies it and issues the access token. Both roles are often served by commercial identity platforms, so the distinction here is about which tenant plays which role rather than about product type. The identity provider publishes its signing keys as a JSON Web Key Set, and your authorization server fetches that key set to verify each assertion. +The Enterprise Managed Auth flow is defined by the [MCP enterprise managed authorization extension](https://modelcontextprotocol.io/extensions/auth/enterprise-managed-authorization) and is built on the standard [JWT bearer authorization grant (RFC 7523)](https://datatracker.ietf.org/doc/html/rfc7523). The assertion profile follows the [Identity Assertion JWT Authorization Grant (ID-JAG)](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/). -The Enterprise Managed Auth flow is defined by the [MCP enterprise managed authorization extension](https://modelcontextprotocol.io/extensions/auth/enterprise-managed-authorization) and is built on the standard [JWT bearer authorization grant (RFC 7523)](https://datatracker.ietf.org/doc/html/rfc7523). The assertion profile follows the [Identity Assertion JWT Authorization Grant](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant/). +### Who issues the identity assertion + +Each customer workspace in your product trusts one issuer of identity assertions. The issuer for a customer is one of the following: + +* **Identity provider-issued**: the customer's identity provider issues and signs the assertion for a user who signed in to Claude through the organization's single sign-on (SSO). The trusted issuer is the identity provider's issuer URL. The customer needs an identity provider that can issue identity assertions. +* **Claude-issued**: Claude issues and signs the assertion under an issuer URL that belongs to the customer's Claude organization. The URL has the form `https://identity.anthropic.com/issuers/`. The trusted issuer is that Claude issuer URL. Claude-issued assertions are in beta. + +Where Claude's managed authorization setup offers both, the administrator sees them under **Identity source** as **IdP-managed** and **Claude-issued**. The token format and the exchange at your token endpoint are the same in both cases. The issuer publishes its signing keys as a JSON Web Key Set, and your authorization server fetches that key set to verify each assertion. ### Enterprise Managed Auth with lazy authentication @@ -43,13 +50,13 @@ Before adding Enterprise Managed Auth, make sure the following are already in pl > [!WARNING] > -> Dynamic Client Registration (DCR) isn't supported with Enterprise Managed Auth. The identity provider stamps a fixed `client_id` into every assertion it issues, so your authorization server must already recognize that client before the first assertion arrives. A client created on the fly through DCR can't satisfy this requirement because its identifier never matches the value in the assertion. +> Dynamic Client Registration (DCR) isn't supported with Enterprise Managed Auth. Register Claude through [Anthropic-held client credentials](https://claude.com/docs/connectors/building/authentication.md#anthropic-held-client-credentials) or a [Client ID Metadata Document](https://claude.com/docs/connectors/building/authentication.md#dcr-and-cimd-details) before the first assertion arrives. When the customer's identity provider issues the assertions, it stamps a fixed `client_id` into every one, so your authorization server must already recognize that client. A client created on the fly through DCR can't satisfy this requirement because its identifier never matches the value in the assertion. ## Authorization server requirements -Your authorization server must support the JWT bearer authorization grant ([RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523)), which lets an authorization server exchange a signed JWT for an access token, and must trust each customer's identity provider as an issuer. This section is for the authorization server operator. +Your authorization server must support the JWT bearer authorization grant ([RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523)), which lets an authorization server exchange a signed JWT for an access token, and must trust one issuer of identity assertions for each customer. This section is for the authorization server operator. -If your MCP server relies on a hosted identity platform, there is typically no code to write. Confirm that the platform supports the JWT bearer authorization grant and enable it for your tenant. Support varies by product, and some commercial authorization servers and identity platforms don't support it yet, so confirm that yours does and that the customer's identity provider can be registered as a trusted issuer. If you run your own authorization server, the steps in this section describe what it needs to support. +If your MCP server relies on a hosted identity platform, you may not need to write code. Confirm that the platform supports the JWT bearer authorization grant, that it runs every check in [Validate the identity assertion](#validate-the-identity-assertion), and that it can register an issuer URL that isn't the customer's identity provider as a trusted issuer. Support varies by product, and some commercial authorization servers and identity platforms don't support the grant yet. If you run your own authorization server, the steps in this section describe what it needs to support. **1. Ensure the JWT bearer grant is supported** @@ -69,15 +76,28 @@ Your authorization server must accept `urn:ietf:params:oauth:grant-type:jwt-bear Claude reads this metadata to discover whether your server supports Enterprise Managed Auth. The grant type must be listed here for Claude to offer the feature to the customer, even if your token endpoint would already accept it silently. +Claude sends assertions when your metadata also meets these conditions: + +* The `issuer` matches the URL Claude fetched the metadata from, as [RFC 8414 section 3.3](https://datatracker.ietf.org/doc/html/rfc8414#section-3.3) requires +* The `token_endpoint` is on the same registrable domain as the `issuer`. Different hosts under that domain work, such as `https://api.example.com/token` for the issuer `https://www.example.com` +* For Claude-issued assertions, the `issuer` is a plain `https` URL on a public domain name, with no user name, query, fragment, percent-escapes, or characters such as commas and semicolons + +Keep the `issuer` value exactly as published, trailing slash included. A Claude-issued setup records the value, and a changed value stops sign-ins for that customer. + **2. Register the trusted issuer** -For each customer, your authorization server needs to trust that customer's identity provider as a JWT issuer. Your authorization server fetches the identity provider's JSON Web Key Set and uses it to verify the signature on every incoming assertion. +For each customer workspace, your authorization server trusts one issuer of identity assertions. The customer's administrator gives you the issuer URL, which is one of the following: -Your authorization server is responsible for maintaining an explicit allowlist of trusted issuer URLs per tenant rather than accepting any well-formed JWT. It must reject an assertion whose `iss` isn't on the tenant's allowlist with `invalid_grant`, even if the signature is valid. +* **Identity provider-issued**: the issuer URL of the customer's identity provider +* **Claude-issued**: a Claude issuer URL of the form `https://identity.anthropic.com/issuers/`, where `` differs for each customer's Claude organization + +Keep an explicit trusted issuer for each workspace rather than accepting any well-formed JWT. Allow that issuer to be a Claude issuer URL, not only a URL on an identity provider's domain. The first check in [Validate the identity assertion](#validate-the-identity-assertion) rejects an assertion whose `iss` isn't an exact match for the workspace's registered issuer, before any key is fetched. + +Bind each issuer to one workspace, and resolve each assertion to exactly one workspace. If the same issuer URL is registered for more than one workspace, don't guess between them. Find the one workspace an assertion is for as [Validate the identity assertion](#validate-the-identity-assertion) describes. > [!WARNING] > -> Never accept an identity assertion without full validation. Your authorization server must verify the signature, issuer, audience, expiry, and subject on every request. Use the JWT validation built into your authorization server product. If you need to inspect assertions in your own code, use the validation library or token introspection endpoint provided by your authorization server vendor rather than writing custom verification logic. +> Never accept an identity assertion without full validation. Your authorization server must run every check in [Validate the identity assertion](#validate-the-identity-assertion) on every request. Use the JWT validation built into your authorization server product. If you need to inspect assertions in your own code, use the validation library or token introspection endpoint provided by your authorization server vendor rather than writing your own signature verification. **3. Understand the token request** @@ -91,31 +111,112 @@ Content-Type: application/x-www-form-urlencoded grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer &assertion=eyJhbGciOi... &client_id=your-registered-client-id -&scope=openid profile +&scope=read%20write &resource=https://mcp.example.com ``` -The `assertion` parameter carries the signed JWT. The `client_id` is the value Claude is registered under at your authorization server. Claude also includes the `resource` parameter ([Resource Indicators, RFC 8707](https://www.rfc-editor.org/rfc/rfc8707)) set to your MCP server URL whenever the customer's identity provider supports forwarding it. Some identity provider configurations cannot pass a resource indicator through, so your authorization server should accept the request whether or not `resource` is present and use it for audience binding when it is. +Client authentication is left out of this example. The `assertion` parameter carries the signed JWT. The `client_id` is the value Claude is registered under at your authorization server, which for a Client ID Metadata Document is the document's URL. If that client has a secret or key, require it on this request. Answer at the `token_endpoint` URL itself, because Claude doesn't follow redirects on this request. -Your authorization server validates the assertion according to the [JWT bearer token processing rules (RFC 7523 section 3)](https://datatracker.ietf.org/doc/html/rfc7523#section-3) and returns a standard OAuth token response. Claude then presents the returned access token as a `Bearer` credential on calls to your MCP server, exactly as it does after the interactive flow. +Claude includes the `resource` parameter ([Resource Indicators, RFC 8707](https://www.rfc-editor.org/rfc/rfc8707)) as follows: -> [!NOTE] +* **Identity provider-issued**: whenever the customer's identity provider supports forwarding it. Some identity provider configurations can't pass a resource indicator through +* **Claude-issued**: always, set to the `resource` in your Protected Resource Metadata when that is your MCP server's URL or a parent of it, and otherwise to your MCP server's URL + +Accept the request whether or not `resource` is present, and use it for audience binding when it is. + +Your authorization server [validates the assertion](#validate-the-identity-assertion) and returns a standard OAuth token response with an access token. Include `expires_in` so Claude knows when to get a new token. Claude doesn't use a refresh token from this grant, so don't issue one. Claude then presents the returned access token as a `Bearer` credential on calls to your MCP server, exactly as it does after the interactive flow. + +### Validate the identity assertion + +Run these checks, in this order, on every token request, whichever kind of issuer signed the assertion. When a check fails, reject the request with `invalid_grant`, as the [JWT bearer token processing rules (RFC 7523 section 3)](https://datatracker.ietf.org/doc/html/rfc7523#section-3) require. + +Before the first check, find the one workspace the assertion is for. If you identify workspaces by your own tenant ID and the assertion carries `aud_tenant`, take the workspace that `aud_tenant` names. A Claude-issued assertion carries the claim when the customer's administrator entered your tenant ID in Claude's managed authorization setup for your connector, and Claude doesn't check the value. Otherwise, take the workspace that registered `iss`, and reject the assertion if no workspace or more than one did. + +1. **Issuer**: `iss` equals, as an exact string, the trusted issuer registered for that workspace. A prefix or host match admits other customers' users. Check this before you fetch any keys. +2. **Keys**: fetch `/.well-known/openid-configuration`, confirm that the document's `issuer` equals `iss`, and fetch the key set from the document's `jwks_uri`. Use only keys from that key set, and ignore any key or key URL carried in the assertion's header. Don't pin a single key. Cache keys for as long as the response headers allow, and fetch them again when an assertion names a `kid` you haven't seen. +3. **Signature**: the signature verifies against a key from that key set. Accept ES256 and RS256, and reject every other `alg`, including `none` and HMAC algorithms such as HS256. Claude-issued assertions use ES256. +4. **Type**: the `typ` header is `oauth-id-jag+jwt`. Check `typ` yourself if your JWT library doesn't check it. +5. **Audience**: `aud` is your authorization server's own `issuer` value, exactly as your metadata publishes it. The claim can arrive as a string or as a JSON array with one element, so use your library's audience option rather than comparing the raw claim text. +6. **Client**: the `client_id` claim equals the `client_id` of this request. +7. **Subject**: a `sub` claim is present. [Claude-issued assertions](#claude-issued-assertions) identify the user by `email`, not by `sub`. +8. **Time**: `exp` hasn't passed, `iat` isn't in the future, and `nbf`, when present, has passed. Allow at most 60 seconds of clock skew. +9. **Replay**: a `jti` claim is present. Accept each `jti` from an issuer once, and remember it at least until the assertion's `exp` plus your clock-skew allowance. Treat `jti` as an opaque string. If you can't check whether a `jti` was already used, reject the request. + +Issue the access token for that workspace only, even when the same user belongs to other workspaces in your product. + +### Claude-issued assertions + +Claude signs a Claude-issued assertion under the issuer URL of the customer's Claude organization, and the checks in [Validate the identity assertion](#validate-the-identity-assertion) apply to it unchanged. This example shows the decoded payload of one: + +```json theme={null} +{ + "iss": "https://identity.anthropic.com/issuers/", + "sub": "abcdefghijklmnopqrstuvwxyz", + "email": "alex@example.com", + "aud": ["https://auth.example.com"], + "client_id": "your-registered-client-id", + "scope": "read write", + "aud_tenant": "your-tenant-id", + "iat": 1790000000, + "nbf": 1789999985, + "exp": 1790000060, + "jti": "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +} +``` + +* **What the assertion says**: the user is a current member of the customer's Claude organization, and `email` is the address of their Claude account, in lowercase. The assertion doesn't say that the user signed in through the customer's identity provider or used multi-factor authentication, and it carries no `sub_id` claim and no groups. +* **Signing keys**: every Claude issuer signs with the same keys, so a valid signature doesn't tell you which Claude organization an assertion is for. Only `iss` does. +* **Discovery document**: a Claude issuer serves its discovery document at `/.well-known/openid-configuration`. The document holds `issuer` and `jwks_uri` and has no `authorization_endpoint` or `token_endpoint`, so read those two members yourself rather than passing the document to a validator that expects a full OpenID Connect provider configuration. +* **Lifetime**: each assertion expires within a minute. Claude signs a new assertion, with a new `jti`, for each sign-in and each renewal. +* **User lookup**: find the user by `email` among the members of the workspace the assertion resolved to. Compare the whole address, ignore letter case, and keep dots and plus tags as they are. The `sub` claim is an opaque value that differs under each issuer, so don't look users up by it. Storing it is optional. If no member of the workspace has the address, reject the request, or create the user only when the address is on an email domain the workspace has verified with your service. + +> [!WARNING] > -> Your authorization server sets the access token lifetime, and the customer's identity provider sets the assertion lifetime. Anthropic doesn't control either value. +> Sign a user in from a Claude-issued assertion only when your service has verified that user's email address, or when the address is on an email domain the workspace has verified. A Claude issuer URL isn't a secret, so someone can register another customer's issuer URL in a workspace they control. ### Access token lifetime -Issue access tokens with whatever lifetime your security policy calls for. A short lifetime, such as one hour, doesn't force users to repeat single sign-on each time a token expires. +Issue access tokens with whatever lifetime your security policy calls for. A short lifetime, such as one hour, doesn't make users sign in again each time a token expires. Claude gets a new identity assertion without any user interaction and exchanges it at your token endpoint for a new access token. Claude gets each new assertion as follows: -When a user signs in to Claude through their organization's SSO, Claude obtains a long-lived refresh token from the identity provider. Claude uses that refresh token to request a fresh identity assertion from the identity provider whenever it needs one, without any user interaction. Claude then exchanges the new assertion at your token endpoint for a new access token. From the user's point of view, the connection stays active for as long as the identity provider's refresh token remains valid. +* **Identity provider-issued**: when a user signs in to Claude through their organization's SSO, Claude obtains a long-lived refresh token from the identity provider and uses it to request each new assertion. The connection stays active for as long as that refresh token remains valid +* **Claude-issued**: Claude signs each new assertion itself, for as long as the user remains a member of the customer's Claude organization -The customer's identity provider issues the refresh token. Treat it as long-lived. +When a user is removed from the customer's Claude organization, Claude stops signing Claude-issued assertions for them. Access tokens you already issued stay valid, so your access token lifetime bounds how long a removed user keeps access. ## Test your implementation -End-to-end testing requires a Claude organization with Enterprise Managed Auth enabled and an identity provider tenant configured to issue assertions for your authorization server's audience. +Test end to end from a Claude organization on a Team or Enterprise plan. + +**1. Add your MCP server as a custom connector** + +Add your MCP server as a custom connector for the test organization, as [Add the connector for the organization](https://claude.com/docs/connectors/custom/add-unlisted.md#add-the-connector-for-the-organization) describes. + +**2. Open the managed authorization setup** + +Open the connector you added. In its **Authentication** section, which is separate from the **Authentication** setting you chose while adding the connector, click **Set up** on the **Managed authorization** row. Under **Identity source**, choose **IdP-managed** or **Claude-issued**. + +**3. Register the issuer in your test workspace** + +Register the issuer URL as the trusted issuer of a test workspace in your product. For **Claude-issued**, copy the **Issuer URL** that the setup shows into your test workspace, and if you identify workspaces by your own tenant ID, enter the test workspace's ID in **Tenant ID (optional)**. + +**4. Run the connection test** -If your identity provider is Okta, refer to Okta's [Cross App Access participation guide](https://support.okta.com/help/s/article/claude-enterprise-managed-auth-with-okta-cross-app-access-xaa-beta-participation-guide?language=en_US) and configure your organization so you can test your MCP server's Cross App Access (XAA) implementation. +Click **Run test** under **Connection status**. The test shows which step failed, what Claude sent and what came back, and, for a Claude-issued assertion that was signed, its decoded claims. + +For each kind of assertion, the test organization also needs the following: + +* **Identity provider-issued**: an identity provider tenant configured to issue assertions for your authorization server's audience. If your identity provider is Okta, refer to Okta's [Cross App Access participation guide](https://support.okta.com/help/s/article/claude-enterprise-managed-auth-with-okta-cross-app-access-xaa-beta-participation-guide?language=en_US) and configure your organization so you can test your MCP server's Cross App Access (XAA) implementation. +* **Claude-issued**: no identity provider. The organization needs **Claude-issued** available under **Identity source**. If your organization doesn't offer Claude-issued, email `mcp-review@anthropic.com`. + +Check each of these cases before you launch: + +* An assertion from the workspace's registered issuer signs the right user in +* An assertion that carries another customer's issuer URL is refused +* An assertion whose `iss` is registered for more than one workspace is refused, unless you identify workspaces by your own tenant ID and the assertion's `aud_tenant` names one of those workspaces +* The same assertion presented a second time is refused +* An assertion whose `aud` isn't your authorization server's issuer is refused +* For a Claude-issued assertion, the user is found by verified email within the workspace the assertion resolved to, not by `sub` +* A Claude-issued assertion for an address your service hasn't verified, on a domain the workspace hasn't verified, is refused ### Test with the cross-app access playground @@ -133,16 +234,31 @@ A customer's administrator turns on Enterprise Managed Auth for their organizati ### Admin settings in your product -In your product's admin settings, give each customer's administrator a control that turns Enterprise Managed Auth on or off for their organization and a field for their identity provider's issuer URL. When the administrator saves, add that URL to the organization's allowlist of trusted issuers, as described in [Authorization server requirements](#authorization-server-requirements). +In your product's admin settings, give each customer's administrator a control that turns Enterprise Managed Auth on or off for their workspace and a field for the trusted issuer URL. Accept only an `https` URL in the field, and let only the workspace's administrators set it. The administrator copies the URL from their identity provider or, for Claude-issued assertions, from the **Issuer URL** box in Claude's managed authorization setup for your connector. When the administrator saves, register the URL as the workspace's trusted issuer, as described in [Authorization server requirements](#authorization-server-requirements). + +If you identify workspaces by your own tenant ID, show that ID in the same settings. The administrator enters it in the **Tenant ID (optional)** field in Claude's managed authorization setup for your connector, and it then arrives in each Claude-issued assertion as `aud_tenant`. ### Provide setup documentation -You can publish documentation that walks an enterprise administrator through enabling Enterprise Managed Auth for your product and add its URL to [your directory listing](https://claude.com/docs/connectors/building/managing-your-listing.md). Claude shows the link in the Claude admin console when an administrator sets up Enterprise Managed Auth for your connector. +Publish documentation that walks an enterprise administrator through enabling Enterprise Managed Auth for your product, including how to enter a Claude issuer URL as the trusted issuer, and add its URL to [your directory listing](https://claude.com/docs/connectors/building/managing-your-listing.md). Claude shows the link in the Claude admin console when an administrator sets up Enterprise Managed Auth for your connector. ### Okta Integration Network apps If your product has an app in the Okta Integration Network, work with Okta to enable Cross App Access (XAA) for that app. Until that app supports Cross App Access, customers who use Okta need to create a custom app in Okta for your product before they can set up Enterprise Managed Auth. +## Launch checklist + +Confirm each of the following before you ask Anthropic to mark your directory listing as supporting Enterprise Managed Auth: + +* Sign-in works end to end for each kind of assertion your server accepts +* Every case in [Test your implementation](#test-your-implementation) passes, including the refused ones +* Your admin settings let a customer's administrator set the trusted issuer for their workspace +* Your setup documentation for administrators is published, and its URL is on [your directory listing](https://claude.com/docs/connectors/building/managing-your-listing.md) + +Then email `mcp-review@anthropic.com` with your listing's name and the kinds of assertion your server accepts. If your connector isn't listed yet, [submit it](https://claude.com/docs/connectors/building/submission.md) before you email. Anthropic reviews the request and sets which kinds the listing is marked as supporting. + +Until the listing is marked, Claude doesn't offer managed authorization for it to customers' administrators. An administrator can choose **Claude-issued** for your listing only after it is marked for Claude-issued assertions. + ## Related resources * [Authentication for connectors](https://claude.com/docs/connectors/building/authentication.md): baseline OAuth requirements your server must already meet diff --git a/content/claude/government/security/security-and-data-handling.md b/content/claude/government/security/security-and-data-handling.md index ddb945bdb4..59869932d2 100644 --- a/content/claude/government/security/security-and-data-handling.md +++ b/content/claude/government/security/security-and-data-handling.md @@ -151,7 +151,9 @@ In Claude for Government, Anthropic-bound error and usage telemetry is always di > [accordion] What is logged for connector actions and outbound requests? > -> Chat and Cowork sessions write a local audit log to the user's disk recording tool invocations, permission decisions, and file operations; that log never leaves the device. The desktop can also export OpenTelemetry events to a collector you specify: tool name, connector, outcome, duration, and approval status are sent. Prompt text, Claude's responses, and tool inputs and results are included only for the categories you select in the **Telemetry content capture** setting on the [Config](https://claude.com/docs/government/config/settings.md#telemetry-content-capture) page. See [Telemetry and egress](https://claude.com/docs/third-party/claude-desktop/telemetry.md) for what the export can include. Server-side, the [Compliance API](https://claude.com/docs/government/org-admin/compliance-api.md) records identity and configuration events but never tool calls or conversation content. +> Chat and Cowork sessions write a [local audit log](https://claude.com/docs/third-party/claude-desktop/data-storage.md#session-audit-log) to the user's disk recording prompt text, Claude's responses, tool inputs and results, and permission decisions. The app doesn't send that log off the device. +> +> The desktop can also export OpenTelemetry events to a collector you specify: tool name, connector, outcome, duration, and approval status are sent. The export includes prompt text, Claude's responses, and tool inputs and results only for the categories you select in the **Telemetry content capture** setting on the [Config](https://claude.com/docs/government/config/settings.md#telemetry-content-capture) page. See [Telemetry and egress](https://claude.com/docs/third-party/claude-desktop/telemetry.md) for what the export can include. Server-side, the [Compliance API](https://claude.com/docs/government/org-admin/compliance-api.md) records identity and configuration events but never tool calls or conversation content. ### Data storage and retention diff --git a/content/claude/third-party/claude-desktop/chat.md b/content/claude/third-party/claude-desktop/chat.md index c78268b79e..2977a258f3 100644 --- a/content/claude/third-party/claude-desktop/chat.md +++ b/content/claude/third-party/claude-desktop/chat.md @@ -109,4 +109,4 @@ While `desktopHome` is unset and Unified Claude is off, at least one surface mus ## Where Chat data lives -Chat conversations are stored on the local device, in the same per-session layout as Cowork sessions: conversation history, attachment copies, scratch outputs, and a tamper-evident audit log, all under the application-data directory. Nothing is synced to a server, and there is no server-side index of past conversations. See [Chat conversations](https://claude.com/docs/third-party/claude-desktop/data-storage.md#chat-conversations) on the data-storage page for the breakdown. +Chat conversations are stored on the local device, in the same per-session layout as Cowork sessions: conversation history, attachment copies, scratch outputs, and an [audit log](https://claude.com/docs/third-party/claude-desktop/data-storage.md#session-audit-log), all under the application-data directory. Nothing is synced to a server, and there is no server-side index of past conversations. See [Chat conversations](https://claude.com/docs/third-party/claude-desktop/data-storage.md#chat-conversations) on the data-storage page for the breakdown. diff --git a/content/claude/third-party/claude-desktop/data-storage.md b/content/claude/third-party/claude-desktop/data-storage.md index 14ee0f66c2..e845cbbf5d 100644 --- a/content/claude/third-party/claude-desktop/data-storage.md +++ b/content/claude/third-party/claude-desktop/data-storage.md @@ -38,7 +38,7 @@ Within the application-data directory: | `local-agent-mode-sessions/` | Cowork and Chat conversation history. One `local_.json` file plus a working directory per session, scoped by the `ant-did` device identifier and the organization ID, not by who is signed in to the app. The working directory includes an `uploads/` subdirectory with copies of files attached to the conversation and an `outputs/` subdirectory for files Claude creates. | | `local-agent-mode-sessions/.../memory/` | Cowork memory: a `CLAUDE.md` instructions file plus a `memory/` subdirectory of Markdown notes Claude writes about the user's preferences, projects, and feedback. See [Memory](#memory). | | `local-agent-mode-sessions/.../spaces//memory/` | Markdown memory notes for one project, used by Cowork sessions and Chat conversations inside that project. See [Memory](#memory). | -| `local-agent-mode-sessions/...//audit.jsonl` | Append-only log of session events (tool invocations, permission decisions, file operations). Each entry is HMAC-chained to the previous one so edits or deletions are detectable; the companion `.audit-key` file holds the per-session signing key, encrypted via the OS keychain. | +| `local-agent-mode-sessions/...//audit.jsonl` | Log of one Cowork session or Chat conversation. It holds the full text of prompts, Claude's responses, and tool inputs and results. See [Session audit log](#session-audit-log). | | `claude-code-sessions/` | Code session records holding each session's working folder, settings, title, and sometimes a short summary. The conversation transcripts themselves are in Claude Code's own store at `~/.claude/projects/`, outside this directory. | | `claude-code/`, `claude-code-vm/` | Claude Code binary and VM workspace data for Code sessions. | | `vm_bundles/` | Cached copy of the VM workspace bundle that Cowork sessions run in, plus the data disk the app creates to hold those sessions' home directories inside the VM. | @@ -51,6 +51,26 @@ The logs directory contains `main.log` (application and configuration-validation Separately from the application-data directory, Claude Desktop writes user-visible outputs (Artifacts and scheduled-task results) to `~/Claude/` in your home directory, or `~/Documents/Claude/` on legacy installs. This folder is intended for you to browse directly and is not removed when you delete the application-data directory. To back up a user's data, copy every location listed under [Copy the data to the new device](#copy-the-data-to-the-new-device). +### Session audit log + +As a Cowork session or Chat conversation runs on the device, the app writes an `audit.jsonl` file in the session's working directory, under `local-agent-mode-sessions/` in the [application-data directory](#where-data-lives). The file holds the conversation's content. The session's transcript, under the same directory, holds it too. The app appends the full text of: + +* The user's prompts +* Claude's responses +* Tool inputs and results, such as the text of a file that Claude reads or writes + +The file also records any thinking text that Claude returns, permission decisions, and session details such as the model and token usage. Code sessions don't write this file. + +The app handles the file as follows: + +* **Protection**: the file isn't encrypted, so protection at rest depends on the device's full-disk encryption +* **Transfer**: the app doesn't send the file off the device +* **Deletion**: the app deletes the file with its session. By default, a session stays until the user deletes it, as described under [Automatic deletion of idle sessions](#automatic-deletion-of-idle-sessions). +* **Configuration**: no configuration key, including [`otlpContentCapture`](https://claude.com/docs/third-party/claude-desktop/telemetry#content-capture), turns the file off or changes what it records +* **Signing**: when the app has a signing key for the session, in the `.audit-key` file beside the log, each entry carries a keyed hash (HMAC) linked to the signed entries before it. Otherwise, entries are unsigned. The app doesn't check these hashes, and they don't reveal entries removed from the end of the file. + +To retain an audit trail, use the [OpenTelemetry export](https://claude.com/docs/third-party/claude-desktop/telemetry.md#sending-telemetry-to-your-own-collector) to your own collector. + ## Memory During Cowork sessions, Claude writes short Markdown files recording what it has learned about the user — working preferences, project context, and corrections — and reads them at the start of subsequent sessions. These files live under `local-agent-mode-sessions/.../memory/memory/` and never leave the device. @@ -69,7 +89,7 @@ To review a project's memory files, users go to **Projects**, open the project, ## Chat conversations -[Chat](https://claude.com/docs/third-party/claude-desktop/chat.md) conversations follow the same storage model as Cowork sessions: each conversation is a session state file plus a working directory under `local-agent-mode-sessions/`, in the layout described in the table above. The state file records the conversation; the working directory holds the transcript, an `uploads/` directory with copies (or hard links) of files attached to the conversation, an `outputs/` directory for files Claude creates during the conversation (its scratch space), and the same HMAC-chained `audit.jsonl` event log. Because attachments are hard-linked where the filesystem allows it, edits made to the original file while the conversation is open can be visible to the conversation. Conversation content leaves the device only as inference requests to your configured provider, as web search queries to your configured search backend, through web access your egress configuration allows, through [sandbox network access](https://claude.com/docs/third-party/claude-desktop/chat.md#sandbox-network-access), in connector tool calls permitted by your `toolPolicy` configuration and the user's approvals, and, if you have enabled [content capture](https://claude.com/docs/third-party/claude-desktop/telemetry.md#content-capture), in telemetry to your own collector. +[Chat](https://claude.com/docs/third-party/claude-desktop/chat.md) conversations follow the same storage model as Cowork sessions: each conversation is a session state file plus a working directory under `local-agent-mode-sessions/`, in the layout described in the table above. The state file records the conversation; the working directory holds the transcript, an `uploads/` directory with copies (or hard links) of files attached to the conversation, an `outputs/` directory for files Claude creates during the conversation (its scratch space), and the [session audit log](#session-audit-log). Because attachments are hard-linked where the filesystem allows it, edits made to the original file while the conversation is open can be visible to the conversation. Conversation content leaves the device only as inference requests to your configured provider, as web search queries to your configured search backend, through web access your egress configuration allows, through [sandbox network access](https://claude.com/docs/third-party/claude-desktop/chat.md#sandbox-network-access), in connector tool calls permitted by your `toolPolicy` configuration and the user's approvals, and, if you have enabled [content capture](https://claude.com/docs/third-party/claude-desktop/telemetry.md#content-capture), in telemetry to your own collector. For the questions security reviews most often ask about Chat: @@ -78,7 +98,7 @@ For the questions security reviews most often ask about Chat: * **Claude cannot search past chats.** Users can search their own conversations in the app, which scans the per-session files on the device on demand, but there is no index of conversation content, server-side or local (history exists only as the per-session files above), and a Chat conversation has no tools for listing or reading other sessions' transcripts. Each conversation is isolated to its own directory. * **The advanced file analysis sandbox writes only inside the session directory.** When [advanced file analysis](https://claude.com/docs/third-party/claude-desktop/chat.md#advanced-file-analysis) is enabled, code runs in a local sandbox. Commands in it can reach the hosts in `coworkEgressAllowedHosts`, as described under [Sandbox network access](https://claude.com/docs/third-party/claude-desktop/chat.md#sandbox-network-access). The sandbox writes only to the conversation's `outputs/` directory, and reads its `uploads/` directory, its transcript, and its saved tool results plus, for a conversation inside a project, that project's memory. For a conversation inside a project, the sandbox can also read the folders added to the project in Claude Desktop, under the conditions in [Advanced file analysis](https://claude.com/docs/third-party/claude-desktop/chat.md#advanced-file-analysis). -Deleting a conversation's session state file and working directory removes all of this; there is no other copy. +Deleting a conversation's session state file and working directory removes all of this. ## Credentials diff --git a/content/claude/third-party/claude-desktop/overview.md b/content/claude/third-party/claude-desktop/overview.md index ea4a661da9..0fb5eac99c 100644 --- a/content/claude/third-party/claude-desktop/overview.md +++ b/content/claude/third-party/claude-desktop/overview.md @@ -40,7 +40,7 @@ The desktop app detects 3P mode at launch from the configured inference provider * **Conversation content goes only to your configured endpoint.** The app sends prompts, responses, files, and tool outputs only to your configured inference endpoint and stores them only on the local machine. If you enable [SSH remote sessions](https://claude.com/docs/third-party/claude-desktop/ssh-remote-sessions.md), Claude Code runs those sessions on a remote host, which also receives that content, sends it to your endpoint, and stores it. What happens to that content at the endpoint depends on the provider, as described under [Data handling by provider](#data-handling-by-provider). * **Sandboxed tool execution.** In Cowork, shell commands run in the hardened Cowork VM; file access is scoped to your allowed folders and web fetches to your egress allowlist. For Code sessions, see [Applied as managed policy](https://claude.com/docs/third-party/claude-desktop/code.md#applied-as-managed-policy). -* **Auditable telemetry.** Crash reports and product analytics are scrubbed of conversation and user data before being sent to Anthropic, and can be fully disabled via configuration keys. Independently, you can export session activity to your own OpenTelemetry collector. The export is metadata only by default, with prompt and tool content available as an explicit opt-in. If you turn on [skill scanning](https://claude.com/docs/third-party/claude-desktop/extensions.md#skill-scanning), the export also carries records of scan results. A record's summary can quote the skill. +* **Auditable telemetry.** [Crash reports and product analytics](https://claude.com/docs/third-party/claude-desktop/telemetry.md#telemetry-categories) are scrubbed of conversation and user data before being sent to Anthropic, and can be fully disabled via configuration keys. Independently, you can export session activity to your own OpenTelemetry collector. The export is metadata only by default, with prompt and tool content available as an explicit opt-in. If you turn on [skill scanning](https://claude.com/docs/third-party/claude-desktop/extensions.md#skill-scanning), the export also carries records of scan results. A record's summary can quote the skill. * **Centrally managed.** Configuration is delivered through your existing MDM (Jamf, Intune, Workspace ONE, Group Policy), a [bootstrap server](https://claude.com/docs/third-party/claude-desktop/bootstrap.md), or the [admin console](https://claude.com/docs/third-party/claude-desktop/admin-console.md). End users can't edit a configuration that MDM delivers. They can leave it for standard Claude Desktop by signing in to claude.ai. On Claude Desktop 2.37337.0 or later, a user who signs in to any organization that uses the admin console can move the device to that organization's configuration. To prevent both, set [`disableDeploymentModeChooser`](https://claude.com/docs/third-party/claude-desktop/configuration#disabledeploymentmodechooser) to `true` in the MDM profile, as described under [Keep a device on its managed profile](https://claude.com/docs/third-party/claude-desktop/admin-console.md#keep-a-device-on-its-managed-profile). For a detailed treatment of the threat model, sandbox boundaries, and data flows, request access to the [Claude Cowork Desktop Security Architecture Overview](https://trust.anthropic.com/resources?s=2a7bbzo1lyymvdt551q7kl\&name=claude-cowork-desktop-security-architecture-overview) on Anthropic's Trust Center. For architecture, telemetry, and controls information specific to Claude Desktop on 3P, see the [Claude Desktop Security Overview (Third-party platforms)](https://trust.anthropic.com/resources?s=0c8rx4s7mm5ierz8ppetfs\&name=claude-cowork-security-overview-\(third-party-platforms\)) on the Trust Center. diff --git a/content/claude/third-party/claude-desktop/telemetry.md b/content/claude/third-party/claude-desktop/telemetry.md index 70e67d871f..179357363b 100644 --- a/content/claude/third-party/claude-desktop/telemetry.md +++ b/content/claude/third-party/claude-desktop/telemetry.md @@ -32,7 +32,7 @@ On Claude Desktop 2.7032.0 and later, the [**Keep only your organization ID and ### Non-essential telemetry -Product-usage analytics: feature adoption, session counts, UI interactions. Used to understand how Claude Desktop is used in aggregate. Contains no prompt or response content. Also gates the **Send to Anthropic** button in **Help → Troubleshooting → Generate Diagnostic Report**; with this disabled, diagnostic bundles can only be saved locally. +Product-usage analytics: feature adoption, session counts, UI interactions. Used to understand how Claude Desktop is used in aggregate. Contains no prompt or response content. | Setting | Default | Effect when `true` | | - | - | - | @@ -302,7 +302,7 @@ Each connection in the following table has a managed-configuration key that turn | Connection | What it carries | Key that turns it off | | - | - | - | | Crash, error, and performance reporting | Diagnostic metadata, never prompt or response content. See [Essential telemetry](#essential-telemetry). | [`disableEssentialTelemetry`](https://claude.com/docs/third-party/claude-desktop/configuration#disableessentialtelemetry) set to `true` | -| Product analytics and diagnostic-report uploads | Feature adoption, session counts, and UI interactions, plus Claude Code usage telemetry. No prompt or response content. See [Non-essential telemetry](#non-essential-telemetry). | [`disableNonessentialTelemetry`](https://claude.com/docs/third-party/claude-desktop/configuration#disablenonessentialtelemetry) set to `true` | +| Product analytics | Feature adoption, session counts, and UI interactions, plus Claude Code usage telemetry. No prompt or response content. See [Non-essential telemetry](#non-essential-telemetry). | [`disableNonessentialTelemetry`](https://claude.com/docs/third-party/claude-desktop/configuration#disablenonessentialtelemetry) set to `true` | | Connector favicons, artifact previews, and MCP App widgets | Icon fetches, and the sandboxed iframe pages that render previews and widgets. Some of these requests go to third-party hosts rather than to Anthropic, such as the icon fetches to `www.google.com` and `*.gstatic.com`. See [Non-essential services](#non-essential-services) and, for each host, [Required egress paths](#required-egress-paths). | [`disableNonessentialServices`](https://claude.com/docs/third-party/claude-desktop/configuration#disablenonessentialservices) set to `true` | | Auto-updates | Requests to Anthropic's update feed, and downloads of new builds. On Linux, `apt` downloads new versions from `downloads.claude.ai`. See [Auto-updates](#auto-updates). | [`disableAutoUpdates`](https://claude.com/docs/third-party/claude-desktop/configuration#disableautoupdates) set to `true`. On Linux, also keep Anthropic's apt repository off the device, as described under [Auto-updates](#auto-updates). | | Model catalog | The signed model catalog that labels the model picker, fetched from `downloads.claude.ai` at launch and then every 5 to 15 minutes, including on devices installed with the offline installer. A blocked catalog request affects nothing else. | [`modelCatalogEnabled`](https://claude.com/docs/third-party/claude-desktop/configuration#modelcatalogenabled) set to `false`, or [`modelCatalogUrl`](https://claude.com/docs/third-party/claude-desktop/configuration#modelcatalogurl) set to a mirror inside your network | diff --git a/content/en/agents-and-tools/tool-use/browser-use-sdk.md b/content/en/agents-and-tools/tool-use/browser-use-sdk.md index 1cab67cb0e..df31f363bb 100644 --- a/content/en/agents-and-tools/tool-use/browser-use-sdk.md +++ b/content/en/agents-and-tools/tool-use/browser-use-sdk.md @@ -18,7 +18,10 @@ featureMetadata: - claude-opus-4-8 supportedPlatforms: Claude API: beta + Claude Platform on AWS: beta + Amazon Bedrock: beta Claude Models on Google Cloud (Google managed): beta + Microsoft Foundry: beta --- With the browser and computer toolsets in the Python and TypeScript SDKs, you can build an agent that works in a web browser or on a desktop. It can use applications with no programmatic interface. Through the [browser use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool), Claude navigates, reads, and interacts with webpages. Through the [computer use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool), Claude receives screenshots of a desktop and uses the mouse and keyboard. @@ -82,6 +85,8 @@ With a driver from a provider, such as one under [Partner integrations](https:// Pass the driver instance itself as the `tools` entry. The runner never closes the toolset, so one instance can serve several runs. Close it when you’re done. +The example’s client calls the Claude API. For another platform listed under [API support](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-sdk#availability-feature-support), create that platform’s SDK client instead. Each platform’s page shows its client. + To write your own driver, see [Implement a driver](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-sdk#implement-a-driver). ## Partner integrations @@ -595,10 +600,6 @@ Claude’s next action depends on the pages it reads. A page, or text injected i The SDK applies steps 1, 4, and 5 through the policies and the callable you pass. Steps 2, 3, and 6 are up to your driver and your deployment. The precautions under [Security considerations](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#security-considerations) apply as well. - - Anthropic’s prompt-injection classifiers, described under [Security considerations](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#security-considerations), don’t currently run on browser toolset requests sent through Amazon Bedrock. - - ### Write a URL policy @@ -1386,9 +1387,10 @@ Browser and computer use SDK toolsets are in beta on select models. * Availability: Available -| Status | Cloud platforms | Models | -| ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Beta | Claude API, [Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/google-managed) | [Claude Fable 5.1](https://platform.claude.com/docs/en/models/fable-5-1/overview), [Claude Mythos 5.1](https://platform.claude.com/docs/en/models/mythos-5-1/overview), [Claude Fable 5](https://platform.claude.com/docs/en/models/fable-5/overview), [Claude Mythos 5](https://platform.claude.com/docs/en/models/mythos-5/overview), Claude Mythos Preview, [Claude Opus 5.5](https://platform.claude.com/docs/en/models/opus-5-5/overview), [Claude Opus 5](https://platform.claude.com/docs/en/models/opus-5/overview), [Claude Sonnet 5.5](https://platform.claude.com/docs/en/models/sonnet-5-5/overview), [Claude Sonnet 5](https://platform.claude.com/docs/en/models/sonnet-5/overview), [Claude Haiku 5.5](https://platform.claude.com/docs/en/models/haiku-5-5/overview), [Claude Opus 4.8](https://platform.claude.com/docs/en/models/opus-4-8/overview) | +| Status | Cloud platforms | Models | +| ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Beta | Claude API, [Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/google-managed) | [Claude Fable 5.1](https://platform.claude.com/docs/en/models/fable-5-1/overview), [Claude Mythos 5.1](https://platform.claude.com/docs/en/models/mythos-5-1/overview), [Claude Fable 5](https://platform.claude.com/docs/en/models/fable-5/overview), [Claude Mythos 5](https://platform.claude.com/docs/en/models/mythos-5/overview), Claude Mythos Preview, [Claude Opus 5.5](https://platform.claude.com/docs/en/models/opus-5-5/overview), [Claude Opus 5](https://platform.claude.com/docs/en/models/opus-5/overview), [Claude Sonnet 5.5](https://platform.claude.com/docs/en/models/sonnet-5-5/overview), [Claude Sonnet 5](https://platform.claude.com/docs/en/models/sonnet-5/overview), [Claude Haiku 5.5](https://platform.claude.com/docs/en/models/haiku-5-5/overview), [Claude Opus 4.8](https://platform.claude.com/docs/en/models/opus-4-8/overview) | +| Beta | [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws), [Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock), [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry) | [Claude Fable 5.1](https://platform.claude.com/docs/en/models/fable-5-1/overview), [Claude Mythos 5.1](https://platform.claude.com/docs/en/models/mythos-5-1/overview), [Claude Fable 5](https://platform.claude.com/docs/en/models/fable-5/overview), [Claude Mythos 5](https://platform.claude.com/docs/en/models/mythos-5/overview), [Claude Opus 5.5](https://platform.claude.com/docs/en/models/opus-5-5/overview), [Claude Opus 5](https://platform.claude.com/docs/en/models/opus-5/overview), [Claude Sonnet 5.5](https://platform.claude.com/docs/en/models/sonnet-5-5/overview), [Claude Sonnet 5](https://platform.claude.com/docs/en/models/sonnet-5/overview), [Claude Haiku 5.5](https://platform.claude.com/docs/en/models/haiku-5-5/overview), [Claude Opus 4.8](https://platform.claude.com/docs/en/models/opus-4-8/overview) | #### [Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview) diff --git a/content/en/agents-and-tools/tool-use/browser-use-tool.md b/content/en/agents-and-tools/tool-use/browser-use-tool.md index 847ab793b1..7fa5d22e4f 100644 --- a/content/en/agents-and-tools/tool-use/browser-use-tool.md +++ b/content/en/agents-and-tools/tool-use/browser-use-tool.md @@ -21,7 +21,10 @@ featureMetadata: - claude-opus-4-8 supportedPlatforms: Claude API: stable + Claude Platform on AWS: stable + Amazon Bedrock: stable Claude Models on Google Cloud (Google managed): stable + Microsoft Foundry: stable --- @@ -38,7 +41,7 @@ With browser use, Claude reads and acts on live webpages, so everything a page s ## Quick start -The browser use tool is available on the Claude API and [Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/google-managed): add one entry of type `browser_toolset_20260801`, with no `name`, to the `tools` array of a [Messages API](https://platform.claude.com/docs/en/api/messages/create) request. +To use the browser use tool, add one entry of type `browser_toolset_20260801`, with no `name`, to the `tools` array of a [Messages API](https://platform.claude.com/docs/en/api/messages/create) request. See [API support](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool#availability-feature-support) for the supported models and platforms. ```bash cURL @@ -1562,7 +1565,6 @@ The API validates the toolset entry and every member `tool_use` and `tool_result ## Limitations -* **Platform availability:** Browser use is available on the Claude API and [Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/google-managed). * **Whole-input streaming only:** When you stream, each member’s `input` arrives as one complete `input_json_delta` ([Client toolsets](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-reference#client-toolsets)). * **Element references are best-effort:** Highly dynamic pages (virtualized lists, canvas-rendered interfaces, pages that re-render on scroll) might not expose stable references, and Claude falls back to screenshots and coordinate clicks there. * **`read_console` and `read_network` depend on your browser automation:** They report only what it can capture, and only from the moment it attached to a tab. @@ -1615,9 +1617,10 @@ Browser use tool is available on select models and eligible for zero data retent * Availability: Available -| Status | Cloud platforms | Models | -| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Available | Claude API, [Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/google-managed) | [Claude Fable 5.1](https://platform.claude.com/docs/en/models/fable-5-1/overview), [Claude Mythos 5.1](https://platform.claude.com/docs/en/models/mythos-5-1/overview), [Claude Fable 5](https://platform.claude.com/docs/en/models/fable-5/overview), [Claude Mythos 5](https://platform.claude.com/docs/en/models/mythos-5/overview), Claude Mythos Preview, [Claude Opus 5.5](https://platform.claude.com/docs/en/models/opus-5-5/overview), [Claude Opus 5](https://platform.claude.com/docs/en/models/opus-5/overview), [Claude Sonnet 5.5](https://platform.claude.com/docs/en/models/sonnet-5-5/overview), [Claude Sonnet 5](https://platform.claude.com/docs/en/models/sonnet-5/overview), [Claude Haiku 5.5](https://platform.claude.com/docs/en/models/haiku-5-5/overview), [Claude Opus 4.8](https://platform.claude.com/docs/en/models/opus-4-8/overview) | +| Status | Cloud platforms | Models | +| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Available | Claude API, [Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/google-managed) | [Claude Fable 5.1](https://platform.claude.com/docs/en/models/fable-5-1/overview), [Claude Mythos 5.1](https://platform.claude.com/docs/en/models/mythos-5-1/overview), [Claude Fable 5](https://platform.claude.com/docs/en/models/fable-5/overview), [Claude Mythos 5](https://platform.claude.com/docs/en/models/mythos-5/overview), Claude Mythos Preview, [Claude Opus 5.5](https://platform.claude.com/docs/en/models/opus-5-5/overview), [Claude Opus 5](https://platform.claude.com/docs/en/models/opus-5/overview), [Claude Sonnet 5.5](https://platform.claude.com/docs/en/models/sonnet-5-5/overview), [Claude Sonnet 5](https://platform.claude.com/docs/en/models/sonnet-5/overview), [Claude Haiku 5.5](https://platform.claude.com/docs/en/models/haiku-5-5/overview), [Claude Opus 4.8](https://platform.claude.com/docs/en/models/opus-4-8/overview) | +| Available | [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws), [Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock), [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry) | [Claude Fable 5.1](https://platform.claude.com/docs/en/models/fable-5-1/overview), [Claude Mythos 5.1](https://platform.claude.com/docs/en/models/mythos-5-1/overview), [Claude Fable 5](https://platform.claude.com/docs/en/models/fable-5/overview), [Claude Mythos 5](https://platform.claude.com/docs/en/models/mythos-5/overview), [Claude Opus 5.5](https://platform.claude.com/docs/en/models/opus-5-5/overview), [Claude Opus 5](https://platform.claude.com/docs/en/models/opus-5/overview), [Claude Sonnet 5.5](https://platform.claude.com/docs/en/models/sonnet-5-5/overview), [Claude Sonnet 5](https://platform.claude.com/docs/en/models/sonnet-5/overview), [Claude Haiku 5.5](https://platform.claude.com/docs/en/models/haiku-5-5/overview), [Claude Opus 4.8](https://platform.claude.com/docs/en/models/opus-4-8/overview) | #### [Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview) diff --git a/content/en/agents-and-tools/tool-use/computer-use-tool.md b/content/en/agents-and-tools/tool-use/computer-use-tool.md index 38dd596fdc..80babbb171 100644 --- a/content/en/agents-and-tools/tool-use/computer-use-tool.md +++ b/content/en/agents-and-tools/tool-use/computer-use-tool.md @@ -27,14 +27,13 @@ featureMetadata: - claude-sonnet-4-5-20250929 supportedPlatforms: Claude API: stable - Claude Platform on AWS: beta - Amazon Bedrock: beta + Claude Platform on AWS: stable + Amazon Bedrock: stable Amazon Bedrock (InvokeModel): beta Claude Models on Google Cloud (Google managed): stable - Microsoft Foundry: beta + Microsoft Foundry: stable details: - - On the Claude API and Claude Models on Google Cloud (Google managed), Claude 5.5 and later models support computer use only through the `computer_toolset_20260801` toolset and return an error for the earlier `computer_20251124` and `computer_20250124` tool versions. To move an existing integration, see [Migrate from `computer_20251124`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124). To move from `computer_20250124`, see [Move computer use to the toolset](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#computer-use-toolset) in the Claude Haiku 5.5 migration guide. - - On Amazon Bedrock, Claude Opus 5.5, Claude Sonnet 5.5, and Claude Haiku 5.5 accept the earlier `computer_20251124` tool version as Claude Opus 5 and Claude Sonnet 5 do. + - Claude 5.5 and later models support computer use through the `computer_toolset_20260801` toolset. They return a 400 error for any computer use tool version they don't accept, such as `computer_20251124` on the Claude API. To move a `computer_20251124` integration to the toolset, see [Migrate from `computer_20251124`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124). To move from `computer_20250124`, see [Move computer use to the toolset](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#computer-use-toolset) in the Claude Haiku 5.5 migration guide. - Claude Opus 4.7, Claude Opus 4.6, Claude Sonnet 4.6, and Claude Opus 4.5 support computer use only through the earlier `computer_20251124` tool version, which requires a beta header; see [Earlier tool versions](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#earlier-tool-versions). --- @@ -48,11 +47,7 @@ The computer use tool is an Anthropic-defined [client toolset](https://platform. For tasks that stay inside webpages, the [browser use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool) is the closer fit: its member tools read and act on the page itself, and it doesn’t need a full desktop environment. - - Computer use is available on the Claude API and [Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/google-managed) as the `computer_toolset_20260801` toolset; see [API support](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#availability-feature-support) for the supported models. - - Existing `computer_20251124` integrations keep working on the models listed for it under [Earlier tool versions](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#earlier-tool-versions), and earlier tool versions remain available in beta for models and platforms that don’t support the toolset. See [Migrate from `computer_20251124`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124) to upgrade, or [Earlier tool versions](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#earlier-tool-versions) for the beta headers. - +See [API support](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#availability-feature-support) for the models and platforms that support the toolset. [Earlier tool versions](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#earlier-tool-versions) lists each earlier version’s beta header and the models to use it with. ## Security considerations @@ -2120,7 +2115,9 @@ If clicks miss their targets, the cause is usually one of the following: ## Migrate from `computer_20251124` -Upgrading from `computer_20251124` to the toolset is optional: the models listed for `computer_20251124` under [Earlier tool versions](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#earlier-tool-versions) keep accepting it with its beta header, so an existing integration keeps working until you change it. Claude 5.5 and later models are the exception on the Claude API and Claude Models on Google Cloud (Google managed): there they accept only the toolset. Upgrade an integration before you move it to one of them. On Amazon Bedrock, Claude Opus 5.5, Claude Sonnet 5.5, and Claude Haiku 5.5 accept `computer_20251124`. To upgrade, make the following changes together: +A `computer_20251124` integration works without changes on the models listed for that version under [Earlier tool versions](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#earlier-tool-versions). Upgrade the integration before you move it to a model that doesn’t accept `computer_20251124`, such as a Claude 5.5 model on the Claude API. + +To upgrade, make the following changes together: 1. **Remove the beta header.** Drop `anthropic-beta: computer-use-2025-11-24` from your requests. With the SDK, remove `betas` (csharp, go: `Betas`; java: `.addBeta()`) and call the Messages API through the standard client rather than the beta namespace. 2. **Change the `tools` entry.** Set `type` to `computer_toolset_20260801` and delete `name`, `display_width_px`, `display_height_px`, `display_number`, and `enable_zoom`. The toolset rejects each of these fields. @@ -2178,13 +2175,15 @@ The following pair shows a `tool_use` block before and after the change. The act ## Earlier tool versions -Two earlier versions of the computer use tool remain available in beta for existing integrations, for models that don’t support the toolset, and on platforms where the toolset isn’t currently available. On Claude Platform on AWS, Amazon Bedrock, and Microsoft Foundry, computer use is available only through these earlier versions. Each requires its [beta header](https://platform.claude.com/docs/en/api/beta-headers) on every request, and their parameters are documented in the [beta Messages API reference](https://platform.claude.com/docs/en/api/beta/messages/create). With the SDK, pass the header through `betas` (csharp, go: `Betas`; java: `.addBeta()`) and use the beta namespace; only the computer use tool needs the header, not the bash or text editor tools in the same request. +Two earlier versions of the computer use tool are available in beta. Each requires its [beta header](https://platform.claude.com/docs/en/api/beta-headers) on every request, and their parameters are documented in the [beta Messages API reference](https://platform.claude.com/docs/en/api/beta/messages/create). With the SDK, pass the header through `betas` (csharp, go: `Betas`; java: `.addBeta()`) and use the beta namespace; only the computer use tool needs the header, not the bash or text editor tools in the same request. | Tool version | Beta header | Use with | Parameters | | ------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | -| `computer_20251124` | `computer-use-2025-11-24` | Claude Fable 5.1, Claude Mythos 5.1, Claude Fable 5, Claude Mythos 5, Claude Opus 5, Claude Sonnet 5, Claude Opus 4.8, Claude Opus 4.7, Claude Opus 4.6, Claude Sonnet 4.6, and Claude Opus 4.5; on Amazon Bedrock, also Claude Opus 5.5, Claude Sonnet 5.5, and Claude Haiku 5.5 | [API reference](https://platform.claude.com/docs/en/api/beta/messages/create) | +| `computer_20251124` | `computer-use-2025-11-24` | Claude Fable 5.1, Claude Mythos 5.1, Claude Fable 5, Claude Mythos 5, Claude Opus 5, Claude Sonnet 5, Claude Opus 4.8, Claude Opus 4.7, Claude Opus 4.6, Claude Sonnet 4.6, and Claude Opus 4.5 | [API reference](https://platform.claude.com/docs/en/api/beta/messages/create) | | `computer_20250124` | `computer-use-2025-01-24` | Claude Sonnet 4.5 ([deprecated](https://platform.claude.com/docs/en/about-claude/model-deprecations)), Claude Haiku 4.5, Claude Opus 4.1 ([retired, except on Bedrock and Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/about-claude/model-deprecations)), Claude Sonnet 4 ([retired, except on Bedrock and Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/about-claude/model-deprecations)), and Claude Opus 4 ([retired, except on Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/about-claude/model-deprecations)) | [API reference](https://platform.claude.com/docs/en/api/beta/messages/create) | +On Amazon Bedrock, Claude Opus 5.5, Claude Sonnet 5.5, and Claude Haiku 5.5 also accept the `computer_20251124` tool with the `computer-use-2025-11-24` beta header. + *** ## Limitations @@ -2267,9 +2266,8 @@ Computer use tool is available or in beta on select models and eligible for zero | Status | Cloud platforms | Models | | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Available | Claude API, [Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/google-managed) | [Claude Fable 5.1](https://platform.claude.com/docs/en/models/fable-5-1/overview), [Claude Mythos 5.1](https://platform.claude.com/docs/en/models/mythos-5-1/overview), [Claude Fable 5](https://platform.claude.com/docs/en/models/fable-5/overview), [Claude Mythos 5](https://platform.claude.com/docs/en/models/mythos-5/overview), Claude Mythos Preview, [Claude Opus 5.5](https://platform.claude.com/docs/en/models/opus-5-5/overview), [Claude Opus 5](https://platform.claude.com/docs/en/models/opus-5/overview), [Claude Sonnet 5.5](https://platform.claude.com/docs/en/models/sonnet-5-5/overview), [Claude Sonnet 5](https://platform.claude.com/docs/en/models/sonnet-5/overview), [Claude Haiku 5.5](https://platform.claude.com/docs/en/models/haiku-5-5/overview), [Claude Opus 4.8](https://platform.claude.com/docs/en/models/opus-4-8/overview) | +| Available | [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws), [Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock), [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry) | [Claude Fable 5.1](https://platform.claude.com/docs/en/models/fable-5-1/overview), [Claude Mythos 5.1](https://platform.claude.com/docs/en/models/mythos-5-1/overview), [Claude Fable 5](https://platform.claude.com/docs/en/models/fable-5/overview), [Claude Mythos 5](https://platform.claude.com/docs/en/models/mythos-5/overview), [Claude Opus 5.5](https://platform.claude.com/docs/en/models/opus-5-5/overview), [Claude Opus 5](https://platform.claude.com/docs/en/models/opus-5/overview), [Claude Sonnet 5.5](https://platform.claude.com/docs/en/models/sonnet-5-5/overview), [Claude Sonnet 5](https://platform.claude.com/docs/en/models/sonnet-5/overview), [Claude Haiku 5.5](https://platform.claude.com/docs/en/models/haiku-5-5/overview), [Claude Opus 4.8](https://platform.claude.com/docs/en/models/opus-4-8/overview) | | Beta | Claude API, [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws), [Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock), [Amazon Bedrock (InvokeModel)](https://platform.claude.com/docs/en/build-with-claude/claude-on-amazon-bedrock-legacy), [Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/google-managed), [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry) | [Claude Haiku 4.5](https://platform.claude.com/docs/en/models/haiku-4-5/overview), [Claude Opus 4.7](https://platform.claude.com/docs/en/models/opus-4-7/overview), [Claude Opus 4.6](https://platform.claude.com/docs/en/models/opus-4-6/overview), [Claude Sonnet 4.6](https://platform.claude.com/docs/en/models/sonnet-4-6/overview), [Claude Opus 4.5](https://platform.claude.com/docs/en/models/opus-4-5/overview), [Claude Sonnet 4.5](https://platform.claude.com/docs/en/models/sonnet-4-5/overview) | -| Beta | [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws), [Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock), [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry) | [Claude Fable 5.1](https://platform.claude.com/docs/en/models/fable-5-1/overview), [Claude Mythos 5.1](https://platform.claude.com/docs/en/models/mythos-5-1/overview), [Claude Fable 5](https://platform.claude.com/docs/en/models/fable-5/overview), [Claude Mythos 5](https://platform.claude.com/docs/en/models/mythos-5/overview), [Claude Opus 5](https://platform.claude.com/docs/en/models/opus-5/overview), [Claude Sonnet 5](https://platform.claude.com/docs/en/models/sonnet-5/overview), [Claude Opus 4.8](https://platform.claude.com/docs/en/models/opus-4-8/overview) | -| Beta | [Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock) | [Claude Opus 5.5](https://platform.claude.com/docs/en/models/opus-5-5/overview), [Claude Sonnet 5.5](https://platform.claude.com/docs/en/models/sonnet-5-5/overview), [Claude Haiku 5.5](https://platform.claude.com/docs/en/models/haiku-5-5/overview) | #### [Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview) @@ -2281,12 +2279,10 @@ Computer use tool is available or in beta on select models and eligible for zero Beta headers allow you to access experimental features and new model capabilities before they become part of the standard API. -| Header | Cloud platforms | Models | -| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `computer-use-2025-11-24` | [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws), [Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock), [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry) | [Claude Fable 5.1](https://platform.claude.com/docs/en/models/fable-5-1/overview), [Claude Mythos 5.1](https://platform.claude.com/docs/en/models/mythos-5-1/overview), [Claude Fable 5](https://platform.claude.com/docs/en/models/fable-5/overview), [Claude Mythos 5](https://platform.claude.com/docs/en/models/mythos-5/overview), [Claude Opus 5](https://platform.claude.com/docs/en/models/opus-5/overview), [Claude Sonnet 5](https://platform.claude.com/docs/en/models/sonnet-5/overview), [Claude Opus 4.8](https://platform.claude.com/docs/en/models/opus-4-8/overview) | -| `computer-use-2025-11-24` | [Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock) | [Claude Opus 5.5](https://platform.claude.com/docs/en/models/opus-5-5/overview), [Claude Sonnet 5.5](https://platform.claude.com/docs/en/models/sonnet-5-5/overview), [Claude Haiku 5.5](https://platform.claude.com/docs/en/models/haiku-5-5/overview) | -| `computer-use-2025-11-24` | All supported platforms | [Claude Opus 4.7](https://platform.claude.com/docs/en/models/opus-4-7/overview), [Claude Opus 4.6](https://platform.claude.com/docs/en/models/opus-4-6/overview), [Claude Sonnet 4.6](https://platform.claude.com/docs/en/models/sonnet-4-6/overview), [Claude Opus 4.5](https://platform.claude.com/docs/en/models/opus-4-5/overview) | -| `computer-use-2025-01-24` | All supported platforms | [Claude Haiku 4.5](https://platform.claude.com/docs/en/models/haiku-4-5/overview), [Claude Sonnet 4.5](https://platform.claude.com/docs/en/models/sonnet-4-5/overview) | +| Header | Models | +| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `computer-use-2025-11-24` | [Claude Opus 4.7](https://platform.claude.com/docs/en/models/opus-4-7/overview), [Claude Opus 4.6](https://platform.claude.com/docs/en/models/opus-4-6/overview), [Claude Sonnet 4.6](https://platform.claude.com/docs/en/models/sonnet-4-6/overview), [Claude Opus 4.5](https://platform.claude.com/docs/en/models/opus-4-5/overview) | +| `computer-use-2025-01-24` | [Claude Haiku 4.5](https://platform.claude.com/docs/en/models/haiku-4-5/overview), [Claude Sonnet 4.5](https://platform.claude.com/docs/en/models/sonnet-4-5/overview) | ### Data handling diff --git a/content/en/api/errors.md b/content/en/api/errors.md index 062ec169e4..dcd258e7bd 100644 --- a/content/en/api/errors.md +++ b/content/en/api/errors.md @@ -530,13 +530,15 @@ tool_choice: type "tool" and "any" are not supported for this model. ### Computer use tool version not supported -On the Claude API and Claude Models on Google Cloud (Google managed), Claude Opus 5.5, Claude Sonnet 5.5, and Claude Haiku 5.5 support [computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) only as the `computer_toolset_20260801` toolset. On those platforms, sending any of these models a `tools` entry of the earlier `computer_20251124` or `computer_20250124` type, with that tool’s beta header, returns a 400 `invalid_request_error`. The message names the rejected type, then lists the tool types the model does accept after `Did you mean one of`. For Claude Opus 5.5, it begins: +Claude Opus 5.5, Claude Sonnet 5.5, and Claude Haiku 5.5 return a 400 error for any [computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) tool version they don’t accept. On the Claude API, that includes `computer_20251124` with its beta header. They don’t accept `computer_20250124` on any platform. The Claude API’s `invalid_request_error` message names the rejected type and, after `Did you mean one of`, lists the tool types the model accepts. For Claude Opus 5.5, the message begins: ```text wrap 'claude-opus-5-5' does not support tool types: computer_20251124. ``` -The API returns the same message for any Anthropic-defined tool type that the requested model doesn’t support. Declare `{"type": "computer_toolset_20260801"}` without the beta header and update your agent loop as described in [Migrate from `computer_20251124`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124). To move from `computer_20250124`, see [Move computer use to the toolset](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#computer-use-toolset) in the Claude Haiku 5.5 migration guide. Earlier models that support the toolset keep accepting `computer_20251124`, as do Claude Opus 5.5, Claude Sonnet 5.5, and Claude Haiku 5.5 on Amazon Bedrock. +The Claude API returns the same message for any Anthropic-defined tool type that the requested model doesn’t support. Claude Opus 5.5, Claude Sonnet 5.5, and Claude Haiku 5.5 support computer use through the `computer_toolset_20260801` toolset. Declare `{"type": "computer_toolset_20260801"}` without the beta header and update your agent loop as described in [Migrate from `computer_20251124`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124). To move from `computer_20250124`, see [Move computer use to the toolset](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#computer-use-toolset) in the Claude Haiku 5.5 migration guide. + +On Amazon Bedrock, Claude Opus 5.5, Claude Sonnet 5.5, and Claude Haiku 5.5 also accept the `computer_20251124` tool with the `computer-use-2025-11-24` beta header. [Earlier tool versions](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#earlier-tool-versions) lists the models to use with each earlier version. ### Thinking block bound to a different conversation diff --git a/content/en/api/ip-addresses.md b/content/en/api/ip-addresses.md index 45b37bb581..2c74338ee0 100644 --- a/content/en/api/ip-addresses.md +++ b/content/en/api/ip-addresses.md @@ -16,6 +16,8 @@ These are the IP addresses where Anthropic services receive incoming connections `160.79.104.0/23` +`153.61.224.0/22` + ### IPv6 `2607:6bc0::/48` @@ -28,6 +30,8 @@ These are the stable IP addresses that Anthropic uses for outbound requests (for `160.79.104.0/21` +`153.61.208.0/20` + ### Phased out IP addresses The following IP addresses are no longer in use by Anthropic. If you have previously allowlisted these addresses, remove them from your firewall rules. diff --git a/content/en/build-with-claude/cache-diagnostics.md b/content/en/build-with-claude/cache-diagnostics.md index c5126c00c5..756fb27cf5 100644 --- a/content/en/build-with-claude/cache-diagnostics.md +++ b/content/en/build-with-claude/cache-diagnostics.md @@ -324,10 +324,7 @@ Include the `diagnostics` object on every turn. The object is the opt-in: the AP IO.println("Comparison still pending."); } else { var reason = r2.diagnostics().get().cacheMissReason().get(); - // CacheMissReason doesn't expose a typed .type() accessor; read it from the raw JSON. - @SuppressWarnings("unchecked") - var json = (Map) reason._json().orElseThrow().asObject().orElseThrow(); - IO.println("cache_miss_reason: " + json.get("type").asStringOrThrow()); + IO.println("cache_miss_reason: " + reason.type().asString()); } ``` @@ -632,10 +629,7 @@ In streaming responses, `diagnostics` appears on the `message_start` event. IO.println("Comparison still pending."); } else { var reason = diagnostics.get().cacheMissReason().get(); - // CacheMissReason doesn't expose a typed .type() accessor; read it from the raw JSON. - @SuppressWarnings("unchecked") - var json = (Map) reason._json().orElseThrow().asObject().orElseThrow(); - IO.println("cache_miss_reason: " + json.get("type").asStringOrThrow()); + IO.println("cache_miss_reason: " + reason.type().asString()); } ``` @@ -903,10 +897,7 @@ In a multi-turn conversation, carry the latest response `id` forward as `previou if (r.diagnostics().isPresent() && r.diagnostics().get().cacheMissReason().isPresent()) { var reason = r.diagnostics().get().cacheMissReason().get(); - // CacheMissReason doesn't expose a typed .type() accessor; read it from the raw JSON. - @SuppressWarnings("unchecked") - var json = (Map) reason._json().orElseThrow().asObject().orElseThrow(); - IO.println("Turn " + (turn + 1) + " cache_miss_reason: " + json.get("type").asStringOrThrow()); + IO.println("Turn " + (turn + 1) + " cache_miss_reason: " + reason.type().asString()); } messages.add(r.toParam()); diff --git a/content/en/build-with-claude/claude-in-amazon-bedrock.md b/content/en/build-with-claude/claude-in-amazon-bedrock.md index 7b24ebc93a..9a860b1437 100644 --- a/content/en/build-with-claude/claude-in-amazon-bedrock.md +++ b/content/en/build-with-claude/claude-in-amazon-bedrock.md @@ -365,7 +365,7 @@ For the full feature list with Amazon Bedrock availability, see [Features overvi * [Messages API](https://platform.claude.com/docs/en/api/messages/create) (`/anthropic/v1/messages`) * [Prompt caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching) * [Thinking](https://platform.claude.com/docs/en/build-with-claude/thinking) -* [Tool use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview), including the [Bash tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/bash-tool), [Computer use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool), [Memory tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/memory-tool), and [Text editor tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/text-editor-tool) +* [Tool use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview), including the [Bash tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/bash-tool), [Browser use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool), [Computer use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool), [Memory tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/memory-tool), and [Text editor tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/text-editor-tool) * [Citations](https://platform.claude.com/docs/en/build-with-claude/citations) * [Structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs) @@ -377,7 +377,6 @@ For the full feature list with Amazon Bedrock availability, see [Features overvi * API endpoints (Message Batches, Models, Admin, Compliance, Usage and Cost) * Claude Managed Agents * Server-side fallback (the [`fallbacks` parameter](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#server-side-fallback); use the [client-side fallback pattern](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#client-side-fallback) instead) -* [Computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) and [browser use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool) toolsets (`computer_toolset_20260801` and `browser_toolset_20260801` are not currently available on Amazon Bedrock; the beta computer use tool versions remain available) ## Regions diff --git a/content/en/build-with-claude/claude-in-microsoft-foundry.md b/content/en/build-with-claude/claude-in-microsoft-foundry.md index f181a5fcfe..bd06e47e45 100644 --- a/content/en/build-with-claude/claude-in-microsoft-foundry.md +++ b/content/en/build-with-claude/claude-in-microsoft-foundry.md @@ -653,7 +653,6 @@ Claude Fable 5.1, Claude Fable 5, Claude Opus 5.5, Claude Opus 5, Claude Opus 4. * Models API * Message Batches API * Server-side fallback (the [`fallbacks` parameter](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#server-side-fallback); use the [client-side fallback pattern](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#client-side-fallback) instead) -* [Computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) and [browser use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool) toolsets (`computer_toolset_20260801` and `browser_toolset_20260801` are not currently available on Microsoft Foundry; the beta computer use tool versions remain available for the models listed under [Earlier tool versions](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#earlier-tool-versions)) ### Additional features not supported when hosted on Azure diff --git a/content/en/build-with-claude/claude-on-amazon-bedrock-legacy.md b/content/en/build-with-claude/claude-on-amazon-bedrock-legacy.md index f9d1a79929..54de69e143 100644 --- a/content/en/build-with-claude/claude-on-amazon-bedrock-legacy.md +++ b/content/en/build-with-claude/claude-on-amazon-bedrock-legacy.md @@ -745,7 +745,21 @@ For the full feature list with Amazon Bedrock availability, see [Features overvi * Claude Managed Agents * Server-side fallback (the [`fallbacks` parameter](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#server-side-fallback); use the [client-side fallback pattern](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#client-side-fallback) instead) * Automatic prompt caching (the [top-level `cache_control` field](https://platform.claude.com/docs/en/build-with-claude/prompt-caching#automatic-caching); use [explicit cache breakpoints](https://platform.claude.com/docs/en/build-with-claude/prompt-caching#explicit-cache-breakpoints) instead) -* [Computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) and [browser use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool) toolsets (`computer_toolset_20260801` and `browser_toolset_20260801` are not currently available on Amazon Bedrock; the beta computer use tool versions remain available) + +### Computer use and browser use toolsets on Bedrock + +The [computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) and [browser use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool) toolsets are available through the InvokeModel API for these models: + +* Claude Fable 5.1 +* Claude Fable 5 +* Claude Opus 5.5 +* Claude Opus 5 +* Claude Opus 4.8 +* Claude Sonnet 5.5 +* Claude Sonnet 5 +* Claude Haiku 5.5 + +To use one, add an entry of type `computer_toolset_20260801` or `browser_toolset_20260801` to the `tools` array. No beta header is required for either toolset. ### PDF support on Bedrock diff --git a/content/en/build-with-claude/claude-platform-on-aws.md b/content/en/build-with-claude/claude-platform-on-aws.md index a4ee83fc8a..0a1c73295a 100644 --- a/content/en/build-with-claude/claude-platform-on-aws.md +++ b/content/en/build-with-claude/claude-platform-on-aws.md @@ -550,7 +550,7 @@ Claude Platform on AWS uses Claude API endpoints directly, which means you get f * **Beta features:** Pass the standard `anthropic-beta` header to access beta features, just as you would with the Claude API. * **Agent Skills:** Use pre-built and custom [Agent Skills](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview) with the same `container.skills` parameter as the Claude API. All pre-built Skills (PowerPoint, Excel, Word, PDF) work out of the box. * **Code execution:** Run code in Anthropic’s managed sandbox using the [code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool). -* **Tool use:** All [tool use capabilities](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview) are available except the computer use and browser use toolsets; see [Features not supported](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws#features-not-supported). +* **Tool use:** All [tool use capabilities](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview) are available. * **Thinking:** [Adaptive thinking](https://platform.claude.com/docs/en/build-with-claude/thinking), the [effort parameter](https://platform.claude.com/docs/en/build-with-claude/effort), and, on the models that support it, [extended thinking](https://platform.claude.com/docs/en/build-with-claude/extended-thinking) work with the same parameters as the Claude API. * **Streaming:** Full SSE streaming support for real-time responses. * **Batch processing:** Submit batch requests for high-throughput workloads. @@ -576,7 +576,6 @@ Sessions and self-hosted workers on Claude Platform on AWS differ from first-par The following capabilities are not currently available on Claude Platform on AWS: * **HIPAA readiness:** Anthropic’s HIPAA-ready program is not available. See [API and data retention](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention). -* **Computer use and browser use toolsets:** `computer_toolset_20260801` and `browser_toolset_20260801` are not currently available on Claude Platform on AWS. The beta computer use tool versions remain available for the models listed under [Earlier tool versions](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#earlier-tool-versions). - **Admin API:** Workspace endpoints (create, get, list, update, and archive on `/v1/organizations/workspaces`), external key endpoints (register, get, list, update, and delete on `/v1/organizations/external_keys`, for [CMEK](https://platform.claude.com/docs/en/manage-claude/cmek); keys are validated when attached to a workspace rather than through a validate endpoint), the [telemetry destination endpoints](https://platform.claude.com/docs/en/api/claude-platform-on-aws-iam-actions#telemetry-destinations), and the [Usage and Cost Analytics API](https://platform.claude.com/docs/en/manage-claude/usage-cost-analytics-api) endpoints are available. Other Admin API endpoints (organization members, workspace members, invites, API keys, the legacy [Usage and Cost API](https://platform.claude.com/docs/en/manage-claude/usage-cost-api), and rate limit reports) are not available. AWS IAM manages organization membership. - **Workspace member management:** Adding or removing users from individual workspaces is not available. AWS IAM policies on workspace ARNs control access. diff --git a/content/en/build-with-claude/prompt-engineering/prompting-claude-opus-4-8.md b/content/en/build-with-claude/prompt-engineering/prompting-claude-opus-4-8.md index 8d7fb4591b..6e985435a3 100644 --- a/content/en/build-with-claude/prompt-engineering/prompting-claude-opus-4-8.md +++ b/content/en/build-with-claude/prompt-engineering/prompting-claude-opus-4-8.md @@ -157,6 +157,6 @@ Iterate on prompts against a subset of your evals or test cases to validate reca ## Computer use -Claude Opus 4.8 supports the earlier `computer_20251124` tool version and, on the Claude API and Claude Models on Google Cloud (Google managed), the `computer_toolset_20260801` toolset. On those two platforms, Claude Opus 4.8 also supports the [browser use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool) (`browser_toolset_20260801`) for tasks inside webpages. [Computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) capability works across resolutions, up to a maximum resolution of 2576px / 3.75MP. Internal computer use testing shows that sending images at 1080p provides a good balance of performance and cost. +Claude Opus 4.8 supports computer use through the `computer_toolset_20260801` toolset and the earlier `computer_20251124` tool version. It also supports the [browser use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool) (`browser_toolset_20260801`) for tasks inside webpages. [Computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) capability works across resolutions, up to a maximum resolution of 2576px / 3.75MP. Internal computer use testing shows that sending images at 1080p provides a good balance of performance and cost. For particularly cost-sensitive workloads, 720p or 1366×768 are lower-cost options with strong performance. Conduct your own testing to find the ideal settings for your use case; experimenting with effort settings can also help tune the model’s behavior. diff --git a/content/en/build-with-claude/prompt-engineering/prompting-claude-sonnet-5.md b/content/en/build-with-claude/prompt-engineering/prompting-claude-sonnet-5.md index 3c0fc40d26..4cfb44cedb 100644 --- a/content/en/build-with-claude/prompt-engineering/prompting-claude-sonnet-5.md +++ b/content/en/build-with-claude/prompt-engineering/prompting-claude-sonnet-5.md @@ -149,6 +149,6 @@ Iterate on prompts against a subset of your evals or test cases to validate reca ## Computer use -Claude Sonnet 5 supports the earlier `computer_20251124` tool version and, on the Claude API and Claude Models on Google Cloud (Google managed), the `computer_toolset_20260801` toolset. On those two platforms, Claude Sonnet 5 also supports the [browser use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool) (`browser_toolset_20260801`) for tasks inside webpages. [Computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) capability works across resolutions, up to a maximum resolution of 2576px / 3.75MP. Internal computer use testing shows that sending images at 1080p provides a good balance of performance and cost. +Claude Sonnet 5 supports computer use through the `computer_toolset_20260801` toolset and the earlier `computer_20251124` tool version. It also supports the [browser use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool) (`browser_toolset_20260801`) for tasks inside webpages. [Computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) capability works across resolutions, up to a maximum resolution of 2576px / 3.75MP. Internal computer use testing shows that sending images at 1080p provides a good balance of performance and cost. For particularly cost-sensitive workloads, 720p or 1366×768 are lower-cost options with strong performance. Conduct your own testing to find the ideal settings for your use case; experimenting with effort settings can also help tune the model’s behavior. diff --git a/content/en/cli-sdks-libraries/cli/using.md b/content/en/cli-sdks-libraries/cli/using.md index 3c82988a0b..00d9eacbd0 100644 --- a/content/en/cli-sdks-libraries/cli/using.md +++ b/content/en/cli-sdks-libraries/cli/using.md @@ -148,15 +148,16 @@ Flags that take a file path, such as `--file` on the upload command, accept a ba ant files upload --file ./report.pdf ``` -To inline a file’s contents into a string-valued field, prefix the path with `@`: +To inline a file’s contents into a string-valued field of a stdin document, prefix the path with `@` and wrap it in quotes: ```bash ant beta:agents create \ - --name "Researcher" --model '{id: claude-opus-5-5}' \ - --system @./prompts/researcher.txt + --name "Researcher" --model '{id: claude-opus-5-5}' <<'YAML' +system: "@./prompts/researcher.txt" +YAML ``` -Inside structured flag values, wrap the path in quotes. To send a PDF to the Messages API: +Structured flag values work the same way. To send a PDF to the Messages API: ```bash ant messages create \ diff --git a/content/en/docs/claude-code/admin-setup.md b/content/en/docs/claude-code/admin-setup.md index a58fe5a33e..34f8392f7c 100644 --- a/content/en/docs/claude-code/admin-setup.md +++ b/content/en/docs/claude-code/admin-setup.md @@ -79,6 +79,8 @@ After WSL sessions are enabled, extend your managed settings to them: * Deploy `wslInheritsWindowsSettings: true` through the HKLM registry or the `C:\Program Files\ClaudeCode` file so WSL sessions inherit the same policy as host sessions. * Verify by running `/status` inside a WSL session and reading the `Setting sources` line. To interpret what it lists, see [Read the source in /status](https://code.claude.com/docs/en/managed-settings.md#read-the-source-in-/status). +If a WSL session starts on a device with Claude Desktop's [`allowedWorkspaceFolders`](https://claude.com/docs/third-party/claude-desktop/configuration#allowedworkspacefolders) list, a `~` entry means the home directory inside the distribution. + Processes inside the WSL 2 utility VM aren't visible to Windows-side endpoint detection sensors. To observe in-distro process and file activity, check your endpoint detection vendor's WSL guidance for a Linux sensor you can run inside the distribution and the exclusions it needs. Claude Code's [OpenTelemetry tool-execution telemetry](https://code.claude.com/docs/en/monitoring-usage.md) is emitted identically for WSL and native sessions. ## Decide what to enforce diff --git a/content/en/docs/claude-code/agent-sdk/cost-tracking.md b/content/en/docs/claude-code/agent-sdk/cost-tracking.md index acee9af74f..cfebd39ff4 100644 --- a/content/en/docs/claude-code/agent-sdk/cost-tracking.md +++ b/content/en/docs/claude-code/agent-sdk/cost-tracking.md @@ -20,7 +20,7 @@ For complete API documentation, see the [TypeScript SDK reference](https://code. > > One billing rule the SDK does model is [data residency pricing](https://platform.claude.com/docs/en/about-claude/pricing#data-residency-pricing). When a response's `usage` reports `inference_geo: "us"`, the SDK multiplies the list price of that response's tokens by 1.1. Per-request fees such as web search aren't multiplied. Requires TypeScript Agent SDK v0.3.239 or later, or Python Agent SDK v0.2.144 or later. > -> Use these fields for development insight and approximate budgeting. For authoritative billing, use the [Usage and Cost API](https://platform.claude.com/docs/en/build-with-claude/usage-cost-api) or the Usage page in the [Claude Console](https://platform.claude.com/usage). Do not bill end users or trigger financial decisions from these fields. +> Use these fields for development insight and approximate budgeting. For authoritative billing, see [Manage costs for your organization](https://code.claude.com/docs/en/costs.md#manage-costs-for-your-organization). Don't bill end users or trigger financial decisions from these fields. ## Understand token usage diff --git a/content/en/docs/claude-code/agent-sdk/typescript.md b/content/en/docs/claude-code/agent-sdk/typescript.md index a937c43104..f3cd816c97 100644 --- a/content/en/docs/claude-code/agent-sdk/typescript.md +++ b/content/en/docs/claude-code/agent-sdk/typescript.md @@ -52,7 +52,10 @@ Each compiled executable embeds a single platform's binary. Match the platform p If your application bundles the Agent SDK together with its own dependencies, import from `@anthropic-ai/claude-agent-sdk/core` instead of the package root. The `/core` entry requires TypeScript Agent SDK v0.3.282 or later, and its types require TypeScript 5.0 or later. -The `/core` entry exports the same `query()`, `startup()`, `tool()`, `createSdkMcpServer()`, and `resolveSettings()` as the root entry, along with the functions that rename, tag, and delete sessions, `AbortError`, the runtime constants, and every type. It adds no names of its own. To keep the code your application loads small, `/core` leaves out some root exports, including `prewarm()`, the `InMemorySessionStore` class, and the helpers that list, read, fork, import, and summarize sessions. If you need one of them, use the root entry instead. +To keep the code your application loads small, the `/core` entry leaves out some root exports: + +* **Exported**: the same `query()`, `startup()`, [`prewarm()`](#prewarm), `tool()`, `createSdkMcpServer()`, and `resolveSettings()` as the root entry, along with the functions that rename, tag, and delete sessions, `AbortError`, the runtime constants, and every type. Importing the alpha `prewarm()` from `/core` requires Agent SDK v0.3.314 or later. +* **Left out**: root exports including the `InMemorySessionStore` class and the helpers that list, read, fork, import, and summarize sessions. If you need one of them, use the root entry instead. The root entry inlines its own copies of `zod` and `@modelcontextprotocol/sdk`. The `/core` entry imports them from your `node_modules` at the ranges the Agent SDK's `peerDependencies` declare, so a bundle that already includes them doesn't carry a second copy. Import from either the root or `/core` in a given process, not both: they are separate bundles, and loading both gives you two copies of the Agent SDK's classes and state. @@ -2002,6 +2005,9 @@ Set `CLAUDE_CODE_STARTUP_FAILURE_RESULTS` to `1` in [`env`](#options) to receive * A resume that Claude Code stops because it [can't return the session to its worktree](https://code.claude.com/docs/en/worktrees.md#the-session-resumes-outside-its-worktree), with `worktree_unverified` or `worktree_resume_refused`. That section says which error carries which value. * A refused [`continue`](#options) of a conversation that a background session holds, with `session_held_by_background`. For a refused [`resume`](#options) of such a conversation, Claude Code writes the result only when the variable is set. +* A start that Claude Code refuses because [`failIfUnavailable`](#sandboxsettings) is on and the sandbox can't start, with `sandbox_required_unavailable`. + +The `SDKStartupFailureReason` type lists the values `startup_failure_reason` can hold: ```typescript theme={null} type SDKStartupFailureReason = @@ -2023,7 +2029,8 @@ type SDKStartupFailureReason = | "cli_version_too_old" | "bypass_root" | "org_config_required_unavailable" - | "org_config_refused"; + | "org_config_refused" + | "sandbox_required_unavailable"; ``` Each value names one refusal: @@ -2049,6 +2056,7 @@ Each value names one refusal: | `bypass_root` | Bypass permissions mode was requested while running as root | | `org_config_required_unavailable` | The session needs the organization's policies and managed settings before it can start, and they couldn't be loaded, for example because of a network failure or an Anthropic server error. Requires Agent SDK v0.3.293 or later | | `org_config_refused` | Anthropic refused to provide the organization's policies and managed settings for this sign-in, for example because the sign-in expired or was revoked, or the organization doesn't allow Claude Code for this account. Requires Agent SDK v0.3.293 or later | +| `sandbox_required_unavailable` | [`failIfUnavailable`](#sandboxsettings) is on and the sandbox can't start. The text in `errors` ends with `Set sandbox.failIfUnavailable=false to allow unsandboxed execution.` Requires Agent SDK v0.3.314 or later | ### `SDKSystemMessage` diff --git a/content/en/docs/claude-code/amazon-bedrock.md b/content/en/docs/claude-code/amazon-bedrock.md index eaeed7c802..e88790b9f9 100644 --- a/content/en/docs/claude-code/amazon-bedrock.md +++ b/content/en/docs/claude-code/amazon-bedrock.md @@ -308,15 +308,29 @@ When a user selects one of these versions in `/model`, Claude Code calls Amazon When Claude Code starts with Amazon Bedrock configured, it verifies that the models it intends to use are accessible in your account. -If you have pinned a model version that is older than the current Claude Code default, and your account can invoke the newer version, Claude Code prompts you to update the pin. Accepting writes the new model ID to your [user settings file](https://code.claude.com/docs/en/settings.md) and restarts Claude Code. Declining is remembered until the next default version change. Pins that point to an [application inference profile ARN](#map-each-model-version-to-an-inference-profile) are skipped, since those are managed by your administrator. +You may have pinned a model version that is older than the current Claude Code default. If your account can invoke the newer version, Claude Code prompts you to update the pin. Accepting writes the new model ID to your [user settings file](https://code.claude.com/docs/en/settings.md) and restarts Claude Code. Declining is remembered until the next default version change. + +Claude Code doesn't check or prompt for these pins: + +* A pin in the `env` block of [managed settings](https://code.claude.com/docs/en/managed-settings.md) +* A pin that points to an [application inference profile ARN](#map-each-model-version-to-an-inference-profile), because your administrator manages it + +If the update prompt still appears for a pin in managed settings, update Claude Code to v2.1.314 or later. Before v2.1.314, the managed pin stayed in effect after you accepted, so the prompt came back at the next start. If you have not pinned a model and the current default is unavailable in your account, Claude Code falls back for the current session and shows a notice. It tries earlier versions of the default model first and, when the default is an Opus model and no Opus version is available, falls back to the default Sonnet model. The fallback is not persisted. Enable the newer model in your Amazon Bedrock account or [pin a version](#4-pin-model-versions) to make the choice permanent. +### Start a session on a specific model + When you start the session on a specific Sonnet or Opus version, for example with `--model`, `ANTHROPIC_MODEL`, or the [`model` setting](https://code.claude.com/docs/en/settings-reference#model), that version acts as the session's pinned default for the matching `sonnet` or `opus` alias. Claude Code skips the availability check for the built-in default your model replaces and starts on the model you configured, with no fallback notice. -Model aliases such as `opus` don't act as pins, and neither does a model ID Claude Code doesn't recognize, such as an application inference profile ARN. +These don't act as pins when you start a session on them: + +* A model alias such as `opus` +* A model ID Claude Code doesn't recognize, such as an application inference profile ARN + +### Remembered model refusals -When these checks find a model your account can't invoke, Claude Code remembers the refusal on this machine for up to a day, and launches during that time skip the remembered model without asking Amazon Bedrock again. Claude Code checks a remembered refusal of a current default model again at launch once ten minutes have passed since the last check, so a default your administrator re-enables comes back. To turn the memory off, set [`CLAUDE_CODE_SKIP_MODEL_ACCESS_MEMORY=1`](https://code.claude.com/docs/en/env-vars). +When the startup model checks find a model your account can't invoke, Claude Code can remember the refusal on this machine for up to a day. Once ten minutes have passed since the last check, Claude Code checks a remembered refusal of a current default model again at launch. A default your administrator re-enables then comes back. To turn the memory off, set [`CLAUDE_CODE_SKIP_MODEL_ACCESS_MEMORY=1`](https://code.claude.com/docs/en/env-vars). ### When your organization enforces a model allowlist diff --git a/content/en/docs/claude-code/analytics.md b/content/en/docs/claude-code/analytics.md index 730978bec4..810277658f 100644 --- a/content/en/docs/claude-code/analytics.md +++ b/content/en/docs/claude-code/analytics.md @@ -77,7 +77,7 @@ The dashboard displays these summary metrics at the top: * **Lines of code with CC**: total lines of code across all merged PRs that were written with Claude Code assistance. Only "effective lines" are counted: lines with more than 3 characters after normalization, excluding empty lines and lines with only brackets or trivial punctuation. * **PRs with Claude Code (%)**: percentage of all merged PRs that contain Claude Code-assisted code * **Suggestion accept rate**: percentage of times users accept Claude Code's code editing suggestions, including Edit, Write, and NotebookEdit tool usage -* **Lines of code accepted**: total lines of code written by Claude Code that users have accepted in their sessions. This excludes rejected suggestions and does not track subsequent deletions. +* **Lines of code accepted**: total lines of code that Claude Code's Edit and Write tools added or removed in accepted edits. This excludes rejected suggestions, and lines deleted later don't reduce the total. ### Explore the charts @@ -192,7 +192,7 @@ To query contribution data through GitHub instead, search for PRs labeled with ` ## Access analytics for API customers -API customers using the Claude Console can access analytics at [platform.claude.com/claude-code](https://platform.claude.com/claude-code). You need the UsageView permission to access the dashboard, which is granted to Developer, Billing, Admin, Owner, and Primary Owner roles. To pull the same daily per-user metrics programmatically, use the [Claude Code Analytics API](https://platform.claude.com/docs/en/build-with-claude/claude-code-analytics-api) with an Admin API key. +API customers using the Claude Console can access analytics at [platform.claude.com/claude-code](https://platform.claude.com/claude-code). You need the UsageView permission to access the dashboard. The Developer, Billing, Admin, Owner, and Primary Owner roles have this permission. To pull daily per-user metrics programmatically, use the [Claude Code Analytics API](https://platform.claude.com/docs/en/build-with-claude/claude-code-analytics-api) with an Admin API key. > [!NOTE] > @@ -200,22 +200,22 @@ API customers using the Claude Console can access analytics at [platform.claude. The Console dashboard displays: -* **Lines of code accepted**: total lines of code written by Claude Code that users have accepted in their sessions. This excludes rejected suggestions and does not track subsequent deletions. +* **Lines of code accepted**: total lines of code that Claude Code's Edit and Write tools added or removed in accepted edits. This excludes rejected suggestions, and lines deleted later don't reduce the total. * **Suggestion accept rate**: percentage of times users accept code editing tool usage, including Edit, Write, and NotebookEdit tools. -* **Activity**: daily active users and sessions shown on a chart. -* **Spend**: daily API costs in dollars alongside user count. +* **Active users** and **Sessions**: daily counts of active users and Claude Code sessions. +* **Spend**: daily API costs in dollars. ### View team insights -The team insights table shows per-user metrics: +The team insights table shows these per-user columns for the date range you select at the top of the dashboard, by default the last 30 days: -* **Members**: all users who have authenticated to Claude Code. API key users display by key identifier, OAuth users display by email address. -* **Spend this month**: per-user total API costs for the current month. -* **Lines this month**: per-user total of accepted code lines for the current month. +* **Members**: users and API keys with reported Claude Code usage in that range. API key users display by key name, and OAuth users by email address. +* **Spend**: per-user total API costs. +* **Lines accepted**: per-user total of lines that the Edit and Write tools added or removed in accepted edits. > [!NOTE] > -> Spend figures in the Console dashboard are estimates for analytics purposes. For actual costs, refer to your billing page. +> Spend figures in the Console dashboard are estimates for analytics purposes. For actual costs, refer to the [Cost page](https://platform.claude.com/cost). ## Related resources diff --git a/content/en/docs/claude-code/authentication.md b/content/en/docs/claude-code/authentication.md index 69ee62eb16..a75dca95e3 100644 --- a/content/en/docs/claude-code/authentication.md +++ b/content/en/docs/claude-code/authentication.md @@ -251,7 +251,7 @@ When multiple credentials are present, Claude Code chooses one in this order: 2. `ANTHROPIC_AUTH_TOKEN` environment variable. Sent as the `Authorization: Bearer` header. Use this when routing through an [LLM gateway or proxy](https://code.claude.com/docs/en/llm-gateway) that authenticates with bearer tokens rather than Anthropic API keys. 3. `ANTHROPIC_API_KEY` environment variable. Sent as the `X-Api-Key` header. Use this for direct Anthropic API access with a key from the [Claude Console](https://platform.claude.com). In interactive mode, you are prompted once to approve or decline the key, and your choice is remembered. To change it later, use the "Use custom API key" toggle in `/config`. The toggle only appears while `ANTHROPIC_API_KEY` is set in your environment. In non-interactive mode (`-p`), the key is always used when present. 4. [`apiKeyHelper`](https://code.claude.com/docs/en/settings-reference#apikeyhelper) script output. Use this for dynamic or rotating credentials, such as short-lived tokens fetched from a vault. -5. `CLAUDE_CODE_OAUTH_TOKEN` environment variable. A long-lived OAuth token generated by [`claude setup-token`](#generate-a-long-lived-token). Use this for CI pipelines and scripts where browser login isn't available. If you run `/login` while the variable is set, Claude Code switches the current session to the new login, but reads the variable again in every new session until you remove it from your shell profile or the `env` block of a [settings file](https://code.claude.com/docs/en/settings.md). +5. `CLAUDE_CODE_OAUTH_TOKEN` environment variable. A long-lived OAuth token generated by [`claude setup-token`](#generate-a-long-lived-token). Use this for CI pipelines and scripts where browser login isn't available. If you run `/login` while the variable is set, Claude Code switches the current session to the new login. To keep that login in new sessions, remove the variable from your shell profile and from [settings files that can set it](https://code.claude.com/docs/en/settings-reference.md#variables-claude-code-ignores-in-env), such as your user settings. 6. Anthropic profile and federation credentials, the credentials that the `ant` CLI and Workload Identity Federation use. A profile that `ant auth login` wrote ranks here only when you name it in `ANTHROPIC_PROFILE`; otherwise it ranks below `/login`. See [Anthropic profiles and federation credentials](#anthropic-profiles-and-federation-credentials). 7. Subscription OAuth credentials from `/login`. This is the default for Claude Pro, Max, Ultra, Team, and Enterprise users. diff --git a/content/en/docs/claude-code/changelog.md b/content/en/docs/claude-code/changelog.md index 8169dd26b5..3e43d6efd3 100644 --- a/content/en/docs/claude-code/changelog.md +++ b/content/en/docs/claude-code/changelog.md @@ -10,6 +10,109 @@ This page is generated from the [CHANGELOG.md on GitHub](https://github.com/anth Run `claude --version` to check your installed version. +**2.1.317** + +November 3, 2026 + +**Added** + +* Added a warning to `/schedule` when a new cloud scheduled task gets connectors you did not ask for, with how to remove them +* Added a check that asks before a web or shell tool call sends your account email address to the network +* Added `onFailure: "block"` for Agent SDK hook callbacks, so a callback that fails blocks the action instead of letting it run +* Added a notice in Claude Desktop's Code tab when your organization's remote managed settings haven't loaded for the session, and another once they do +* Added a notice when auto mode's check has no answer for a subagent's tool call, which used to leave nothing in the main view +* Added `anthropic.plan`, `anthropic.seat_type`, `anthropic.provider` and `anthropic.custom_base_url` to OTel metrics, events and spans +* Added a cost report to the Claude apps gateway admin API, `GET /v1/organizations/analytics/cost`, for reading past spend over a date range in total, per developer, per day or per IdP group +* Added a daily record of each developer's IdP groups on Claude apps gateways with `admin:` set, kept for `admin.identity_retention_days`, which the cost report groups by +* Added `CLAUDE_CODE_DISABLE_NESTED_SESSION_ID`: set it to `1` on a self-hosted runner to have `claude -p` run inside a session use that session's ID and transcript, as in earlier versions +* \[Cloud sessions] Added a link card to cloud sessions, so you can open or decline a link an MCP server asks you to visit instead of the request going unseen + +**Changed** + +* Changed SendMessage so a message to a running background agent arrives earlier: its running command moves to the background, without being stopped +* Changed subagents and teammates on a different model from the main conversation to use that model's saved effort level or its default, instead of the session's effort level +* Changed exit to skip the "Background work is running" prompt for plugin monitors +* Changed the built-in `plugin-authoring` skill to offer once, after a mod you built works, to help share the mod +* Removed the Read tool's "file unchanged since your last Read" stub: reading an unchanged file again returns its content +* \[Cloud sessions] Changed the organization environment dialog in admin settings to the personal dialogs' short layout: each section opens from a row, and unsaved input asks before closing +* \[Claude Tag] Changed newly pasted artifact links in Slack to show a simpler card with an Open button that opens the artifact in Claude, instead of Slack's side panel + +**8 improvements** + +* Improved the error shown on Microsoft Foundry when Azure credentials can't be loaded: it now says to check or refresh them, and reports as `cloud_credential_error` +* Improved `/design-sync` to say up front when your design system has moved to Claude, and stop before building instead of failing at upload +* Improved the startup error when a required Claude apps gateway can't be reached: it points to the network instead of a sign-in, and says when the gateway's TLS certificate can't be verified +* Improved the "Resume this session with" hint shown at exit to repeat the flags you launched with (for example `--chrome --debug`) ahead of `--resume` +* Improved how self-hosted runners recover from server errors: after a 5xx other than 501 or 529, a runner's next poll now opens a new connection instead of reusing the one that failed +* Improved how self-hosted runner sessions recover from server errors: after a 5xx other than 501 or 529, a session now opens new connections instead of reusing the one that failed +* Improved how self-hosted runner sessions recover when connections stop answering: after a heartbeat gets no answer, a session now opens new connections instead of trying each idle one in turn +* Remote Control: Improved fork names when the app doesn't set one: a long name keeps its "(fork)" ending, and in sessions started with `claude remote-control` a fork of "Name (fork)" is "Name (fork 2)" + +**62 bug fixes** + +* Fixed project and local MCP servers disconnecting after the first turn in some Claude desktop sessions +* Fixed auto mode failing every turn when an LLM gateway set as the base URL answers 403 or 422 to its server-side safety check (a 403 with an apiKeyHelper is unchanged) +* Fixed `claude auth status` exiting before a slow token refresh was saved, which could sign you out on the next run +* Fixed a project's `effortLevel` setting being ignored by sessions that an app starts ahead of time and then opens in the project, such as new sessions in the desktop app's Code tab +* Fixed `claude --from-pr` reporting "No conversations found" in projects with many sessions when the linked session was older than the first page +* Fixed the second of two simultaneous permission prompts showing no file path or command on claude.ai and the mobile apps +* Fixed Remote Control and SDK hosts offering "don't ask again" on a mod's tool calls +* Fixed session titles being lost in cloud and SDK sessions when a new message or Stop arrived while the title was generating +* Fixed self-paced `/loop` wakeups sometimes not being scheduled when Claude left a field out of its request +* Fixed auto mode in cloud sessions stopping for approval when the Artifact tool uploaded, wrote to a database or saved a file through the outputs folder +* Fixed skills synced from claude.ai being lost or downloaded again every ten minutes when they can't be written to disk +* Fixed `/schedule` leaving a cloud scheduled task's next run time and link out of its results after creating or updating it +* Fixed screen readers speaking a running subagent's elapsed time and token count on every change in screen reader mode +* Fixed a region or network block (HTTP 403) being shown as a sign-in failure; the error now explains the block +* Fixed Claude saying a working claude.ai connector needed authorization or had failed in cloud sessions when a synced plugin included the same server +* Fixed `claude -p` exiting 0 when a full disk or quota lost its transcript or \~/.claude.json writes; it now prints an error and, in text and json output, exits 1. Full NFS exports may be missed +* Fixed edits to settings files made in the first second or so after launch not taking effect until a settings file changed again +* Fixed old transcripts not being cleaned up on machines where some runs skip cleanup, such as runs using `--setting-sources` +* Fixed deleted agent team inboxes being re-created by a teammate's late message +* Fixed a re-created agent teammate being removed from its team by an earlier shutdown approval +* Fixed stored scheduled tasks being impossible to list or delete after scheduled tasks were turned off +* Fixed Claude deleting your most recently updated `/team-onboarding` guide when asked to delete one without naming which +* Fixed Claude saying a `/team-onboarding` guide was deleted when the server refused the delete +* Fixed the Claude apps gateway hiding Amazon Bedrock's "Input is too long." error, which left sessions failing every turn with "upstream rejected the request" instead of compacting +* Fixed self-hosted runner sessions losing recent turns or the whole conversation when restarted while a plan waited for approval +* Fixed "Prompt is too long" after automatic compaction in sessions whose very large CLAUDE.md changed since it was last sent +* Fixed high memory use and slow startup in headless sessions with many plugins that register commands +* Fixed stdio MCP servers receiving an empty `AWS_BEARER_TOKEN_BEDROCK` when their env config sets it to empty; the variable is now unset, so the server can use the machine's own AWS credentials +* Fixed API requests failing with "unable to get local issuer certificate" behind some TLS-inspecting proxies after a root certificate renewal +* Fixed very long conversations losing their earlier summary when compaction had to shorten its own request +* Fixed a PDF's own metadata being able to make Read and @-mentions under-count its pages +* Fixed `DISABLE_PROMPT_CACHING_OPUS` and `DISABLE_PROMPT_CACHING_SONNET` having no effect on `[1m]`, other-region and undated spellings of the default model +* Fixed `/artifacts` and the Artifact tool's shared list showing no shared artifacts when you have 200 or more of your own +* Fixed Claude treating partial Grep and Glob results as complete when a search hit its time limit +* Fixed OpenTelemetry exports to an `https://` endpoint through a proxy never being sent when they started while another export was still in progress +* Fixed a flood of connection attempts to a proxy that blocks (HTTP 403) OpenTelemetry exports to an `http://` endpoint +* Fixed OpenTelemetry exports hanging indefinitely behind a proxy that never answers; they now time out after 10 seconds, or `OTEL_EXPORTER_OTLP_TIMEOUT` up to 30 seconds +* Fixed resumed sessions telling Claude again about a file change it already knew about +* Fixed Claude sometimes not using a built-in tool in a resumed session after an earlier call failed because the tool was switched off +* Fixed `/remote-control` answering "Unknown command" instead of saying that Remote Control is turned off by the `disableRemoteControl` setting +* Fixed agent team teammates in tmux or iTerm2 panes starting in auto mode when the lead session was in manual mode +* Fixed a background session sometimes losing a just-made change of permission mode when it was upgraded or retired +* Fixed Ctrl+C stopping all running background agents when pressed to clear typed text at the prompt +* Fixed /feedback showing "Enter to confirm" while a report is being sent +* Fixed child processes of a stopped shell command sometimes being sent SIGTERM twice, which could make some programs skip their cleanup +* Fixed `claude -p` run inside a cloud or self-hosted runner session sharing that session's ID: it wrote into the session's transcript, and a restart could resume the wrong conversation +* Fixed `claude -p` run inside a cloud or self-hosted runner session generating a title of its own and sending it to that session +* Windows: Fixed every tool call being refused on some volumes where the native path lookup fails; the working-directory check now compares the folder's identity instead +* Windows: Fixed the session scratchpad and other temporary paths growing with your project's path length in sessions not started by Claude Desktop, which made repositories cloned into them hit the 260-character path limit +* Gateway: Fixed the status line and `/usage` showing a developer's own spend limit as 100% used after their group's pooled budget ran out +* Self-hosted runner: Fixed Claude not seeing the interrupted tool call when a session moves to a new runner and the turn is older than `CLAUDE_CODE_RESUME_INTERRUPTED_TURN_MAX_AGE_MS` +* Self-hosted runner: Fixed an MCP server that was switched off coming back on after the session moved to a new machine, when the session service had refused to save the switch +* \[VSCode] Fixed forked conversations dropping messages: only one of the tool calls Claude ran in parallel was kept, and the last messages a compaction kept were lost, which could leave Claude's answer without the question it answered +* \[VSCode] Fixed a message being lost when Claude did not finish starting in time: the extension now starts Claude once more before showing the error +* \[VSCode] Fixed the sign-in screen opening when a request is blocked for its region or network +* \[VSCode] Fixed the Account panel showing the plan name with a lower-cased second word +* \[VSCode] Fixed file links in a Claude tab opening on top of the chat instead of in another editor group +* \[VSCode] Fixed attachment chips, menus, banners and dialogs in the Claude panel staying small when `chat.fontSize` is raised +* \[VSCode] Fixed `ultrathink` not raising effort for its turn or showing its rainbow when telemetry is off +* \[Cloud sessions] Fixed adding a network secret for a host that already has one silently replacing it; the Add secret form now refuses and points you to the existing secret +* \[Cloud sessions] Fixed new scheduled tasks ignoring your organization's default environment: the form now starts on the one an admin chose instead of the Anthropic-hosted default +* \[Remote Control] Fixed the next message to an idle session going unanswered after you restart `claude remote-control`, when you sent it within a minute of your previous message + **2.1.316** October 31, 2026 diff --git a/content/en/docs/claude-code/cli-reference.md b/content/en/docs/claude-code/cli-reference.md index 97792ba4a9..f03a8d09dc 100644 --- a/content/en/docs/claude-code/cli-reference.md +++ b/content/en/docs/claude-code/cli-reference.md @@ -99,11 +99,11 @@ Customize Claude Code's behavior with these command-line flags. `claude --help` | `--init-only` | Run [Setup](https://code.claude.com/docs/en/hooks.md#setup) and `SessionStart` hooks, then exit without starting a conversation | `claude --init-only` | | `--include-hook-events` | Include hook lifecycle events in the output stream. `SessionStart` and `Setup` hook events are always included and don't need this flag. Some hook events, such as `Notification`, `SessionEnd`, `PreCompact`, and `PostCompact`, never produce a `hook_started` event, even with this flag. For those events, Claude Code still emits `hook_progress` while a command hook that runs for more than a second produces output, and emits `hook_response` only when a [hook that runs in the background](https://code.claude.com/docs/en/hooks.md#run-hooks-in-the-background) finishes. Requires `--output-format stream-json` | `claude -p --output-format stream-json --verbose --include-hook-events "query"` | | `--include-partial-messages` | Include partial streaming events in output. Requires `--print` and `--output-format stream-json` | `claude -p --output-format stream-json --verbose --include-partial-messages "query"` | -| `--input-format` | Specify input format for print mode (options: `text`, `stream-json`) | `claude -p --output-format json --input-format stream-json` | +| `--input-format` | Specify input format for print mode (options: `text`, `stream-json`) | `claude -p --input-format stream-json --output-format stream-json --verbose` | | `--json-schema` | Get validated JSON output matching a JSON Schema after the agent completes its workflow (print mode only). See [structured outputs](https://code.claude.com/docs/en/agent-sdk/structured-outputs.md). Claude Code exits with an error on an invalid schema and accepts the `format` keyword as an annotation without client-side validation | `claude -p --json-schema '{"type":"object","properties":{...}}' "query"` | | `--maintenance` | Run [Setup hooks](https://code.claude.com/docs/en/hooks.md#setup) with the `maintenance` matcher before the session (print mode only) | `claude -p --maintenance "query"` | | `--max-budget-usd` | Stop the run once estimated spend on API calls reaches this amount (print mode only). Claude Code checks the cap against its [client-side cost estimate](https://code.claude.com/docs/en/agent-sdk/cost-tracking.md#estimates-not-billing), which can differ from your bill. Spend from [subagents](https://code.claude.com/docs/en/sub-agents.md) counts toward the cap. Spend can pass the cap, so [leave headroom](https://code.claude.com/docs/en/agent-sdk/agent-loop.md#budget-headroom). When you return to a conversation with `--continue` or `--resume`, totals [restored from earlier runs](https://code.claude.com/docs/en/agent-sdk/cost-tracking.md#accumulate-costs-across-multiple-calls) don't count toward it. Once spend reaches the cap, spawning another subagent fails with `Budget limit reached`, and Claude Code stops background subagents that are still running; the cap-enforcement behaviors require Claude Code v2.1.217 or later | `claude -p --max-budget-usd 5.00 "query"` | -| `--max-turns` | Limit the number of agentic turns (print mode only). Exits with an error when the limit is reached. No limit by default. With `--input-format stream-json`, a message still queued when the limit ends a turn stays queued and starts a new turn with its own limit | `claude -p --max-turns 3 "query"` | +| `--max-turns` | Limit the number of agentic turns (print mode only). No limit by default. With `--input-format stream-json`, a message still queued when the limit ends a turn stays queued and starts a new turn with its own limit | `claude -p --max-turns 3 "query"` | | `--mcp-config` | Load MCP servers from JSON files or strings (space-separated). When you pass this flag with `-p`, Claude Code waits for still-pending servers to connect before running the first turn, up to the [`MCP_TIMEOUT`](https://code.claude.com/docs/en/env-vars) startup timeout, 30 seconds by default; a server with a [cached tool list](https://code.claude.com/docs/en/mcp.md#managing-your-servers) skips the wait and connects on first use. In a [self-hosted environment](https://code.claude.com/docs/en/self-hosted-environments-configuration.md#connection-timing), a shorter wait applies instead. The wait requires Claude Code v2.1.221 or later | `claude --mcp-config ./mcp.json` | | `--model` | Sets the model for the current session with a [model alias](https://code.claude.com/docs/en/model-config.md#model-aliases) such as `sonnet`, `opus`, `haiku`, or `fable`, or a model's full name. Overrides the [`model`](https://code.claude.com/docs/en/settings-reference#model) setting and [`ANTHROPIC_MODEL`](https://code.claude.com/docs/en/model-config#environment-variables) | `claude --model claude-sonnet-5` | | `--name`, `-n` | Set a display name for the session, shown in `/resume` and the terminal title. You can resume a named session with `claude --resume `. [`/rename`](https://code.claude.com/docs/en/commands) changes the name mid-session and also shows it on the prompt bar | `claude -n "my-feature-work"` | diff --git a/content/en/docs/claude-code/cloud-environments.md b/content/en/docs/claude-code/cloud-environments.md index d867ab01bf..ef3beee36f 100644 --- a/content/en/docs/claude-code/cloud-environments.md +++ b/content/en/docs/claude-code/cloud-environments.md @@ -335,6 +335,7 @@ Cloud sessions come with common language runtimes, build tools, and databases pr | **C/C++** | GCC, Clang, cmake, ninja, conan | | **Docker** | docker, dockerd, docker compose | | **Databases** | PostgreSQL 16, Redis 7.0 | +| **Browser** | Chrome for Testing at `/usr/bin/google-chrome`, with the `CHROME_PATH` environment variable set to that path | | **Utilities** | git, gh, jq, yq, ripgrep, tmux, vim, nano | ¹ Bun is installed but has known [proxy compatibility issues](#install-dependencies-with-a-sessionstart-hook) for package fetching. diff --git a/content/en/docs/claude-code/commands.md b/content/en/docs/claude-code/commands.md index cd4e230cbc..0634302c33 100644 --- a/content/en/docs/claude-code/commands.md +++ b/content/en/docs/claude-code/commands.md @@ -35,7 +35,7 @@ Most commands are useful at a specific point in a session, from setting up a pro The table below lists all the commands included in Claude Code. Most are built-in commands whose behavior is coded into the CLI. Two kinds of entries are marked: * **[Skill](https://code.claude.com/docs/en/skills.md#bundled-skills)**: a bundled skill. It works like skills you write yourself: a prompt handed to Claude. - * `/verify` runs only when you invoke it. Before v2.1.215, Claude could also run `/verify` on its own. + * `/verify` runs only when you invoke it. * **[Workflow](https://code.claude.com/docs/en/workflows.md#bundled-workflows)**: a bundled [dynamic workflow](https://code.claude.com/docs/en/workflows.md) that fans work out across many subagents and runs in the background. * `/deep-research` runs only when you invoke it. diff --git a/content/en/docs/claude-code/costs.md b/content/en/docs/claude-code/costs.md index 9675c60964..430abdadc3 100644 --- a/content/en/docs/claude-code/costs.md +++ b/content/en/docs/claude-code/costs.md @@ -20,7 +20,9 @@ This page covers Claude Code usage only: how to [track your costs](#track-your-c > > The Session block in `/usage` shows API token usage and is intended for API users. Claude Pro, Max, and Ultra subscribers have usage included in their subscription, so the session cost figure isn't relevant for billing purposes. Subscribers see plan usage bars, activity stats, and a usage breakdown on the same screen. -The Session block at the top of `/usage` shows detailed token usage statistics for your current session. Claude Code computes the dollar figure locally from token counts at list price, unless a [`modelPricing`](https://code.claude.com/docs/en/settings-reference#modelpricing) table is in effect. An administrator sets one in your organization's managed settings so the figure uses your contracted rates, and while a table is in effect the `Total cost` line carries the note `at your organization's configured rates`. The figure is an estimate, so for authoritative billing see the Usage page in the [Claude Console](https://platform.claude.com/usage). +The Session block at the top of `/usage` shows detailed token usage statistics for your current session. + +Claude Code computes the dollar figure locally from token counts at list price, unless a [`modelPricing`](https://code.claude.com/docs/en/settings-reference#modelpricing) table is in effect. An administrator sets one in your organization's managed settings so the figure uses your contracted rates, and while a table is in effect the `Total cost` line carries the note `at your organization's configured rates`. The figure is an estimate, so for authoritative billing see [Manage costs for your organization](#manage-costs-for-your-organization). ```text theme={null} Total cost: $0.55 @@ -138,7 +140,7 @@ For Team and Enterprise members without billing access, the confirmation appears If you run `/usage-credits` again while your earlier request is waiting on an admin, Claude Code tells you a request has already been sent rather than sending a duplicate. After an admin dismisses your request, running the command again sends a new one. Before v2.1.222, a dismissed request also blocked new requests. -On Pro and Max plans, when you reach your spend limit with usage credits still available, Claude Code prompts you to raise or remove the limit without leaving the CLI. If the server rejects the change, see [Could not update your spend limit](https://code.claude.com/docs/en/errors.md#could-not-update-your-spend-limit). +On Pro, Max, and Ultra plans, when you reach your spend limit with usage credits left, Claude Code prompts you to raise or remove the limit without leaving the CLI. If the server rejects the change, see [Could not update your spend limit](https://code.claude.com/docs/en/errors.md#could-not-update-your-spend-limit). ## Manage costs for your organization @@ -149,7 +151,7 @@ The table maps each setup to where you see spend, where you cap it, and how you | Your setup | See spend | Cap spend | Per-user reporting | | :- | :- | :- | :- | | [Claude for Teams or Enterprise](#claude-for-teams-and-enterprise) | [Spend report in org analytics](https://support.claude.com/en/articles/12883420-view-usage-analytics-for-team-and-enterprise-plans) | Spend limits in admin settings | [Spend report CSV](https://support.claude.com/en/articles/12883420-view-usage-analytics-for-team-and-enterprise-plans); [Enterprise Analytics API](https://platform.claude.com/docs/en/api/admin/analytics) on Enterprise | -| [Claude Console (API)](#claude-console) | [Console usage page](https://platform.claude.com/usage) | Workspace spend limits | [Console dashboard](https://platform.claude.com/claude-code), [Claude Code Analytics API](https://platform.claude.com/docs/en/build-with-claude/claude-code-analytics-api) | +| [Claude Console (API)](#claude-console) | [Console Cost page](https://platform.claude.com/cost) | Workspace spend limits | [Console dashboard](https://platform.claude.com/claude-code), [Claude Code Analytics API](https://platform.claude.com/docs/en/build-with-claude/claude-code-analytics-api) | | [Amazon Bedrock, Google Cloud's Agent Platform, or Microsoft Foundry](#cloud-providers) | Your cloud billing console | Your cloud's budget controls | [OpenTelemetry](https://code.claude.com/docs/en/monitoring-usage.md) or an [LLM gateway](https://code.claude.com/docs/en/llm-gateway) | [OpenTelemetry export](https://code.claude.com/docs/en/monitoring-usage.md) works on every setup and is the only option that streams per-user token and cost metrics into your own observability stack in near real time. @@ -193,7 +195,7 @@ API organizations manage Claude Code spend through [workspaces](https://platform > > For organizations with custom rate limits, Claude Code traffic in this workspace counts toward your organization's overall API rate limits. You can set a [workspace rate limit](https://platform.claude.com/docs/en/api/rate-limits#setting-lower-limits-for-workspaces) on this workspace's Limits page in the Claude Console to cap Claude Code's share and protect other production workloads. -For per-user reporting, the [Console dashboard](https://platform.claude.com/claude-code) shows spend and accepted lines per member, and the [Claude Code Analytics API](https://platform.claude.com/docs/en/build-with-claude/claude-code-analytics-api) returns the same daily per-user metrics programmatically with an [Admin API key](https://platform.claude.com/settings/admin-keys). See [analytics for API customers](https://code.claude.com/docs/en/analytics.md#access-analytics-for-api-customers). +For per-user reporting, the [Console dashboard](https://platform.claude.com/claude-code) shows spend and lines accepted per member, and the [Claude Code Analytics API](https://platform.claude.com/docs/en/build-with-claude/claude-code-analytics-api) returns daily per-user metrics programmatically with an [Admin API key](https://platform.claude.com/settings/admin-keys). See [analytics for API customers](https://code.claude.com/docs/en/analytics.md#access-analytics-for-api-customers). #### Rate limit recommendations diff --git a/content/en/docs/claude-code/desktop-changelog.md b/content/en/docs/claude-code/desktop-changelog.md index c2e332cf54..c59615686c 100644 --- a/content/en/docs/claude-code/desktop-changelog.md +++ b/content/en/docs/claude-code/desktop-changelog.md @@ -131,6 +131,8 @@ From the Browser pane, you can: * Start or stop servers, or stop them all at once, from the **Dev servers** menu in the Browser pane's header * Choose whether the Browser keeps cookies after you quit the app with **Keep cookies** in the Browser pane's **⋮** menu, so you don't have to sign in again during development +In an SSH session, you lose the pane's cookies when you quit Desktop. You can't change that with **Keep cookies**. + Claude creates the initial server configuration based on your project. If your app uses a custom dev command, edit `.claude/launch.json` to match your setup. See [Configure preview servers](#configure-preview-servers) for the full reference. To clear the Browser's saved data, select **Clear browsing data** in the Browser pane's **⋮** menu. To turn the Browser off entirely, turn off **Browser tools** in **Settings > Code** or **Settings > Claude Code**. @@ -312,7 +314,7 @@ To see how full this session's context window is, find your Code tab layout: In either layout, type `/context` in the prompt box to print a per-category breakdown of this session's context window in the chat. -Both layouts have the usage ring next to the model picker. Click it to see your plan usage, which is shared across all your Claude Code surfaces. +In both layouts, the usage ring is in the row under the prompt box. Click it to see your plan usage, which is shared across all your Claude Code surfaces. ## Let Claude use your computer @@ -409,9 +411,9 @@ In the split view, the pane you opened or clicked last has focus, and the other #### Run a session in its own worktree -In a project that's a Git repository, turn on **Worktree** before you start a session to run it in its own [Git worktree](https://code.claude.com/docs/en/worktrees.md), an isolated copy of the project. By default, **Worktree** is off and Claude works in the project folder itself. On the [current layout](#check-which-layout-you-have), turn on the **Worktree** button in the [row under the prompt box](#start-a-session). +In a project that's a Git repository, turn on **Worktree** before you start a session to run it in its own [Git worktree](https://code.claude.com/docs/en/worktrees.md), an isolated copy of the project. By default, **Worktree** is off and Claude works in the project folder itself. On the [current layout](#check-which-layout-you-have), turn on **Worktree** in the [row under the prompt box](#start-a-session). -* **With a [third-party provider](https://code.claude.com/docs/en/third-party-integrations.md)**: if the row under the prompt box shows the project folder control but no **Worktree** button, click that control and turn on **Worktree** +* **With a [third-party provider](https://code.claude.com/docs/en/third-party-integrations.md)**: if the row under the prompt box shows the project folder control but not **Worktree**, click the project folder control and turn on **Worktree** * **As the default for a [saved local or SSH environment](#create-a-saved-environment)**: set **Worktree** when you create or edit the environment * **[Earlier layout](#check-which-layout-you-have)**: select the **worktree** checkbox beside the branch name, above the prompt box @@ -1094,11 +1096,11 @@ You can leave the **SSH port** and **SSH key (optional)** fields empty. If you f ##### Connect on Windows without the OpenSSH client -On Windows, you connect through Desktop's built-in SSH client if your computer doesn't meet [the requirements for the OpenSSH client](#use-your-ssh-configuration). With a third-party provider, you connect through the built-in client by default, and your administrator can change that. For the setting, see [SSH remote sessions in Claude Desktop on 3P](https://claude.com/docs/third-party/claude-desktop/ssh-remote-sessions). +On Windows, you connect through Desktop's built-in SSH client if your computer doesn't meet [the requirements for the OpenSSH client](#use-your-ssh-configuration). With a third-party provider, which client you connect through also depends on your Desktop version and on your administrator's settings. See [SSH remote sessions in Claude Desktop on 3P](https://claude.com/docs/third-party/claude-desktop/ssh-remote-sessions). With the built-in client, you can still enter a `Host` name from your SSH configuration in the **SSH host** field if your `PATH` has an `ssh` command, with these limits: -* **Settings from the entry**: Desktop takes `HostName`, `User`, `Port`, and `IdentityFile`. It also takes `ProxyCommand` if an `sh` shell is on your `PATH`. +* **Settings from the entry**: Desktop takes `HostName`, `User`, `Port`, `IdentityFile`, and `ConnectTimeout`. It also takes `ProxyCommand` if an `sh` shell is on your `PATH`. * **SSH key (optional)**: leave this field empty to keep the entry's `IdentityFile`, because a key file that you pick here replaces the `IdentityFile` * **`CertificateFile` and `ProxyJump`**: Desktop ignores `CertificateFile`, and the connection fails if the entry sets `ProxyJump`. To use either setting, [connect through the OpenSSH client](#use-your-ssh-configuration). @@ -1198,7 +1200,7 @@ Run `ssh` with the host in a terminal to confirm that the entry still connects t ##### Raise the SSH connection timeout -If your SSH configuration sets no `ConnectTimeout` for the host, Desktop gives `ssh` 30 seconds to connect. Through a jump host or a `ProxyCommand`, that time includes the time the route takes to connect. If your route needs longer, add a higher value to the entry: +If your session times out while it connects through a jump host or a `ProxyCommand`, raise `ConnectTimeout` in the remote machine's entry in your `~/.ssh/config`. Use more than 90 seconds. Add any time that a jump host or a `ProxyCommand` waits for you, for example at a login prompt or for a phone push: ```text ~/.ssh/config theme={null} Host devbox @@ -1210,7 +1212,15 @@ Host devbox `ssh` uses the first value it finds for a host, so keep the entry above any `Host *` entry that sets `ConnectTimeout`. To confirm, run `ssh -G devbox` in a terminal on your computer. Its output includes `connecttimeout 120`. After you change the value, quit and reopen Desktop. -If the remote machine itself waits for an approval on your phone, approve within 45 seconds, whatever `ConnectTimeout` you set. You can't raise this limit, because Desktop sets `ServerAliveInterval` and `ServerAliveCountMax` itself, and `ssh` then closes a login in which the remote machine sends nothing for that long. If a jump host or a `ProxyCommand` waits for you instead, raise `ConnectTimeout` in the remote machine's entry to cover that time. +If your SSH configuration sets no `ConnectTimeout` for the host, Desktop gives `ssh` 30 seconds to connect. Through a jump host or a `ProxyCommand`, that time includes the time the route takes to connect. + +| `ConnectTimeout` | Connection | Time that you have | +| - | - | - | +| Not set | You start a session through a jump host or a `ProxyCommand`, with Claude Desktop v4.4212.0 or later on macOS or Linux | 30 seconds, then a second try with 90 seconds. If Desktop showed you a prompt during the first try, you have no second try. Time at a login prompt that Desktop shows for a `ProxyJump` host doesn't count. Other waits on the route do. | +| Not set | Desktop on Windows or an earlier version, a remote machine that sets `MaxSessions 1`, or a reconnect that Desktop starts on its own | 30 seconds. Every wait on the route counts. | +| Set | Every connection and reconnect | The value that you set. Every wait on the route counts. | + +If the remote machine itself waits for an approval on your phone, approve within 45 seconds, whatever `ConnectTimeout` you set. You can't raise this limit, because Desktop sets `ServerAliveInterval` and `ServerAliveCountMax` itself, and `ssh` then closes a login in which the remote machine sends nothing for that long. ##### Fix a `Match host` block that only Desktop applies @@ -1334,7 +1344,7 @@ File edits and some tools can fail while Desktop is disconnected. If the task ne > > Edits still fail in some cases, including these: > -> * **Built-in SSH client**: Desktop uses it, for example in a Microsoft Store install, on a Windows computer without Microsoft's OpenSSH 9.4 or later, or by default on Windows with a third-party provider +> * **Built-in SSH client**: Desktop uses it, for example in a Microsoft Store install, or on a Windows computer without Microsoft's OpenSSH 9.4 or later > * **Repository location**: the repository is your home directory, a folder above it, or `~/.claude` > * **macOS paths**: on a macOS remote machine, the repository is under `/Volumes`, or a folder name in the path of the repository or the worktree has a `~` or a non-ASCII character > * **Folder restrictions**: your organization restricts which folders sessions may use @@ -1369,11 +1379,12 @@ If Desktop hasn't reconnected when you come back, send a message in the session. * **Remembered password**: a password that you let Desktop remember also works without a prompt, but for a long absence prefer a key that your SSH agent holds. If sign-ins with that password break off or hang, Desktop can stop reconnecting and wait for you. * **Any other prompt**: if the remote machine prompts for anything else, such as a one-time code, you can get a notification on your computer. Click the notification, or send a message in the session, and Desktop shows the prompt. -> [accordion] If a jump host asks for a sign-in, the outage is long, output is missing, or the process is gone +> [accordion] If a jump host asks for a sign-in, the outage is long, a message isn't sent, output is missing, or the process is gone > > * **Jump host, pushes stop while you're away**: this can happen with Desktop on macOS or Linux when nobody answers a jump host's sign-in, for example a push to a phone. Desktop then stops reconnecting while nobody is at your computer. When you unlock or use the computer, you can get another push, because Desktop can try again. After three unanswered attempts it waits until you retry or send a message. > * **Jump host, pushes keep coming**: where Desktop can't tell that nobody answers, as with Desktop on Windows, it keeps trying while it has a process to rejoin, whether or not that process still runs. You can get another push with each attempt. To end the attempts, quit Desktop, which [can cost you the running task](#reopen-a-session-after-you-quit-desktop). -> * **Long outage**: Desktop slows to about one attempt every five minutes. To reconnect sooner, retry in the session or send a message, which Desktop delivers once it is connected. +> * **Long outage**: Desktop slows to about one attempt every five minutes. To reconnect sooner, retry in the session or send a message. Desktop tries to deliver the message once it is connected. +> * **Message not sent**: the row `Your organization's settings haven't loaded, so your message to wasn't sent. Retry to send it.` under your message means that Desktop reconnected and held your message back, because your organization's settings hadn't loaded yet. Select **Retry** to send the message now. If you do nothing, Desktop tries again once the settings load. > * **Missing output**: while Desktop is disconnected, the helper keeps each session's most recent Claude Code output in a 16 MiB buffer and drops older output. After Desktop reconnects, the session can show `Loading recent output from …`. If Desktop can't load all of the output, you see the row `Some output produced while you were disconnected may be missing here.` The row doesn't mean that the task stopped. > * **Process gone**: the process ended while Desktop was disconnected, as when the remote machine restarts. Desktop can then start a new one from the conversation's saved history and tell Claude to continue the task. If the task stays stopped, send a message. With a third-party provider, update to Claude Desktop v2.42304.0 or later, because earlier versions never continue the task on their own. @@ -2290,6 +2301,8 @@ Find the card's title, or the code that ends the error message, in this table, t | ` is out of disk space` | `[ENOSPC]` or `[EDQUOT]` | Free space or quota on the remote machine, in your home directory or `/tmp` | | `Free up disk space on this computer` | `[ENOSPC]` or `[EDQUOT]`, in a message that starts with `Couldn't prepare the deploy locally` | Free space on your computer | | `Claude Code won't start on ` | `[CLI_UNRESPONSIVE]` | Wait a minute, then try again. If it keeps failing, run the command that the message names on the remote machine to see whether Claude Code answers there. | +| `Ask 's administrator to let Claude's server run` | `[SERVER_NOT_RUNNABLE]` or `[SETUP_DIR_NOEXEC]` | Ask the remote machine's administrator to let programs run from `~/.claude/remote/` on that machine, as the [requirements](#remote-machine-requirements-for-ssh-sessions) say | +| `Try again in a few minutes` | `[DOWNLOAD_BUSY]` | Wait a few minutes, then try again. Anthropic's download server or a proxy on your computer's network reported that it is busy. If the card keeps coming back, ask that network's administrator whether a proxy limits downloads. | For any other message, check the [remote machine requirements](#remote-machine-requirements-for-ssh-sessions). diff --git a/content/en/docs/claude-code/desktop.md b/content/en/docs/claude-code/desktop.md index c2e332cf54..c59615686c 100644 --- a/content/en/docs/claude-code/desktop.md +++ b/content/en/docs/claude-code/desktop.md @@ -131,6 +131,8 @@ From the Browser pane, you can: * Start or stop servers, or stop them all at once, from the **Dev servers** menu in the Browser pane's header * Choose whether the Browser keeps cookies after you quit the app with **Keep cookies** in the Browser pane's **⋮** menu, so you don't have to sign in again during development +In an SSH session, you lose the pane's cookies when you quit Desktop. You can't change that with **Keep cookies**. + Claude creates the initial server configuration based on your project. If your app uses a custom dev command, edit `.claude/launch.json` to match your setup. See [Configure preview servers](#configure-preview-servers) for the full reference. To clear the Browser's saved data, select **Clear browsing data** in the Browser pane's **⋮** menu. To turn the Browser off entirely, turn off **Browser tools** in **Settings > Code** or **Settings > Claude Code**. @@ -312,7 +314,7 @@ To see how full this session's context window is, find your Code tab layout: In either layout, type `/context` in the prompt box to print a per-category breakdown of this session's context window in the chat. -Both layouts have the usage ring next to the model picker. Click it to see your plan usage, which is shared across all your Claude Code surfaces. +In both layouts, the usage ring is in the row under the prompt box. Click it to see your plan usage, which is shared across all your Claude Code surfaces. ## Let Claude use your computer @@ -409,9 +411,9 @@ In the split view, the pane you opened or clicked last has focus, and the other #### Run a session in its own worktree -In a project that's a Git repository, turn on **Worktree** before you start a session to run it in its own [Git worktree](https://code.claude.com/docs/en/worktrees.md), an isolated copy of the project. By default, **Worktree** is off and Claude works in the project folder itself. On the [current layout](#check-which-layout-you-have), turn on the **Worktree** button in the [row under the prompt box](#start-a-session). +In a project that's a Git repository, turn on **Worktree** before you start a session to run it in its own [Git worktree](https://code.claude.com/docs/en/worktrees.md), an isolated copy of the project. By default, **Worktree** is off and Claude works in the project folder itself. On the [current layout](#check-which-layout-you-have), turn on **Worktree** in the [row under the prompt box](#start-a-session). -* **With a [third-party provider](https://code.claude.com/docs/en/third-party-integrations.md)**: if the row under the prompt box shows the project folder control but no **Worktree** button, click that control and turn on **Worktree** +* **With a [third-party provider](https://code.claude.com/docs/en/third-party-integrations.md)**: if the row under the prompt box shows the project folder control but not **Worktree**, click the project folder control and turn on **Worktree** * **As the default for a [saved local or SSH environment](#create-a-saved-environment)**: set **Worktree** when you create or edit the environment * **[Earlier layout](#check-which-layout-you-have)**: select the **worktree** checkbox beside the branch name, above the prompt box @@ -1094,11 +1096,11 @@ You can leave the **SSH port** and **SSH key (optional)** fields empty. If you f ##### Connect on Windows without the OpenSSH client -On Windows, you connect through Desktop's built-in SSH client if your computer doesn't meet [the requirements for the OpenSSH client](#use-your-ssh-configuration). With a third-party provider, you connect through the built-in client by default, and your administrator can change that. For the setting, see [SSH remote sessions in Claude Desktop on 3P](https://claude.com/docs/third-party/claude-desktop/ssh-remote-sessions). +On Windows, you connect through Desktop's built-in SSH client if your computer doesn't meet [the requirements for the OpenSSH client](#use-your-ssh-configuration). With a third-party provider, which client you connect through also depends on your Desktop version and on your administrator's settings. See [SSH remote sessions in Claude Desktop on 3P](https://claude.com/docs/third-party/claude-desktop/ssh-remote-sessions). With the built-in client, you can still enter a `Host` name from your SSH configuration in the **SSH host** field if your `PATH` has an `ssh` command, with these limits: -* **Settings from the entry**: Desktop takes `HostName`, `User`, `Port`, and `IdentityFile`. It also takes `ProxyCommand` if an `sh` shell is on your `PATH`. +* **Settings from the entry**: Desktop takes `HostName`, `User`, `Port`, `IdentityFile`, and `ConnectTimeout`. It also takes `ProxyCommand` if an `sh` shell is on your `PATH`. * **SSH key (optional)**: leave this field empty to keep the entry's `IdentityFile`, because a key file that you pick here replaces the `IdentityFile` * **`CertificateFile` and `ProxyJump`**: Desktop ignores `CertificateFile`, and the connection fails if the entry sets `ProxyJump`. To use either setting, [connect through the OpenSSH client](#use-your-ssh-configuration). @@ -1198,7 +1200,7 @@ Run `ssh` with the host in a terminal to confirm that the entry still connects t ##### Raise the SSH connection timeout -If your SSH configuration sets no `ConnectTimeout` for the host, Desktop gives `ssh` 30 seconds to connect. Through a jump host or a `ProxyCommand`, that time includes the time the route takes to connect. If your route needs longer, add a higher value to the entry: +If your session times out while it connects through a jump host or a `ProxyCommand`, raise `ConnectTimeout` in the remote machine's entry in your `~/.ssh/config`. Use more than 90 seconds. Add any time that a jump host or a `ProxyCommand` waits for you, for example at a login prompt or for a phone push: ```text ~/.ssh/config theme={null} Host devbox @@ -1210,7 +1212,15 @@ Host devbox `ssh` uses the first value it finds for a host, so keep the entry above any `Host *` entry that sets `ConnectTimeout`. To confirm, run `ssh -G devbox` in a terminal on your computer. Its output includes `connecttimeout 120`. After you change the value, quit and reopen Desktop. -If the remote machine itself waits for an approval on your phone, approve within 45 seconds, whatever `ConnectTimeout` you set. You can't raise this limit, because Desktop sets `ServerAliveInterval` and `ServerAliveCountMax` itself, and `ssh` then closes a login in which the remote machine sends nothing for that long. If a jump host or a `ProxyCommand` waits for you instead, raise `ConnectTimeout` in the remote machine's entry to cover that time. +If your SSH configuration sets no `ConnectTimeout` for the host, Desktop gives `ssh` 30 seconds to connect. Through a jump host or a `ProxyCommand`, that time includes the time the route takes to connect. + +| `ConnectTimeout` | Connection | Time that you have | +| - | - | - | +| Not set | You start a session through a jump host or a `ProxyCommand`, with Claude Desktop v4.4212.0 or later on macOS or Linux | 30 seconds, then a second try with 90 seconds. If Desktop showed you a prompt during the first try, you have no second try. Time at a login prompt that Desktop shows for a `ProxyJump` host doesn't count. Other waits on the route do. | +| Not set | Desktop on Windows or an earlier version, a remote machine that sets `MaxSessions 1`, or a reconnect that Desktop starts on its own | 30 seconds. Every wait on the route counts. | +| Set | Every connection and reconnect | The value that you set. Every wait on the route counts. | + +If the remote machine itself waits for an approval on your phone, approve within 45 seconds, whatever `ConnectTimeout` you set. You can't raise this limit, because Desktop sets `ServerAliveInterval` and `ServerAliveCountMax` itself, and `ssh` then closes a login in which the remote machine sends nothing for that long. ##### Fix a `Match host` block that only Desktop applies @@ -1334,7 +1344,7 @@ File edits and some tools can fail while Desktop is disconnected. If the task ne > > Edits still fail in some cases, including these: > -> * **Built-in SSH client**: Desktop uses it, for example in a Microsoft Store install, on a Windows computer without Microsoft's OpenSSH 9.4 or later, or by default on Windows with a third-party provider +> * **Built-in SSH client**: Desktop uses it, for example in a Microsoft Store install, or on a Windows computer without Microsoft's OpenSSH 9.4 or later > * **Repository location**: the repository is your home directory, a folder above it, or `~/.claude` > * **macOS paths**: on a macOS remote machine, the repository is under `/Volumes`, or a folder name in the path of the repository or the worktree has a `~` or a non-ASCII character > * **Folder restrictions**: your organization restricts which folders sessions may use @@ -1369,11 +1379,12 @@ If Desktop hasn't reconnected when you come back, send a message in the session. * **Remembered password**: a password that you let Desktop remember also works without a prompt, but for a long absence prefer a key that your SSH agent holds. If sign-ins with that password break off or hang, Desktop can stop reconnecting and wait for you. * **Any other prompt**: if the remote machine prompts for anything else, such as a one-time code, you can get a notification on your computer. Click the notification, or send a message in the session, and Desktop shows the prompt. -> [accordion] If a jump host asks for a sign-in, the outage is long, output is missing, or the process is gone +> [accordion] If a jump host asks for a sign-in, the outage is long, a message isn't sent, output is missing, or the process is gone > > * **Jump host, pushes stop while you're away**: this can happen with Desktop on macOS or Linux when nobody answers a jump host's sign-in, for example a push to a phone. Desktop then stops reconnecting while nobody is at your computer. When you unlock or use the computer, you can get another push, because Desktop can try again. After three unanswered attempts it waits until you retry or send a message. > * **Jump host, pushes keep coming**: where Desktop can't tell that nobody answers, as with Desktop on Windows, it keeps trying while it has a process to rejoin, whether or not that process still runs. You can get another push with each attempt. To end the attempts, quit Desktop, which [can cost you the running task](#reopen-a-session-after-you-quit-desktop). -> * **Long outage**: Desktop slows to about one attempt every five minutes. To reconnect sooner, retry in the session or send a message, which Desktop delivers once it is connected. +> * **Long outage**: Desktop slows to about one attempt every five minutes. To reconnect sooner, retry in the session or send a message. Desktop tries to deliver the message once it is connected. +> * **Message not sent**: the row `Your organization's settings haven't loaded, so your message to wasn't sent. Retry to send it.` under your message means that Desktop reconnected and held your message back, because your organization's settings hadn't loaded yet. Select **Retry** to send the message now. If you do nothing, Desktop tries again once the settings load. > * **Missing output**: while Desktop is disconnected, the helper keeps each session's most recent Claude Code output in a 16 MiB buffer and drops older output. After Desktop reconnects, the session can show `Loading recent output from …`. If Desktop can't load all of the output, you see the row `Some output produced while you were disconnected may be missing here.` The row doesn't mean that the task stopped. > * **Process gone**: the process ended while Desktop was disconnected, as when the remote machine restarts. Desktop can then start a new one from the conversation's saved history and tell Claude to continue the task. If the task stays stopped, send a message. With a third-party provider, update to Claude Desktop v2.42304.0 or later, because earlier versions never continue the task on their own. @@ -2290,6 +2301,8 @@ Find the card's title, or the code that ends the error message, in this table, t | ` is out of disk space` | `[ENOSPC]` or `[EDQUOT]` | Free space or quota on the remote machine, in your home directory or `/tmp` | | `Free up disk space on this computer` | `[ENOSPC]` or `[EDQUOT]`, in a message that starts with `Couldn't prepare the deploy locally` | Free space on your computer | | `Claude Code won't start on ` | `[CLI_UNRESPONSIVE]` | Wait a minute, then try again. If it keeps failing, run the command that the message names on the remote machine to see whether Claude Code answers there. | +| `Ask 's administrator to let Claude's server run` | `[SERVER_NOT_RUNNABLE]` or `[SETUP_DIR_NOEXEC]` | Ask the remote machine's administrator to let programs run from `~/.claude/remote/` on that machine, as the [requirements](#remote-machine-requirements-for-ssh-sessions) say | +| `Try again in a few minutes` | `[DOWNLOAD_BUSY]` | Wait a few minutes, then try again. Anthropic's download server or a proxy on your computer's network reported that it is busy. If the card keeps coming back, ask that network's administrator whether a proxy limits downloads. | For any other message, check the [remote machine requirements](#remote-machine-requirements-for-ssh-sessions). diff --git a/content/en/docs/claude-code/env-vars.md b/content/en/docs/claude-code/env-vars.md index 08e41b6868..49215768d2 100644 --- a/content/en/docs/claude-code/env-vars.md +++ b/content/en/docs/claude-code/env-vars.md @@ -126,7 +126,7 @@ Numeric variables such as timeouts, token budgets, and retry counts accept scien > * `CLAUDE_CODE_TMUX_TRUECOLOR` > * `IS_DEMO` > -> One other variable has its own rule: `FORCE_HYPERLINK` reads a number, so only `0` turns it off. Each variable's row also states its own rule. +> Each variable's row also states its own rule. | Variable | Purpose | | :- | :- | @@ -239,7 +239,7 @@ Numeric variables such as timeouts, token budgets, and retry counts accept scien | `CLAUDE_CODE_DISABLE_BG_EXIT_HANDOFF` | Set to `1` to stop a [background session's](https://code.claude.com/docs/en/agent-view.md) in-flight work when the [supervisor](https://code.claude.com/docs/en/agent-view.md#the-supervisor-process) stops, restarts, or updates that session's process, instead of handing it to the session's next process. That work is the session's running background shell commands, plus background subagents as of v2.1.198. Affects only that handoff: backgrounding a session with `←` or [`/background`](https://code.claude.com/docs/en/agent-view#from-inside-a-session) still carries in-flight background work over. Requires Claude Code v2.1.196 or later | | `CLAUDE_CODE_DISABLE_BG_SHELL_PRESSURE_REAP` | Set to `1` to stop Claude Code from terminating [background shell commands](https://code.claude.com/docs/en/interactive-mode.md#background-bash-commands) under memory pressure. By default, on macOS and Linux, Claude Code terminates background shells when the operating system reports critical memory pressure and the session has been idle for 30 minutes with no turn or subagent running. Windows has no memory-pressure signal, so this variable has no effect there. Requires Claude Code v2.1.193 or later | | `CLAUDE_CODE_DISABLE_BUNDLED_SKILLS` | Set to `1` to disable the [skills](https://code.claude.com/docs/en/skills.md) and workflows included with Claude Code: bundled skills and workflows are removed entirely, while built-in commands like `/init` stay typable but are hidden from the model. `/doctor` stays typable like the built-in commands; hide it with `DISABLE_DOCTOR_COMMAND` instead. Skills from plugins, `.claude/skills/`, and `.claude/commands/` are unaffected. Equivalent to the [`disableBundledSkills`](https://code.claude.com/docs/en/settings-reference#disablebundledskills) setting | -| `CLAUDE_CODE_DISABLE_CFC_PROMPT` | Set to `1` to keep the [Claude in Chrome](https://code.claude.com/docs/en/chrome.md) browser tools available while omitting the Chrome section of the system prompt and the `/claude-in-chrome` [bundled skill](https://code.claude.com/docs/en/skills.md#bundled-skills). For hosts that embed Claude Code and supply their own browser guidance. Requires Claude Code v2.1.257 or later | +| `CLAUDE_CODE_DISABLE_CFC_PROMPT` | For hosts that embed Claude Code and supply their own browser guidance. Set to `1` to keep the [Claude in Chrome](https://code.claude.com/docs/en/chrome.md) browser tools available while omitting the Chrome section of the system prompt and the `/claude-in-chrome` [bundled skill](https://code.claude.com/docs/en/skills.md#bundled-skills). In VS Code, the extension at v2.1.314 or later also leaves the Claude in Chrome instructions out of a session's messages. Requires Claude Code v2.1.257 or later | | `CLAUDE_CODE_DISABLE_CLAUDE_MDS` | Set to `1` to prevent loading any CLAUDE.md memory files into context, including user, project, and auto memory files | | `CLAUDE_CODE_DISABLE_CRON` | Set to `1` to disable [session-scoped scheduled tasks](https://code.claude.com/docs/en/scheduled-tasks.md). The `/loop` skill and cron tools become unavailable and any already-scheduled tasks stop firing, including tasks that are already running mid-session | | `CLAUDE_CODE_DISABLE_DANGEROUS_RM_TIMEOUT` | Set to `1` to turn off the `auto` and `bypassPermissions` [time limit and denials](https://code.claude.com/docs/en/permission-modes.md#time-limits-and-denials-in-auto-and-bypasspermissions-modes) on critical-path removals. These removals then go to the classifier in `auto` mode, and get an untimed prompt in `bypassPermissions` mode wherever Claude Code can show one. Set it in the environment that launches Claude Code, since Claude Code ignores a copy delivered through a settings `env` block. Requires Claude Code v2.1.281 or later | @@ -307,7 +307,7 @@ Numeric variables such as timeouts, token budgets, and retry counts accept scien | `CLAUDE_CODE_GIT_BASH_PATH` | Windows only: path to the Git Bash executable (`bash.exe`). Use when Git Bash is installed but not in your PATH. If the path doesn't exist or the file isn't named `bash.exe`, `sh.exe`, `bash`, or `sh`, Claude Code ignores the variable and auto-detects Git Bash as if it were unset, logging a warning visible with `--debug`. Before v2.1.219, Claude Code exited at startup when the path didn't exist, and used any existing file as the shell without checking that it was bash or sh. See [Windows setup](https://code.claude.com/docs/en/setup.md#set-up-on-windows) | | `CLAUDE_CODE_GLOB_HIDDEN` | Set to `false` to exclude dotfiles from results when Claude invokes the [Glob tool](https://code.claude.com/docs/en/tools-reference.md#glob-tool-behavior). Included by default. Does not affect `@` file autocomplete, `ls`, Grep, or Read | | `CLAUDE_CODE_GLOB_NO_IGNORE` | Set to `false` to make the [Glob tool](https://code.claude.com/docs/en/tools-reference.md#glob-tool-behavior) respect `.gitignore` patterns. By default, Glob returns all matching files including gitignored ones. Does not affect `@` file autocomplete, which has its own [`respectGitignore` setting](https://code.claude.com/docs/en/settings-reference#respectgitignore) | -| `CLAUDE_CODE_GLOB_TIMEOUT_SECONDS` | Timeout in seconds for Glob tool file discovery. Defaults to 20 seconds on most platforms and 60 seconds on WSL | +| `CLAUDE_CODE_GLOB_TIMEOUT_SECONDS` | Timeout in seconds for [Glob](https://code.claude.com/docs/en/tools-reference.md#glob-tool-behavior) and Grep tool searches. Defaults to 20 seconds on most platforms and 60 seconds on WSL | | `CLAUDE_CODE_GOAL_CHECKIN_MINUTES` | How many minutes background work can keep an active goal waiting before Claude Code [asks Claude to check on it](https://code.claude.com/docs/en/goal.md#background-work-defers-evaluation). Default `30`. Set `0` to turn check-ins off. Give whole minutes in plain digits, at most `10080`, which is one week. Claude Code treats any other value as unset and uses the default. Requires Claude Code v2.1.234 or later | | `CLAUDE_CODE_GZIP_REQUEST_BODIES` | Set to `0` to turn off gzip compression of Claude API, telemetry, and [artifact](https://code.claude.com/docs/en/artifacts.md) publish request bodies sent to `api.anthropic.com`. By default, Claude Code compresses large request bodies on direct connections and skips compression when you send requests through a proxy, configure a client certificate, or set `NODE_EXTRA_CA_CERTS`. Use `0` if a [TLS-inspecting proxy](https://code.claude.com/docs/en/network-config.md#ca-certificate-store) that Claude Code can't detect mishandles compressed requests | | `CLAUDE_CODE_HIDE_CWD` | Set to `1` to hide the working directory in the startup logo. Useful for screenshares or recordings where the path exposes your OS username | @@ -335,9 +335,9 @@ Numeric variables such as timeouts, token budgets, and retry counts accept scien | `CLAUDE_CODE_NONBLOCKING_STDOUT` | Set to `1` to write terminal output through a second non-blocking file descriptor, so a terminal that stops reading, such as a paused tmux control-mode pane or a stalled SSH connection, can't freeze Claude Code mid-session. Applies on macOS, Linux, and WSL when stdout is a terminal. Requires Claude Code v2.1.261 or later | | `CLAUDE_CODE_NONSTREAMING_TIMEOUT_RETRIES` | Limit how many times Claude Code re-sends a [non-streaming request](https://code.claude.com/docs/en/errors.md#streaming-response-ended-before-any-complete-data-was-received) that times out. With `0`, the request fails on the first timeout. See [Tune retry behavior](https://code.claude.com/docs/en/errors.md#tune-retry-behavior) for the timeout. Requires Claude Code v2.1.285 or later | | `CLAUDE_CODE_NO_FLICKER` | Set to `1` to enable [fullscreen rendering](https://code.claude.com/docs/en/fullscreen.md), a research preview that reduces flicker and keeps memory flat in long conversations. Overrides the [`tui`](https://code.claude.com/docs/en/settings-reference#tui) setting; you can also switch with `/tui fullscreen` | -| `CLAUDE_CODE_OAUTH_REFRESH_TOKEN` | OAuth refresh token for Claude.ai authentication. When set, `claude auth login` exchanges this token directly instead of opening a browser. Requires `CLAUDE_CODE_OAUTH_SCOPES`. Useful for provisioning authentication in automated environments | -| `CLAUDE_CODE_OAUTH_SCOPES` | Space-separated OAuth scopes the refresh token was issued with, such as `"user:profile user:inference user:sessions:claude_code"`. Required when `CLAUDE_CODE_OAUTH_REFRESH_TOKEN` is set | -| `CLAUDE_CODE_OAUTH_TOKEN` | OAuth access token for claude.ai authentication. Alternative to `/login` for SDK and automated environments. Takes precedence over keychain-stored credentials. Generate one with [`claude setup-token`](https://code.claude.com/docs/en/authentication#generate-a-long-lived-token). Unless you run [`/login`](https://code.claude.com/docs/en/authentication#authentication-precedence), Claude Code uses the token you set for the whole session. To replace an expired token, generate a new one and restart | +| `CLAUDE_CODE_OAUTH_REFRESH_TOKEN` | OAuth refresh token for claude.ai authentication. When set, `claude auth login` exchanges this token directly instead of opening a browser. Requires `CLAUDE_CODE_OAUTH_SCOPES`. Useful for provisioning authentication in automated environments. Ignored in [project and local settings](https://code.claude.com/docs/en/settings-reference.md#variables-claude-code-ignores-in-env) | +| `CLAUDE_CODE_OAUTH_SCOPES` | Space-separated OAuth scopes the refresh token was issued with, such as `"user:profile user:inference user:sessions:claude_code"`. Required when `CLAUDE_CODE_OAUTH_REFRESH_TOKEN` is set. Ignored in [project and local settings](https://code.claude.com/docs/en/settings-reference.md#variables-claude-code-ignores-in-env) | +| `CLAUDE_CODE_OAUTH_TOKEN` | OAuth access token for claude.ai authentication. Alternative to `/login` for SDK and automated environments. Ignored in [project and local settings](https://code.claude.com/docs/en/settings-reference.md#variables-claude-code-ignores-in-env). Takes precedence over keychain-stored credentials. Generate one with [`claude setup-token`](https://code.claude.com/docs/en/authentication#generate-a-long-lived-token). Unless you run [`/login`](https://code.claude.com/docs/en/authentication#authentication-precedence), Claude Code uses the token you set for the whole session. To replace an expired token, generate a new one and restart | | `CLAUDE_CODE_OPUS_4_6_FAST_MODE_OVERRIDE` | Removed in v2.1.160 and now a no-op. Previously pinned [fast mode](https://code.claude.com/docs/en/fast-mode.md) to Claude Opus 4.6 instead of the current default. Opus 4.6 no longer supports fast mode | | `CLAUDE_CODE_OTEL_CONTENT_MAX_LENGTH` | Maximum length of content-bearing OpenTelemetry attributes (model responses, tool content, system prompts, raw API bodies), truncation marker included, in UTF-16 code units (default: 61440, i.e. 60 KB). Raise it only if your telemetry backend accepts attribute values larger than 64 KB, or lower it to cut telemetry volume. Requires Claude Code v2.1.214 or later. See [Monitoring](https://code.claude.com/docs/en/monitoring-usage.md) | | `CLAUDE_CODE_OTEL_DIAG_STDERR` | Set to `1` to write OpenTelemetry exporter diagnostic errors to stderr. By default these errors only appear with `--debug`, so a misconfigured exporter such as a Prometheus port collision otherwise fails silently. Requires Claude Code v2.1.179 or later. See [Monitoring](https://code.claude.com/docs/en/monitoring-usage.md) | @@ -469,7 +469,7 @@ Numeric variables such as timeouts, token budgets, and retry counts accept scien | `ENABLE_PROMPT_CACHING_1H_BEDROCK` | Deprecated. Use `ENABLE_PROMPT_CACHING_1H` instead. Has no effect on [Claude apps gateway](https://code.claude.com/docs/en/claude-apps-gateway) sessions, even when the gateway routes to Amazon Bedrock | | `ENABLE_TOOL_SEARCH` | Controls [MCP tool search](https://code.claude.com/docs/en/mcp.md#scale-with-mcp-tool-search). Unset or `true` defers MCP tools, except in the [cases that keep tool search off](https://code.claude.com/docs/en/mcp.md#configure-tool-search). `auto` turns tool search on once definitions reach 10% of the context window. `auto:N` sets a custom threshold, such as `auto:5` for 5%. `false` loads all tools upfront. If a gateway rejects tool search, see [Tool search through an LLM gateway](https://code.claude.com/docs/en/mcp.md#tool-search-through-a-gateway) | | `FORCE_AUTOUPDATE_PLUGINS` | Set to `1` to force plugin auto-updates even when the main auto-updater is disabled via `DISABLE_AUTOUPDATER` | -| `FORCE_HYPERLINK` | Set to `1` to enable clickable OSC 8 hyperlinks when your terminal supports them but isn't auto-detected, or `0` to disable them. When unset, Claude Code enables hyperlinks only when it detects terminal support. Claude Code parses this value as a number, not a Boolean, so a value such as `false`, `no`, or `off` enables hyperlinks rather than disabling them. The footer [PR or merge request badge](https://code.claude.com/docs/en/interactive-mode.md#pr-review-status) renders as a hyperlink even when Claude Code can't detect terminal support, such as over SSH. Set `0` to render the badge as plain text | +| `FORCE_HYPERLINK` | Set to `1` to enable clickable OSC 8 hyperlinks when your terminal supports them but isn't auto-detected. When unset, Claude Code enables most hyperlinks only when it detects terminal support. The footer [PR or merge request badge](https://code.claude.com/docs/en/interactive-mode.md#pr-review-status) and long sign-in URLs are links either way. Set `0`, `false`, `no`, or `off` to render all of them as plain text. Before v2.1.314, `false`, `no`, and `off` enabled hyperlinks instead | | `FORCE_PROMPT_CACHING_5M` | Set to `1` to force the 5-minute prompt cache TTL even when 1-hour TTL would otherwise apply. Overrides `CLAUDE_CODE_PROMPT_CACHE_TTL`, `CLAUDE_CODE_SUBAGENT_PROMPT_CACHE_TTL`, `ENABLE_PROMPT_CACHING_1H`, and the `promptCacheTtl` and `subagentPromptCacheTtl` settings | | `HTTP_PROXY` | Specify HTTP proxy server for network connections | | `HTTPS_PROXY` | Specify HTTPS proxy server for network connections | @@ -586,7 +586,6 @@ With fetching off, you can't: * Get [Claude-drafted feedback](https://code.claude.com/docs/en/tools-reference.md#sendfeedback-tool-behavior), which Claude Code turns on through a fetched flag * Have Claude [treat large pastes as pasted rather than typed text](https://code.claude.com/docs/en/terminal-config.md#how-claude-treats-pasted-text); the content behind a `[Pasted text #N]` placeholder reaches Claude unmarked * Have Claude Code [exclude MCP tools whose input schema the API would reject](https://code.claude.com/docs/en/mcp.md#tools-with-invalid-input-schemas) -* Have Claude Code [compact a long conversation while your terminal session is idle](https://code.claude.com/docs/en/settings-reference.md#idlecompaction), shortly before a one-hour prompt cache expires ### First session after an install or upgrade diff --git a/content/en/docs/claude-code/errors.md b/content/en/docs/claude-code/errors.md index 2461bb525b..ba42f99399 100644 --- a/content/en/docs/claude-code/errors.md +++ b/content/en/docs/claude-code/errors.md @@ -552,7 +552,7 @@ When a proxy, load balancer, or gateway answers with an HTML error page, the mes * Check [status.claude.com](https://status.claude.com), or the provider status page named in the message, for active incidents * Wait a minute, then send your message again. Your original message is still in the conversation, so for a long prompt you can type `try again` instead of pasting the whole thing. -* If [`ANTHROPIC_BASE_URL`](https://code.claude.com/docs/en/env-vars) points at an [LLM gateway](https://code.claude.com/docs/en/llm-gateway) and every request fails this way, check whether your gateway is rejecting the tool search fields Claude Code sends by default. To check, set `ENABLE_TOOL_SEARCH=false` as [Tool search through an LLM gateway](https://code.claude.com/docs/en/mcp.md#tool-search-through-a-gateway) describes, then try again. Before v2.1.304, tool search was off behind a gateway unless you turned it on with `ENABLE_TOOL_SEARCH`. +* If [`ANTHROPIC_BASE_URL`](https://code.claude.com/docs/en/env-vars) points at an [LLM gateway](https://code.claude.com/docs/en/llm-gateway) and every request fails this way, check that your gateway and its upstream accept [tool search](https://code.claude.com/docs/en/mcp.md#tool-search-through-a-gateway) fields. By default, Claude Code sends `defer_loading` tool fields and `tool_reference` blocks, with the `anthropic-beta` header that enables them. Before v2.1.304, tool search was off behind a gateway unless you turned it on with `ENABLE_TOOL_SEARCH`. * If the error persists with no posted incident, run `/feedback` so Anthropic can investigate with your request details. See [Report an error](#report-an-error) if `/feedback` is unavailable in your environment. ### API Error: Repeated 529 Overloaded errors @@ -837,7 +837,7 @@ Usage counts against the session and weekly allowances at the same time. A singl * Run `/usage-credits` to buy additional usage on Pro, Max, and Ultra, or to request it from your admin on Team and Enterprise. See [usage credits for paid plans](https://support.claude.com/en/articles/12429409-extra-usage-for-paid-claude-plans) for how this is billed. * To upgrade your plan for higher base limits, see [claude.com/pricing](https://claude.com/pricing) -Before a window runs out, Claude Code can warn you that you've used most of it, with a message such as `You've used 85% of your session limit · resets 3:45pm`. To watch your remaining allowance continuously, add the `rate_limits` fields to a [custom status line](https://code.claude.com/docs/en/statusline.md#rate-limit-usage), or in the Desktop app click the [usage ring](https://code.claude.com/docs/en/desktop.md#check-usage) next to the model picker. +Before a window runs out, Claude Code can warn you that you've used most of it, with a message such as `You've used 85% of your session limit · resets 3:45pm`. To watch your remaining allowance, add the `rate_limits` fields to a [custom status line](https://code.claude.com/docs/en/statusline.md#rate-limit-usage), or in the Desktop app click the [usage ring](https://code.claude.com/docs/en/desktop.md#check-usage). ### Usage credits required for 1M context @@ -1350,7 +1350,7 @@ Please run /login · API Error: 401 Invalid authentication credentials * If `/status` shows only your login, run `/login` once. If the credential was revoked, a fresh login replaces it. * If the same message returns for the same login account, the account or organization is no longer active. Check the account and organization that `/status` reports, and ask your organization admin to restore access. * If [`ANTHROPIC_BASE_URL`](https://code.claude.com/docs/en/env-vars) points at an [LLM gateway](https://code.claude.com/docs/en/llm-gateway), the text after `401` is your gateway's message rather than Anthropic's, and `/login` doesn't change it. Fix the credential your gateway expects instead. -* If every request fails with a `401` once your gateway has the credential it expects, check whether the gateway is rejecting the tool search fields Claude Code sends by default. To check, set `ENABLE_TOOL_SEARCH=false` as [Tool search through an LLM gateway](https://code.claude.com/docs/en/mcp.md#tool-search-through-a-gateway) describes, then try again. Before v2.1.304, tool search was off behind a gateway unless you turned it on with `ENABLE_TOOL_SEARCH`. +* If every request fails with a `401` once your gateway has the credential it expects, check that the gateway and its upstream accept [tool search](https://code.claude.com/docs/en/mcp.md#tool-search-through-a-gateway) fields. By default, Claude Code sends `defer_loading` tool fields and `tool_reference` blocks, with the `anthropic-beta` header that enables them. Before v2.1.304, tool search was off behind a gateway unless you turned it on with `ENABLE_TOOL_SEARCH`. ### Login expired @@ -1953,7 +1953,7 @@ Common causes include no internet access, a VPN that blocks `api.anthropic.com`, * Confirm you can reach the API host from the same shell by running `curl -I https://api.anthropic.com`. On Windows PowerShell use `curl.exe -I https://api.anthropic.com` so the built-in `Invoke-WebRequest` alias is not used. * If you are behind a corporate proxy, set `HTTPS_PROXY` before launching Claude Code and see [Network configuration](https://code.claude.com/docs/en/network-config.md) * If you route through an LLM gateway or relay, set [`ANTHROPIC_BASE_URL`](https://code.claude.com/docs/en/env-vars) to its address. See [Connect Claude Code to an LLM gateway](https://code.claude.com/docs/en/llm-gateway-connect.md) for setup. -* If `ANTHROPIC_BASE_URL` already points at your gateway and every request ends in `Connection dropped`, check whether your gateway is rejecting the tool search fields Claude Code sends by default. To check, set `ENABLE_TOOL_SEARCH=false` as [Tool search through an LLM gateway](https://code.claude.com/docs/en/mcp.md#tool-search-through-a-gateway) describes, then try again. Before v2.1.304, tool search was off behind a gateway unless you turned it on with `ENABLE_TOOL_SEARCH`. +* If `ANTHROPIC_BASE_URL` already points at your gateway and every request ends in `Connection dropped`, check that your gateway and its upstream accept [tool search](https://code.claude.com/docs/en/mcp.md#tool-search-through-a-gateway) fields. By default, Claude Code sends `defer_loading` tool fields and `tool_reference` blocks, with the `anthropic-beta` header that enables them. Before v2.1.304, tool search was off behind a gateway unless you turned it on with `ENABLE_TOOL_SEARCH`. * Ensure your firewall allows the hosts listed in [Network access requirements](https://code.claude.com/docs/en/network-config.md#network-access-requirements) * Intermittent failures are [retried automatically](#automatic-retries) @@ -2488,9 +2488,7 @@ Claude Code sends beta-only fields such as `context_management` and tool search' **What to do:** * If the message contains `context_management: Extra inputs are not permitted`, [update Claude Code](https://code.claude.com/docs/en/setup.md#update-claude-code) to v2.1.304 or later. After you update, Claude Code answers this rejection by sending the request once more without the field. Before v2.1.304, Claude Code didn't retry this rejection. -* If the message names `defer_loading` or `tool_reference`, update Claude Code or turn [tool search](https://code.claude.com/docs/en/mcp.md#tool-search-through-a-gateway) off: - * [Update Claude Code](https://code.claude.com/docs/en/setup.md#update-claude-code) to v2.1.305 or later. Claude Code then answers this rejection by sending the request once more without tool search fields. - * If you can't update, or the message still appears after you do, set `ENABLE_TOOL_SEARCH=false` in your shell or your [settings `env`](https://code.claude.com/docs/en/settings-reference#env). If a settings file already sets the variable, change it there, since that value [can override a shell export](https://code.claude.com/docs/en/settings-reference.md#how-env-values-interact-with-your-shell). Claude Code then loads MCP tools upfront. +* If the message names `defer_loading` or `tool_reference`, [update Claude Code](https://code.claude.com/docs/en/setup.md#update-claude-code) to v2.1.305 or later. Claude Code then answers this rejection by [sending the request once more](https://code.claude.com/docs/en/llm-gateway-protocol.md#retry-without-tool-search) without tool search fields. * If your gateway drops the header, configure it to forward the `anthropic-beta` header. See [feature pass-through](https://code.claude.com/docs/en/llm-gateway-protocol.md#feature-pass-through) for what gateways must forward. * As a fallback, set [`CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1`](https://code.claude.com/docs/en/env-vars) before launching. [Disable pre-release capabilities](https://code.claude.com/docs/en/llm-gateway-protocol.md#disable-pre-release-capabilities) covers the exact scope. @@ -2569,7 +2567,7 @@ There's an issue with the selected model (claude-...). It may not exist or you m * Use an alias such as `sonnet` or `opus` instead of a full versioned ID. Aliases resolve to a maintained default so they don't go stale. See [Model configuration](https://code.claude.com/docs/en/model-config.md). * If the wrong model keeps coming back in the CLI, a stale ID is set somewhere. Check the places you can set a model in [priority order](https://code.claude.com/docs/en/model-config.md#setting-your-model) and remove the stale value. * Claude Code reports an expired claude.ai login as [Login expired](#login-expired), not as this error. Before v2.1.206, an expired login that could no longer be refreshed failed every model with this error; run `/login` if you see that on an older version. -* If [`ANTHROPIC_BASE_URL`](https://code.claude.com/docs/en/env-vars) points at an [LLM gateway](https://code.claude.com/docs/en/llm-gateway) and every model fails this way, check whether your gateway is rejecting the tool search fields Claude Code sends by default. To check, set `ENABLE_TOOL_SEARCH=false` as [Tool search through an LLM gateway](https://code.claude.com/docs/en/mcp.md#tool-search-through-a-gateway) describes, then try again. Before v2.1.304, tool search was off behind a gateway unless you turned it on with `ENABLE_TOOL_SEARCH`. +* If [`ANTHROPIC_BASE_URL`](https://code.claude.com/docs/en/env-vars) points at an [LLM gateway](https://code.claude.com/docs/en/llm-gateway) and every model fails this way, check that your gateway and its upstream accept [tool search](https://code.claude.com/docs/en/mcp.md#tool-search-through-a-gateway) fields. By default, Claude Code sends `defer_loading` tool fields and `tool_reference` blocks, with the `anthropic-beta` header that enables them. Before v2.1.304, tool search was off behind a gateway unless you turned it on with `ENABLE_TOOL_SEARCH`. * For Google Cloud's Agent Platform deployments, see [Google Cloud's Agent Platform troubleshooting](https://code.claude.com/docs/en/google-vertex-ai.md#troubleshooting). ### Model is not a recognized model id @@ -6204,14 +6202,14 @@ Claude Code sent a request for a model ID that your Claude Code version doesn't In a script or harness that reads stderr, match on the `[claude-code:unrecognized_model]` prefix. After the prefix and one space, Claude Code writes a one-line JSON object. Claude Code can add fields to it in a later version, so ignore any field you don't expect. It writes at least these two: * `model`: the model string as you configured it -* `query_source`: the request path that used the model. Claude Code reports `sdk` for a `-p` run and a value that starts with `agent:` for a subagent. +* `query_source`: the request path that used the model. For example, the value is `sdk` for the main conversation of a `-p` run and starts with `agent:` for a subagent. Claude Code writes the line to one of two places, depending on how you run it: * In [non-interactive mode](https://code.claude.com/docs/en/headless.md) with `-p`, Claude Code writes it to stderr under every `--output-format`, so you can parse stdout without filtering the line out * In an interactive session or a [background session](https://code.claude.com/docs/en/agent-view.md), Claude Code writes it to the debug log instead; run with `--debug` to capture it at `~/.claude/debug/.txt` -Claude Code writes the line once per model string per process. It writes a separate line for each further unrecognized ID, such as one that a [subagent](https://code.claude.com/docs/en/sub-agents.md#choose-a-model) or [background functionality](https://code.claude.com/docs/en/costs.md#background-token-usage) uses. +Claude Code writes the line once per model ID per process. It writes a separate line for each further unrecognized ID, such as one that a [subagent](https://code.claude.com/docs/en/sub-agents.md#choose-a-model) or [background functionality](https://code.claude.com/docs/en/model-config.md#environment-variables) uses. Claude Code doesn't write the line for provider IDs it resolves to a model it recognizes, such as Amazon Bedrock `us.anthropic.claude-...` IDs, Google Cloud's Agent Platform IDs with an `@` version suffix, and Microsoft Foundry deployment names that contain a Claude model ID. Claude Code checks the model behind an Amazon Bedrock [application inference profile ARN](https://code.claude.com/docs/en/amazon-bedrock.md#map-each-model-version-to-an-inference-profile) rather than the ARN itself. It writes no line for an ARN it can't resolve, such as a mistyped one. diff --git a/content/en/docs/claude-code/fast-mode.md b/content/en/docs/claude-code/fast-mode.md index 081e0e19ce..c640177ff9 100644 --- a/content/en/docs/claude-code/fast-mode.md +++ b/content/en/docs/claude-code/fast-mode.md @@ -95,7 +95,7 @@ You see fast mode spend in a different place depending on how you signed in, so * **Pro, Max, and Ultra**: you pay for fast mode from your usage credits. Go to [**Settings > Usage**](https://claude.ai/settings/usage) on claude.ai, where the **Usage credits** section shows how much you've spent in usage credits this month. That figure includes fast mode but doesn't break it out separately. * **Team and Enterprise**: your organization pays for your fast mode usage from its usage credits. To see your own usage-credits spend, run [`/usage`](https://code.claude.com/docs/en/costs#check-your-usage-credits-spend). For where your organization sees that spend, see [Claude for Teams and Enterprise](https://code.claude.com/docs/en/costs.md#claude-for-teams-and-enterprise). -* **Claude Console**: your organization pays for fast mode with the rest of its API usage. On the Console [Usage](https://platform.claude.com/usage) and [Cost](https://platform.claude.com/cost) pages, select **Speed (Research Preview)** in the **Group by** menu to separate fast mode from standard-speed usage. You see that option only when the selected date range includes fast mode usage. +* **Claude Console**: your organization pays for fast mode with the rest of its API usage. On the Console [Usage](https://platform.claude.com/usage) and [Cost](https://platform.claude.com/cost) pages, select **Speed (research preview)** in the **Group by** menu to separate fast mode from standard-speed usage. You see that option only when the selected date range includes fast mode usage. ## Decide when to use fast mode diff --git a/content/en/docs/claude-code/google-vertex-ai.md b/content/en/docs/claude-code/google-vertex-ai.md index 8d49ca60f5..1caf030a86 100644 --- a/content/en/docs/claude-code/google-vertex-ai.md +++ b/content/en/docs/claude-code/google-vertex-ai.md @@ -192,15 +192,24 @@ Start Claude Code and run `/status` to confirm the setup. The `API provider` lin When Claude Code starts with Google Cloud's Agent Platform configured, it verifies that the models it intends to use are accessible in your project. -If you have pinned a model version that is older than the current Claude Code default, and your project can invoke the newer version, Claude Code prompts you to update the pin. Accepting writes the new model ID to your [user settings file](https://code.claude.com/docs/en/settings.md) and restarts Claude Code. Declining is remembered until the next default version change. +You may have pinned a model version that is older than the current Claude Code default. If your project can invoke the newer version, Claude Code prompts you to update the pin: + +* **If you accept**: Claude Code writes the new model ID to your [user settings file](https://code.claude.com/docs/en/settings.md) and restarts +* **If you decline**: Claude Code remembers your choice until the next default version change + +For a pin in the `env` block of [managed settings](https://code.claude.com/docs/en/managed-settings.md), Claude Code runs no check and shows no prompt. If the update prompt still appears for this pin, update Claude Code to v2.1.314 or later. Before v2.1.314, the managed pin stayed in effect after you accepted, so the prompt came back at the next start. If you have not pinned a model and the current default is unavailable in your project, Claude Code falls back for the current session and shows a notice. It tries earlier versions of the default model first and, when the default is an Opus model and no Opus version is available, falls back to the default Sonnet model. The fallback is not persisted. Enable the newer model in [Model Garden](https://console.cloud.google.com/vertex-ai/model-garden) or [pin a version](#5-pin-model-versions) to make the choice permanent. +### Start a session on a specific model + When you start the session on a specific Sonnet or Opus version, for example with `--model`, `ANTHROPIC_MODEL`, or the [`model` setting](https://code.claude.com/docs/en/settings-reference#model), that version acts as the session's pinned default for the matching `sonnet` or `opus` alias. Claude Code skips the availability check for the built-in default your model replaces and starts on the model you configured, with no fallback notice. -Model aliases such as `opus` don't act as pins, and neither does a model ID Claude Code doesn't recognize. +When you start a session on a model alias such as `opus` or on a model ID Claude Code doesn't recognize, that value doesn't act as a pin. + +### Remembered model refusals -When these checks find a model your project can't invoke, Claude Code remembers the refusal on this machine for up to a day, and launches during that time skip the remembered model without asking Agent Platform again. Claude Code checks a remembered refusal of a current default model again at launch once ten minutes have passed since the last check, so a default your administrator re-enables comes back. To turn the memory off, set [`CLAUDE_CODE_SKIP_MODEL_ACCESS_MEMORY=1`](https://code.claude.com/docs/en/env-vars). +When the startup model checks find a model your project can't invoke, Claude Code can remember the refusal on this machine for up to a day. Once ten minutes have passed since the last check, Claude Code checks a remembered refusal of a current default model again at launch. A default your administrator re-enables then comes back. To turn the memory off, set [`CLAUDE_CODE_SKIP_MODEL_ACCESS_MEMORY=1`](https://code.claude.com/docs/en/env-vars). ### When your organization enforces a model allowlist diff --git a/content/en/docs/claude-code/hooks.md b/content/en/docs/claude-code/hooks.md index 8a904e51bd..ab8cde746b 100644 --- a/content/en/docs/claude-code/hooks.md +++ b/content/en/docs/claude-code/hooks.md @@ -580,7 +580,7 @@ In addition to the [common fields](#common-fields), prompt and agent hooks accep | Field | Required | Description | | :- | :- | :- | | `prompt` | yes | Prompt text to send to the model. Use `$ARGUMENTS` as a placeholder for the hook input JSON. Escape with a backslash to include literal text: `\$1.00` renders as `$1.00` | -| `model` | no | Model to use for evaluation. Defaults to the model Claude Code uses for [background functionality](https://code.claude.com/docs/en/costs.md#background-token-usage) | +| `model` | no | Model to use for evaluation. Defaults to the model Claude Code uses for [background functionality](https://code.claude.com/docs/en/model-config.md#environment-variables) | ### Reference scripts by path @@ -3914,7 +3914,7 @@ Events that support `command`, `http`, and `mcp_tool` hooks but not `prompt` or Instead of executing a Bash command, prompt-based hooks: -1. Send the hook input and your prompt to a Claude model, by default the one Claude Code uses for [background functionality](https://code.claude.com/docs/en/costs.md#background-token-usage) +1. Send the hook input and your prompt to a Claude model, by default the one Claude Code uses for [background functionality](https://code.claude.com/docs/en/model-config.md#environment-variables) 2. The LLM responds with structured JSON containing a decision 3. Claude Code processes the decision automatically @@ -3947,7 +3947,7 @@ This `Stop` hook asks the LLM to evaluate whether all tasks are complete before | :- | :- | :- | | `type` | yes | Must be `"prompt"` | | `prompt` | yes | The prompt text to send to the LLM. Use `$ARGUMENTS` as a placeholder for the hook input JSON. If `$ARGUMENTS` is not present, input JSON is appended to the prompt | -| `model` | no | Model to use for evaluation. Defaults to the model Claude Code uses for [background functionality](https://code.claude.com/docs/en/costs.md#background-token-usage) | +| `model` | no | Model to use for evaluation. Defaults to the model Claude Code uses for [background functionality](https://code.claude.com/docs/en/model-config.md#environment-variables) | | `timeout` | no | Timeout in seconds. Default: 30 | | `continueOnBlock` | no | On the events it applies to, `true` feeds an `ok: false` reason back to Claude and continues instead of ending the turn. Default: `false`. See [Response schema](#response-schema) for per-event behavior | diff --git a/content/en/docs/claude-code/iam.md b/content/en/docs/claude-code/iam.md index 69ee62eb16..a75dca95e3 100644 --- a/content/en/docs/claude-code/iam.md +++ b/content/en/docs/claude-code/iam.md @@ -251,7 +251,7 @@ When multiple credentials are present, Claude Code chooses one in this order: 2. `ANTHROPIC_AUTH_TOKEN` environment variable. Sent as the `Authorization: Bearer` header. Use this when routing through an [LLM gateway or proxy](https://code.claude.com/docs/en/llm-gateway) that authenticates with bearer tokens rather than Anthropic API keys. 3. `ANTHROPIC_API_KEY` environment variable. Sent as the `X-Api-Key` header. Use this for direct Anthropic API access with a key from the [Claude Console](https://platform.claude.com). In interactive mode, you are prompted once to approve or decline the key, and your choice is remembered. To change it later, use the "Use custom API key" toggle in `/config`. The toggle only appears while `ANTHROPIC_API_KEY` is set in your environment. In non-interactive mode (`-p`), the key is always used when present. 4. [`apiKeyHelper`](https://code.claude.com/docs/en/settings-reference#apikeyhelper) script output. Use this for dynamic or rotating credentials, such as short-lived tokens fetched from a vault. -5. `CLAUDE_CODE_OAUTH_TOKEN` environment variable. A long-lived OAuth token generated by [`claude setup-token`](#generate-a-long-lived-token). Use this for CI pipelines and scripts where browser login isn't available. If you run `/login` while the variable is set, Claude Code switches the current session to the new login, but reads the variable again in every new session until you remove it from your shell profile or the `env` block of a [settings file](https://code.claude.com/docs/en/settings.md). +5. `CLAUDE_CODE_OAUTH_TOKEN` environment variable. A long-lived OAuth token generated by [`claude setup-token`](#generate-a-long-lived-token). Use this for CI pipelines and scripts where browser login isn't available. If you run `/login` while the variable is set, Claude Code switches the current session to the new login. To keep that login in new sessions, remove the variable from your shell profile and from [settings files that can set it](https://code.claude.com/docs/en/settings-reference.md#variables-claude-code-ignores-in-env), such as your user settings. 6. Anthropic profile and federation credentials, the credentials that the `ant` CLI and Workload Identity Federation use. A profile that `ant auth login` wrote ranks here only when you name it in `ANTHROPIC_PROFILE`; otherwise it ranks below `/login`. See [Anthropic profiles and federation credentials](#anthropic-profiles-and-federation-credentials). 7. Subscription OAuth credentials from `/login`. This is the default for Claude Pro, Max, Ultra, Team, and Enterprise users. diff --git a/content/en/docs/claude-code/interactive-mode.md b/content/en/docs/claude-code/interactive-mode.md index 6d1e094514..3f57752db9 100644 --- a/content/en/docs/claude-code/interactive-mode.md +++ b/content/en/docs/claude-code/interactive-mode.md @@ -708,7 +708,13 @@ Once the answer appears, the overlay accepts these keys. In an attached [background session](https://code.claude.com/docs/en/agent-view.md#attach-to-a-session), `Left` detaches and returns you to agent view, even while the answer is still arriving. The side question keeps running while you're away. The next time you attach to the session, the overlay reopens with the side question, or with its answer. Before v2.1.257, `Left` didn't detach there. -`/btw` sees your full conversation but has no tools. A [subagent](https://code.claude.com/docs/en/sub-agents.md) has tools and starts from the prompt it receives, or, for a [fork](https://code.claude.com/docs/en/sub-agents.md#fork-the-current-conversation), from a copy of this conversation. Use `/btw` to ask about what Claude already knows from this session; use a subagent to go find out something new. +`/btw` sees your full conversation, or the [subagent transcript you have open](#ask-btw-about-a-subagent), but has no tools. A [subagent](https://code.claude.com/docs/en/sub-agents.md) has tools and starts from the prompt it receives. A [fork](https://code.claude.com/docs/en/sub-agents.md#fork-the-current-conversation) starts from a copy of this conversation. Use `/btw` to ask about what Claude already knows from this session; use a subagent to go find out something new. + +### Ask /btw about a subagent + +With a [subagent's transcript open](https://code.claude.com/docs/en/sub-agents.md#observe-and-steer-running-forks), Claude answers `/btw` from that transcript instead of the main conversation, so you can ask what the subagent did. A later `/btw` from that transcript sees only the side questions you asked from it. Requires Claude Code v2.1.314 or later. + +From an [agent team](https://code.claude.com/docs/en/agent-teams.md) teammate's transcript, Claude answers from the main conversation. ## Task list @@ -749,7 +755,9 @@ Keep the session open. What happens next depends on how the wait ends: * **After your computer slept**: if it slept for more than about 30 minutes and the limit reset while it slept, the first line reads `Your usage limit has reset` and the second reads `Press enter to continue`. Press `Enter` to continue. After a shorter sleep, or one that ended before the reset, Claude Code continues on its own. * **Early**: when you finish adding [usage credits](https://code.claude.com/docs/en/costs.md#add-usage-credits-to-your-subscription) with `/usage-credits`, sign back in after `/upgrade`, or switch models with `/model` during the wait, Claude Code checks whether usage is available again and continues right away if it is. It doesn't check after an upgrade or purchase you make in a browser on your own. Under [`opusplan`](https://code.claude.com/docs/en/model-config#opusplan-model-setting) and other model settings that run plan mode on a different model, Claude Code waits for the reset instead. -The continued task runs like any other turn. Claude Code still asks for [permissions](https://code.claude.com/docs/en/permissions.md) as usual, so the task can stop on a prompt while you're away. If it hits the limit again, Claude Code re-arms the wait on its own at most twice in a row, then stops and shows `Automatic continue stopped after repeated usage-limit hits · /rate-limit-options to try again`. +In the continued task, Claude Code still asks for [permissions](https://code.claude.com/docs/en/permissions.md) as usual, so the task can stop on a prompt while you're away. If the task hits the limit again, the wait starts again. + +After three automatic continuations, automatic continue stops and the `Automatic continue stopped after repeated usage-limit hits` notification appears. Run `/rate-limit-options` to choose what to do next. When you send another prompt, or pick a wait from that menu, the count starts over. Automatic continue also stops after three continuations for a [`/goal`](https://code.claude.com/docs/en/goal) or [session-scoped scheduled task](https://code.claude.com/docs/en/scheduled-tasks.md) that runs through several reset windows. ### Cancel the wait diff --git a/content/en/docs/claude-code/jetbrains.md b/content/en/docs/claude-code/jetbrains.md index ce2306a595..12a598822a 100644 --- a/content/en/docs/claude-code/jetbrains.md +++ b/content/en/docs/claude-code/jetbrains.md @@ -39,6 +39,10 @@ Follow the [quickstart](https://code.claude.com/docs/en/quickstart.md) to instal Install the [Claude Code plugin](https://plugins.jetbrains.com/plugin/27310-claude-code-beta-) from the JetBrains Marketplace and restart your IDE. +> [!NOTE] +> +> The JetBrains Marketplace is third-party software, which Anthropic doesn't endorse, maintain, or audit. Anthropic submits the Claude Code plugin for publication to the JetBrains Marketplace. + If `claude` is installed somewhere your IDE can't find, set the full path in the plugin's [Claude command setting](#general-settings). Claude Code works with any paid Claude subscription (Pro, Max, Ultra, Team, or Enterprise) or a Claude Console account, and no API key is required. You'll be prompted to [log in](https://code.claude.com/docs/en/authentication.md#log-in-to-claude-code) the first time you run `claude`. diff --git a/content/en/docs/claude-code/llm-gateway-protocol.md b/content/en/docs/claude-code/llm-gateway-protocol.md index a023b5ee2b..b8a71fa2cb 100644 --- a/content/en/docs/claude-code/llm-gateway-protocol.md +++ b/content/en/docs/claude-code/llm-gateway-protocol.md @@ -237,23 +237,48 @@ When the upstream rejects one of these capabilities, Claude Code can retry the r * When the upstream rejects a `role: "system"` entry inside `messages`, Claude Code retries once without those mid-conversation system messages and carries their text in user messages instead. Later requests in the conversation keep that shape until the developer runs `/clear` or the conversation compacts * When the upstream rejects only the `cache_control` marker on a mid-conversation system message, Claude Code keeps the system messages and retries once with the marker moved. The marker goes on the last entry in `messages` that isn't a system message, in that retry and in later requests until Claude Code exits * When the upstream rejects a [thinking signature](https://platform.claude.com/docs/en/build-with-claude/extended-thinking), including with a `400` whose message says the block is `bound to a different conversation`, Claude Code removes earlier thinking blocks from the request, retries, and keeps them out of every later request. New responses still include thinking -* When the gateway or its upstream rejects the [advisor tool](https://code.claude.com/docs/en/advisor.md) entry in `tools` as an unrecognized tool type, Claude Code retries the request once without that entry and its `anthropic-beta` value. Later requests to that base URL leave the advisor out until Claude Code exits, and `/advisor` is unavailable to the developer for that time. Claude Code recognizes this rejection by a `400` or `422` response whose message names the tool type after `Input tag`, such as `Input tag 'advisor_20260301'`. Before v2.1.280, Claude Code didn't retry this rejection -* When the upstream rejects `output_config.effort` or its `anthropic-beta` value, Claude Code retries and adds neither to requests for that model until Claude Code exits. Your gateway needs no change if it forwards the upstream's `400` unmodified and the message: +* When the gateway or its upstream rejects the [advisor tool](https://code.claude.com/docs/en/advisor.md) entry in `tools` as an unrecognized tool type, Claude Code retries once without that entry and its `anthropic-beta` value. [Later requests](#how-long-a-rejected-beta-value-stays-out) omit them. Claude Code recognizes this rejection by a `400` or `422` response whose message names the tool type after `Input tag`, such as `Input tag 'advisor_20260301'`. Before v2.1.280, Claude Code didn't retry this rejection +* When the upstream rejects `output_config.effort` or its `anthropic-beta` value, the gateway sees the request once more without them. [Later requests](#how-long-a-rejected-beta-value-stays-out) omit them. Your gateway needs no change if it forwards the upstream's `400` unmodified and the message: * Names `output_config.effort` alongside `Extra inputs are not permitted` * Says the model doesn't support the effort parameter * Starts with `Unexpected value(s)` and lists `effort-2025-11-24` for the `anthropic-beta` header. Requires v2.1.310 or later. Developers whose [`ANTHROPIC_BETAS`](https://code.claude.com/docs/en/env-vars) lists the value keep sending it and getting the `400`, so have them remove that entry -* When the upstream rejects the `context_management` field or its `anthropic-beta` value, the gateway sees the request once more without them. If the gateway sees them again in a later request and the upstream rejects them again, the same retry follows. Claude Code recognizes this rejection by its message, for example one containing `context_management: Extra inputs are not permitted`. Before v2.1.304, Claude Code didn't retry this rejection +* When the upstream rejects the `context_management` field or its `anthropic-beta` value, the gateway sees the request once more without them. [Later requests](#how-long-a-rejected-beta-value-stays-out) omit them. Claude Code recognizes this rejection by its message, for example one containing `context_management: Extra inputs are not permitted`. Before v2.1.304, Claude Code didn't retry this rejection +* When a `400` rejects another `anthropic-beta` value by name, the gateway sees the request once more without it if [the retry covers that value](#retry-without-a-rejected-beta-value) * When the upstream rejects a beta tool field other than `defer_loading`, such as `strict`, the `400` reaches the developer. Before it does, the gateway can see the request again [without the tool search fields](#retry-without-tool-search). To stop sending such fields, have developers set [`CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1`](#disable-pre-release-capabilities) The `bound to a different conversation` rejection comes from the API's [preserved thinking](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking) check, which fails when `system`, `tools`, or earlier `messages` content differs from the request that produced the thinking. A gateway that rewrites any of that content can cause the rejection itself; [Libraries, proxies, and gateways](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#libraries-proxies-gateways) covers what to pass through unchanged. Most of this retry logic matches on the upstream's error wording, so forward error response bodies unmodified. A gateway that wraps upstream errors in its own envelope breaks the recovery path, even when it preserves the status code, unless the envelope's message carries a stable `capability_rejected:` token. [Claude apps gateway substitutes those tokens for cloud providers' error wording](https://code.claude.com/docs/en/claude-apps-gateway-config.md#upstream-error-messages), for example `capability_rejected: prompt_too_long`. +#### Retry without a rejected beta value + +When a `400` rejects by name an `anthropic-beta` value that this retry covers, the gateway sees the request once more without it. [Later requests](#how-long-a-rejected-beta-value-stays-out) omit the value. Most values it covers require v2.1.314 or later. + +Your gateway needs no change if the message of the `400` it returns carries the value in either of these forms: + +* **The API's sentence**: the `Unexpected value(s)` sentence that lists the value for the `anthropic-beta` header +* **A `beta_header:` token**: `capability_rejected: beta_header:` followed by the value, a [`capability_rejected:` token](#automatic-retry-and-error-forwarding) + +The retry doesn't cover cases such as a value with its own retry, a value Claude Code doesn't recognize, or a message that names no value: + +* **A value with its own retry, such as advisor or tool search**: the gateway sees [that capability's own retry](#automatic-retry-and-error-forwarding) instead +* **A value Claude Code doesn't recognize**: a value that a developer set through `ANTHROPIC_BETAS` stays on each request, so the developer's requests keep failing with the `400`. Have the developer remove the entry +* **A bare `invalid beta flag`**: Claude Code guesses which value the upstream rejected. If the request carried a value it guesses at, the gateway sees the request again without that value. If the `400` still reaches the developer, have your gateway name the rejected value in one of those forms + +#### How long a rejected beta value stays out + +| Upstream rejected | Requests that omit it | Until | +| :- | :- | :- | +| The advisor tool type, or the advisor's `anthropic-beta` value | Requests to the same base URL. `/advisor` is unavailable | Claude Code exits | +| `output_config.effort` or its `anthropic-beta` value | Requests for the same model | Claude Code exits | +| `context_management` or another `anthropic-beta` value the [retry by name](#retry-without-a-rejected-beta-value) covers | Requests in the same conversation | The conversation ends or Claude Code rebuilds its prompt, such as when the main conversation compacts | +| `context_management` or another value that retry covers, when the error message opens with the API's own sentence for the rejection, such as `Unexpected value(s)`, or carries a `beta_header:` token | Also new conversations on the model the rejected request named, including after `/clear` | Claude Code exits | + #### Retry without tool search -On v2.1.305 or later, a request carrying [`defer_loading` fields and `tool_reference` blocks](https://code.claude.com/docs/en/mcp#tool-search-through-a-gateway) can arrive again without them after a `400` or `422` whose cause Claude Code doesn't recognize. After a successful retry, later requests omit them too. +On v2.1.305 or later, Claude Code resends a request without [`defer_loading` fields and `tool_reference` blocks](https://code.claude.com/docs/en/mcp#tool-search-through-a-gateway) after a `400` or `422` that names tool search or whose cause it doesn't recognize. After a successful retry, later requests in that conversation omit them too. -The developer's requests keep working without any change on the gateway, with their MCP tools loaded upfront. Claude Code tries tool search again later, so the gateway can see another rejected request followed by its retry. To keep the fields out of every request, have developers set `ENABLE_TOOL_SEARCH=false`. For tool search itself, Claude Code expects the gateway to forward the `defer_loading` fields and `tool_reference` blocks with their `anthropic-beta` value. +The developer's requests keep working without any change on the gateway, with their MCP tools loaded upfront. When Claude Code tries tool search again, the gateway can see another rejected request followed by its retry. For tool search itself, Claude Code expects the gateway to forward the `defer_loading` fields and `tool_reference` blocks with their `anthropic-beta` value. ### Disable pre-release capabilities diff --git a/content/en/docs/claude-code/llm-gateway-rollout.md b/content/en/docs/claude-code/llm-gateway-rollout.md index 8d41d36825..62aed6d445 100644 --- a/content/en/docs/claude-code/llm-gateway-rollout.md +++ b/content/en/docs/claude-code/llm-gateway-rollout.md @@ -166,7 +166,7 @@ The same set of variables applies whichever path you choose. Most rollouts only | `CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY` | Queries the gateway's `/v1/models` at startup and adds the returned names to the `/model` picker | Your gateway serves `/v1/models` and you want developers' pickers populated from it | | `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS` | Stops Claude Code sending pre-release capability headers and body fields. [Disable pre-release capabilities](https://code.claude.com/docs/en/llm-gateway-protocol.md#disable-pre-release-capabilities) covers the exact scope | Your gateway forwards to an Amazon Bedrock or Google Cloud's Agent Platform upstream that rejects beta fields. See [Gateway requirements](#gateway-requirements) | | `CLAUDE_CODE_SKIP_FAST_MODE_NETWORK_ERRORS` or `CLAUDE_CODE_SKIP_FAST_MODE_ORG_CHECK` | Restores [fast mode](https://code.claude.com/docs/en/fast-mode.md) when its availability check, which calls `api.anthropic.com` directly rather than following `ANTHROPIC_BASE_URL`, fails, is intercepted, or is skipped for lack of an Anthropic credential | Your organization uses fast mode, and developers authenticate with `ANTHROPIC_AUTH_TOKEN` alone, with a gateway-issued key in `ANTHROPIC_API_KEY` or from an `apiKeyHelper`, or your network blocks or intercepts direct requests to `api.anthropic.com`; [use fast mode behind proxies and LLM gateways](https://code.claude.com/docs/en/fast-mode.md#use-fast-mode-behind-proxies-and-llm-gateways) covers which of the two variables matches your configuration | -| `ANTHROPIC_MODEL` or [`ANTHROPIC_DEFAULT_HAIKU_MODEL`](https://code.claude.com/docs/en/model-config) | Set which model name Claude Code requests for the main session and for background traffic | Your gateway routes model names that don't match Claude Code's defaults, or you route [background functionality](https://code.claude.com/docs/en/costs.md#background-token-usage) to a different model. Route both the override names and the built-in model IDs Claude Code requests when no override is set, since some background sub-calls request a built-in ID regardless of the override; [model configuration](https://code.claude.com/docs/en/model-config.md) covers which model each part of a session uses | +| `ANTHROPIC_MODEL` or [`ANTHROPIC_DEFAULT_HAIKU_MODEL`](https://code.claude.com/docs/en/model-config) | Set which model name Claude Code requests for the main session and for background traffic | Your gateway routes model names that don't match Claude Code's defaults, or you route [background functionality](https://code.claude.com/docs/en/model-config.md#environment-variables) to a different model. Route both the override names and the built-in model IDs Claude Code requests when no override is set, since some background sub-calls request a built-in ID regardless of the override | | `ANTHROPIC_BEDROCK_BASE_URL`, `ANTHROPIC_VERTEX_BASE_URL`, `ANTHROPIC_FOUNDRY_BASE_URL`, or `ANTHROPIC_AWS_BASE_URL` with the [variables for that provider](https://code.claude.com/docs/en/llm-gateway-connect.md#route-to-a-cloud-provider-through-a-gateway) | Point Claude Code at the gateway through a provider-specific base URL. Amazon Bedrock and Google Cloud's Agent Platform also switch to those providers' native request format | Your gateway fronts Amazon Bedrock, Google Cloud's Agent Platform, Microsoft Foundry, or the Claude Platform on AWS; see [API formats](https://code.claude.com/docs/en/llm-gateway-protocol.md#api-formats) | #### Distribute through managed settings diff --git a/content/en/docs/claude-code/managed-settings.md b/content/en/docs/claude-code/managed-settings.md index c940fd03d7..7fcaa53896 100644 --- a/content/en/docs/claude-code/managed-settings.md +++ b/content/en/docs/claude-code/managed-settings.md @@ -171,7 +171,9 @@ The cross-source keys include: * The sandbox binary paths `sandbox.bwrapPath` and `sandbox.socatPath` * The sandbox `ripgrep` binary, [`sandbox.ripgrep`](https://code.claude.com/docs/en/settings-reference#sandbox-ripgrep) * `sandbox.filesystem.disabled` and `sandbox.network.strictAllowlist` -* [`useAutoModeDuringPlan`](https://code.claude.com/docs/en/settings-reference#useautomodeduringplan), [`syncClaudeAiSkills`](https://code.claude.com/docs/en/settings-reference#syncclaudeaiskills), and [`syncClaudeAiPlugins`](https://code.claude.com/docs/en/settings-reference#syncclaudeaiplugins), where a `false` from any admin source turns the behavior off. A `false` in the developer's user or local settings turns it off too; each key can only deny +* [`useAutoModeDuringPlan`](https://code.claude.com/docs/en/settings-reference#useautomodeduringplan), [`syncClaudeAiSkills`](https://code.claude.com/docs/en/settings-reference#syncclaudeaiskills), and [`syncClaudeAiPlugins`](https://code.claude.com/docs/en/settings-reference#syncclaudeaiplugins), where a `false` from any admin source turns the behavior off. Each key can only deny: + * A `false` in the developer's user or local settings turns it off too + * For `useAutoModeDuringPlan`, a `false` in a user or local file the developer leaves out with an option such as [`--setting-sources`](https://code.claude.com/docs/en/cli-reference#cli-flags) doesn't count. Ignoring a left-out file requires Claude Code v2.1.314 or later * [`enableArtifact`](https://code.claude.com/docs/en/settings-reference#enableartifact), where a `false` from any admin source turns the [Artifact tool](https://code.claude.com/docs/en/artifacts.md) off. A `false` in the developer's user, project, or local settings turns it off too, and no source turns it back on; see [which lower-level values still count](https://code.claude.com/docs/en/settings.md#exceptions-to-managed-settings-precedence). Requires Claude Code v2.1.242 or later * [`maxEffortLevel`](https://code.claude.com/docs/en/settings-reference#maxeffortlevel), where the lowest cap in any admin source applies. If a developer sets a lower cap in their own settings or with `--settings`, Claude Code applies that one; no source can raise the cap. Requires Claude Code v2.1.267 or later * A commit-trailer opt-out in `attribution`, or in the deprecated `includeCoAuthoredBy`, from any tier diff --git a/content/en/docs/claude-code/mcp.md b/content/en/docs/claude-code/mcp.md index b19f5c44af..d8d27b00a3 100644 --- a/content/en/docs/claude-code/mcp.md +++ b/content/en/docs/claude-code/mcp.md @@ -952,7 +952,12 @@ Claude Code marks a remote server as needing authentication when the server resp * For a server whose `Authorization` header you configured, in `headers` or through a [`headersHelper`](#use-dynamic-headers-for-custom-authentication), a `401` or `403` while connecting doesn't flag the server, because the credential to fix is the one you configured. Claude Code reports the connection as failed instead. If you set that header from a `${VAR}` reference, check whether that variable is one Claude Code [reads as empty](#credential-variables-that-read-as-empty). * For a connector [delivered to a cloud session](#how-connectors-reach-claude-code), Claude Code doesn't run a sign-in flow, because the session's proxy authenticates to the connector with the authorization you granted in claude.ai. When a connector there needs authorizing again, reconnect it at [claude.ai/customize/connectors](https://claude.ai/customize/connectors) rather than from the session. -When an OAuth server you already signed in to rejects your stored token with `401 Unauthorized`, Claude Code refreshes the token, reconnects, and retries the request once. It flags the server in `/mcp` only if that retry also fails. In a `claude -p` or Agent SDK run on macOS, a request that Claude Code sent while it couldn't read your stored token fails with a [stored-credentials error](https://code.claude.com/docs/en/errors.md#couldnt-read-the-stored-credentials-for-mcp-server) instead. +When an OAuth server you already signed in to rejects your stored token with `401 Unauthorized`, Claude Code reconnects with or without a new token: + +* **Your stored login has a refresh token**: it refreshes the token, reconnects, and retries the request once. The server is flagged in `/mcp` only if that retry also fails. +* **Your stored login has no refresh token**: it connects once without the token. If the server answers, its tools work while you're signed out, and the rejected token is deleted. If the server rejects that connection too, `/mcp` shows that the server needs authentication. + +In a `claude -p` or Agent SDK run on macOS, a request that Claude Code sent while it couldn't read your stored token fails with a [stored-credentials error](https://code.claude.com/docs/en/errors.md#couldnt-read-the-stored-credentials-for-mcp-server). When the server rejects the stored refresh token, Claude Code immediately shows a notice pointing at `/mcp`. Open `/mcp` and select **Re-authenticate** on the server to sign in again before the next tool call fails. @@ -1640,7 +1645,7 @@ For example, these fields in a `tools/list` entry mark the `set_issue_status` to ## Respond to MCP elicitation requests -MCP servers can request structured input from you mid-task using elicitation. When a server needs information it can't get on its own, Claude Code displays an interactive dialog and passes your response back to the server. No configuration is required on your side: elicitation dialogs appear automatically when a server requests them. +MCP servers can request structured input from you mid-task using elicitation. When a server needs information it can't get on its own, Claude Code displays an interactive dialog in the terminal and passes your response back to the server. No configuration is required on your side: elicitation dialogs appear automatically when a server requests them. Servers can request input in two ways: @@ -1653,6 +1658,17 @@ To auto-respond to elicitation requests without showing a dialog, use the [`Elic If you're building an MCP server that uses elicitation, see the [MCP elicitation specification](https://modelcontextprotocol.io/docs/learn/client-concepts#elicitation) for protocol details and schema examples. +### Answer an elicitation request in a cloud session + +When Claude's task in your cloud session waits on an MCP server's request, the server needs something from you, such as a value or a sign-in. If the request appears as a card at claude.ai/code or in the Desktop app's **Code** tab, answer on the card: + +* **Form mode**: fill in the fields, then click **Submit** +* **URL mode**: click **Open link**, finish the flow it opens, then click **I’m done, continue** on the card + +To refuse the request, click **Decline**. Claude continues once the server responds. + +If you see no card in either place, you can't answer the request there. In your own session, click the stop button there to end the turn. + ### Elicitation modes Claude Code declares If you build an MCP server, the client capabilities Claude Code sends when it connects tell your server which elicitation modes it can request. Claude Code declares `elicitation: {form: {}, url: {}}` on the following connections, so a server on any of them can request both modes: @@ -1815,9 +1831,9 @@ If you deny `ToolSearch` or leave it out of [`--tools`](https://code.claude.com/ > * **You've set `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS`**: see [how it affects tool search](#configure-tool-search) > * **A request failed with an error that names `defer_loading` or `tool_reference`**: see [Extra inputs are not permitted](https://code.claude.com/docs/en/errors.md#extra-inputs-are-not-permitted) -When `ANTHROPIC_BASE_URL` points to a gateway, tool search is on by default, so requests include `defer_loading` tool fields and `tool_reference` blocks for the gateway to forward. While tool search is on, MCP tools are [deferred](#scale-with-mcp-tool-search). To load every tool upfront instead, set `ENABLE_TOOL_SEARCH=false` in your shell or your [settings `env`](https://code.claude.com/docs/en/settings-reference#env). Before v2.1.304, tool search was off behind a gateway unless `ENABLE_TOOL_SEARCH` was `true`, `auto`, or `auto:N`. +When `ANTHROPIC_BASE_URL` points to a gateway, Claude Code expects the gateway to forward `defer_loading` tool fields and `tool_reference` blocks [along with the `anthropic-beta` header](https://code.claude.com/docs/en/llm-gateway-protocol#beta-header-and-body-field-pairs). Tool search is on by default behind the gateway, so MCP tools are [deferred](#scale-with-mcp-tool-search) and requests include those fields and blocks. Before v2.1.304, tool search was off behind a gateway unless `ENABLE_TOOL_SEARCH` was `true`, `auto`, or `auto:N`. -On v2.1.305 or later, Claude Code can [retry a request without tool search](https://code.claude.com/docs/en/llm-gateway-protocol.md#retry-without-tool-search) after a `400` or `422` whose cause it doesn't recognize. When the retry works, nothing shows on screen and you don't need to do anything: MCP tools load upfront instead. Claude Code tries tool search again later, at the cost of another rejected request. To skip those requests, set `ENABLE_TOOL_SEARCH=false`. +On v2.1.305 or later, Claude Code can [retry a request without tool search](https://code.claude.com/docs/en/llm-gateway-protocol.md#retry-without-tool-search) after a `400` or `422`. When the retry works, nothing shows on screen and you don't need to do anything: MCP tools load upfront instead. Claude Code tries tool search again later, at the cost of another rejected request. #### Tools that stay deferred below the `ENABLE_TOOL_SEARCH=auto` threshold diff --git a/content/en/docs/claude-code/memory.md b/content/en/docs/claude-code/memory.md index f5362113e0..5378884dc3 100644 --- a/content/en/docs/claude-code/memory.md +++ b/content/en/docs/claude-code/memory.md @@ -206,7 +206,7 @@ paths: - Include OpenAPI documentation comments ``` -Rules without a `paths` field are loaded unconditionally and apply to all files. A path-scoped rule loads when Claude uses the Read, Write, or Edit tool on a matching file. It also loads when Claude views a matching file with a Bash command that [counts as a read](https://code.claude.com/docs/en/tools-reference.md#edit-tool-behavior), such as `cat` or `head` on a single file. Matching also works when Claude reaches a file through a symlinked path to the project directory, for example in a symlinked checkout. +A path-scoped rule loads when Claude uses the Read, Write, or Edit tool on a matching file. It also loads when Claude views a matching file with a Bash command that [counts as a read](https://code.claude.com/docs/en/tools-reference.md#edit-tool-behavior), such as `cat` or `head` on a single file. Matching also works when Claude reaches a file through a symlinked path to the project directory, for example in a symlinked checkout. Each pattern is relative to the rule's base directory: @@ -219,10 +219,11 @@ Use glob patterns in the `paths` field to match files by extension, directory, o | Pattern | Matches | | - | - | -| `**/*.ts` | All TypeScript files in any directory | -| `src/**/*` | All files under `src/` directory | -| `*.md` | Markdown files in the project root | -| `src/components/*.tsx` | React components in a specific directory | +| `**/*.ts` | `.ts` files anywhere under the base directory | +| `src/**/*` | All files under the base directory's `src/` | +| `*.md` | `.md` files anywhere under the base directory | +| `/*.md` | `.md` files directly in the base directory, not in subfolders | +| `src/components/*.tsx` | `.tsx` files directly in the base directory's `src/components/`, not in subfolders | You can specify multiple patterns and use brace expansion to match multiple extensions in one pattern: diff --git a/content/en/docs/claude-code/model-config.md b/content/en/docs/claude-code/model-config.md index 27dff0c2dd..c0c8f37b8f 100644 --- a/content/en/docs/claude-code/model-config.md +++ b/content/en/docs/claude-code/model-config.md @@ -933,7 +933,7 @@ Use the following environment variables to control the model names that the alia | `ANTHROPIC_DEFAULT_FABLE_MODEL` | The model to use for `fable`, and the model ID Claude Code recognizes as a Fable model for [automatic model fallback](#automatic-model-fallback) on third-party providers | | `ANTHROPIC_DEFAULT_OPUS_MODEL` | The model to use for `opus`, or for `opusplan` when Plan Mode is active. | | `ANTHROPIC_DEFAULT_SONNET_MODEL` | The model to use for `sonnet`, or for `opusplan` when Plan Mode is not active. | -| `ANTHROPIC_DEFAULT_HAIKU_MODEL` | The model to use for `haiku`, or [background functionality](https://code.claude.com/docs/en/costs.md#background-token-usage) | +| `ANTHROPIC_DEFAULT_HAIKU_MODEL` | The model to use for `haiku`, or background functionality | | `CLAUDE_CODE_SUBAGENT_MODEL` | The default model for [subagents](https://code.claude.com/docs/en/sub-agents.md#choose-a-model), [agent team](https://code.claude.com/docs/en/agent-teams.md#specify-teammates-and-models) teammates, and [workflow](https://code.claude.com/docs/en/workflows.md) agents that aren't assigned a model another way. Accepts an alias such as `haiku` or a full model name. A per-invocation model or a definition's `model` field, including `inherit`, takes precedence. To change that, set [`CLAUDE_CODE_SUBAGENT_MODEL_FORCE`](https://code.claude.com/docs/en/sub-agents#run-every-subagent-on-one-model) | On third-party providers, [Customize pinned model display and capabilities](#customize-pinned-model-display-and-capabilities) describes what a pinned model's row in the `/model` picker shows. diff --git a/content/en/docs/claude-code/monitoring-usage.md b/content/en/docs/claude-code/monitoring-usage.md index ea84d74878..0a3acd7c29 100644 --- a/content/en/docs/claude-code/monitoring-usage.md +++ b/content/en/docs/claude-code/monitoring-usage.md @@ -1559,7 +1559,7 @@ The `claude_code.cost.usage` metric helps with: > [!NOTE] > -> Cost metrics are approximations. For official billing data, refer to your API provider (Claude Console, Amazon Bedrock, or Google Cloud's Agent Platform). +> Cost metrics are approximations. For official billing data, see [Manage costs for your organization](https://code.claude.com/docs/en/costs.md#manage-costs-for-your-organization). Claude Code counts each streaming response toward the cost and token metrics exactly once, including when a gateway or proxy behind `ANTHROPIC_BASE_URL` streams usage progressively across multiple frames. diff --git a/content/en/docs/claude-code/network-config.md b/content/en/docs/claude-code/network-config.md index ed9fcde32a..9cd91265cf 100644 --- a/content/en/docs/claude-code/network-config.md +++ b/content/en/docs/claude-code/network-config.md @@ -131,7 +131,11 @@ In [cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web.md), Claude Code notes each ignored key in the session's debug log. -In [Claude Desktop](https://code.claude.com/docs/en/desktop.md) sessions where the app manages the provider connection, such as the Code tab on a [third-party provider](https://code.claude.com/docs/en/third-party-integrations.md) and Cowork sessions, Claude Code reads these variables and the proxy variables `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` only from [managed settings](https://code.claude.com/docs/en/managed-settings.md) and `~/.claude/settings.json`: it ignores them in a repository's own settings files, so a checked-out repository can't redirect the TLS or proxy path of a session whose credentials come from the app. In a local, SSH, or WSL Code tab session signed in through claude.ai, the app doesn't manage the connection, and Claude Code reads these variables from every settings scope, like any terminal session; [cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web.md) follow the cloud-session rules above wherever you start them. Before v2.1.217, Claude Code ignored these variables in every settings file when the app managed the connection. +In [Claude Desktop](https://code.claude.com/docs/en/desktop.md) sessions where the app manages the provider connection, such as the Code tab on a [third-party provider](https://code.claude.com/docs/en/third-party-integrations.md) and Cowork sessions, Claude Code reads these variables except `CLAUDE_CODE_OAUTH_SCOPES`, and the proxy variables `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY`, only from [managed settings](https://code.claude.com/docs/en/managed-settings.md) and `~/.claude/settings.json`. It ignores them in a repository's own settings files, so a checked-out repository can't redirect the TLS or proxy path of a session whose credentials come from the app. Before v2.1.217, Claude Code ignored these variables in every settings file when the app managed the connection. + +In a local, SSH, or WSL Code tab session signed in through claude.ai, you can set these variables and the proxy variables in any settings file, apart from `CLAUDE_CODE_OAUTH_SCOPES`. Desktop sets `CLAUDE_CODE_OAUTH_SCOPES` itself in Code tab and Cowork sessions, so you can't set it. + +When the session's launch environment already sets a variable, Claude Code [ignores the settings file's value](https://code.claude.com/docs/en/settings-reference.md#how-env-values-interact-with-your-shell) and names the variable in the [debug log](https://code.claude.com/docs/en/debug-your-config.md). To use your own proxy or certificate value in a local session, [add it to a saved local environment](https://code.claude.com/docs/en/desktop.md#set-environment-variables-for-local-sessions). [Cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web.md) follow the cloud-session rules above wherever you start them. ## Verify your configuration diff --git a/content/en/docs/claude-code/permission-modes.md b/content/en/docs/claude-code/permission-modes.md index 290cc4c094..8d9f7583f0 100644 --- a/content/en/docs/claude-code/permission-modes.md +++ b/content/en/docs/claude-code/permission-modes.md @@ -532,7 +532,7 @@ The prompt doesn't appear in non-interactive `-p` runs or background sessions; r Whatever you answer, Claude keeps working: * **Yes, and keep allowing any reads outside the working directories**: the read runs, later reads outside the working directories run as before, and Claude Code records your answer so the prompt doesn't appear again -* **No, and block reads outside the working directories from now on**: the read is refused, and Claude Code sets [`permissions.blockReadsOutsideWorkingDirectories`](https://code.claude.com/docs/en/settings-reference#permissions-blockreadsoutsideworkingdirectories) to `true` in your user settings, which makes the file tools refuse such reads in every later session and every permission mode. To let Claude read such a path later, add its directory with `/add-dir` or remove the setting. +* **No, and block reads outside the working directories from now on**: the read is refused, and Claude Code sets [`permissions.blockReadsOutsideWorkingDirectories`](https://code.claude.com/docs/en/settings-reference#permissions-blockreadsoutsideworkingdirectories) to `true` in your user settings, which makes the file tools refuse such reads in this and every later session and every permission mode. To lift the block, remove the setting from every [settings file](https://code.claude.com/docs/en/settings.md#settings-files-and-who-they-affect) that sets it, then restart each running session. For one directory this session, use `/add-dir`. * **No, and ask again next time**: the read is refused, and the next read outside the working directories prompts again * **Yes, but ask again next time**: the read runs, nothing is saved, and the next read outside the working directories prompts again diff --git a/content/en/docs/claude-code/plugins/mods/api.md b/content/en/docs/claude-code/plugins/mods/api.md index 22b0cb1bfd..172e6f2b0b 100644 --- a/content/en/docs/claude-code/plugins/mods/api.md +++ b/content/en/docs/claude-code/plugins/mods/api.md @@ -256,7 +256,7 @@ When a background job finds something that needs Claude's attention, it can star ### Stop background work -Timers stop when the module reloads. For long-running work inside a hook, [`next.signal`](https://code.claude.com/docs/en/plugins/mods/reference#the-hook-function) is an `AbortSignal` that aborts when the event your hook is handling is abandoned, for example when the user interrupts, so pass it to anything long-running. +Timers stop after the module reloads. For long-running work inside a hook, [`next.signal`](https://code.claude.com/docs/en/plugins/mods/reference#the-hook-function) is an `AbortSignal` that aborts when the event your hook is handling is abandoned, for example when the user interrupts. Pass it to anything long-running. ### Calls and background work after the user interrupts a turn diff --git a/content/en/docs/claude-code/plugins/mods/interface.md b/content/en/docs/claude-code/plugins/mods/interface.md index 0da38aa33c..b0d020fb72 100644 --- a/content/en/docs/claude-code/plugins/mods/interface.md +++ b/content/en/docs/claude-code/plugins/mods/interface.md @@ -738,7 +738,7 @@ on('session.start', async ($, e, next) => { }) ``` -Claude Code now runs your `ui.render` hook once a second. The timer stops when the module reloads, and the new instance of the module starts its own. +Claude Code now runs your `ui.render` hook once a second. The timer stops after the module reloads, and the new instance of the module starts its own. ### How often a site can redraw diff --git a/content/en/docs/claude-code/remote-control.md b/content/en/docs/claude-code/remote-control.md index 53553ac367..5c1e99432c 100644 --- a/content/en/docs/claude-code/remote-control.md +++ b/content/en/docs/claude-code/remote-control.md @@ -51,7 +51,7 @@ You can start a Remote Control session from the CLI, the [Claude Desktop app](ht > > Until you accept Remote Control's one-time confirmation, `claude remote-control` explains what it does and asks `Enable Remote Control? (y/n)` before starting the server. Answer `y` to accept and start the server. If you decline, Claude Code exits without starting the server and asks again the next time you run the command. > -> The process stays running in your terminal in server mode, waiting for remote connections. It displays a session URL you can use to [connect from another device](#connect-from-another-device), and you can press spacebar to show a QR code for quick access from your phone. While a remote session is active, the terminal shows connection status and tool activity. +> The process stays running in your terminal in server mode, waiting for remote connections. It displays a URL you can use to [connect from another device](#connect-from-another-device), and you can press spacebar to show a QR code for quick access from your phone. While a remote session is active, the terminal shows connection status and tool activity. > > Pass any of these flags after `remote-control`: > @@ -151,8 +151,8 @@ If the connection fails in an interactive session, the indicator changes to show Once a Remote Control session is active, you have a few ways to connect from another device: -* **Open the session URL** in any browser to go directly to the session on [claude.ai/code](https://claude.ai/code). -* **Scan the QR code** shown alongside the session URL to open it directly in the Claude app. With `claude remote-control`, press spacebar to toggle the QR code display. +* **Open the URL Claude Code displays** in any browser to go to [claude.ai/code](https://claude.ai/code). +* **Scan the QR code** shown alongside the URL to open it in the Claude app. With `claude remote-control`, press spacebar to toggle the QR code display. * **Open [claude.ai/code](https://claude.ai/code) or the Claude app** and find the session by name in the session list. In the Claude mobile app, tap **Code** in the navigation to reach the session list. Remote Control sessions show a computer icon with a green status dot when online. When you connect, the device shows any subagents and workflows the session already has running in the background. Stop one of them from the device, and Claude Code stops that task on your machine. diff --git a/content/en/docs/claude-code/routines.md b/content/en/docs/claude-code/routines.md index 3d80c2ba1c..94a36de1c5 100644 --- a/content/en/docs/claude-code/routines.md +++ b/content/en/docs/claude-code/routines.md @@ -105,7 +105,7 @@ Each repository is cloned at the start of a run. Claude creates `claude/`-prefix **5. Select an environment** -After you select a repository, **Cloud environment** appears below it. Pick a [cloud environment](https://code.claude.com/docs/en/cloud-environments.md) for the task. Environments control what the cloud session has access to: +After you select a repository, **Cloud environment** appears below it. Pick a [cloud environment](https://code.claude.com/docs/en/cloud-environments.md) for the task. If an environment is already selected, you can keep it or select a different one. Environments control what the cloud session has access to: * **Network access**: set the level of internet access available during each run * **Environment variables**: provide values Claude can use during each run. They're [visible to anyone who uses the environment](https://code.claude.com/docs/en/cloud-environments.md#what-carries-over-from-your-setup), so in an Anthropic-hosted environment, store keys for the APIs Claude calls during a run as [network secrets](https://code.claude.com/docs/en/cloud-environments.md#add-network-secrets) instead. That section also lists the requests that never get a secret diff --git a/content/en/docs/claude-code/sandboxing.md b/content/en/docs/claude-code/sandboxing.md index b174ee7157..7058486673 100644 --- a/content/en/docs/claude-code/sandboxing.md +++ b/content/en/docs/claude-code/sandboxing.md @@ -1074,6 +1074,7 @@ Sandboxing reduces risk but is not a complete isolation boundary. Review the lim * **Filesystem permission escalation**: overly broad filesystem write permissions can enable privilege escalation attacks. Allowing writes to directories containing executables in `$PATH`, system configuration directories, or user shell configuration files such as `.bashrc` or `.zshrc` can lead to code execution in different security contexts when other users or system processes access these files. * **Linux sandbox strength**: the Linux implementation provides strong filesystem and network isolation but includes an `enableWeakerNestedSandbox` mode that enables it to work inside Docker environments without privileged namespaces. This option considerably weakens security and should only be used when additional isolation is otherwise enforced. * **Apple Events on macOS**: the macOS sandbox blocks Apple Events by default. The `allowAppleEvents` setting lifts this restriction so tools such as `open` and `osascript` work, but it removes code-execution isolation: sandboxed commands can launch other applications unsandboxed with no user prompt, and can send AppleScript commands to running applications, subject to the per-app macOS automation-consent prompt (TCC). It is only honored from user, managed, or CLI settings. Project settings cannot enable it. +* **Mach and XPC services on macOS**: sandboxed commands can reach outside the sandbox to each service that you list in [`network.allowMachLookup`](https://code.claude.com/docs/en/settings-reference#sandbox-network-allowmachlookup), and the sandbox doesn't confine what those services do for those commands. * **User namespaces on Linux and WSL2**: by default, sandboxed commands can't create user namespaces. If you set [`allowNestedUserNamespaces`](https://code.claude.com/docs/en/settings-reference#sandbox-allownestedusernamespaces) to `true`, you turn off a security boundary: code from a sandboxed command can end up running outside the sandbox. Before you turn this setting on, read the warning in [Chromium or rootless Podman fails inside the sandbox on Linux](#chromium-or-rootless-podman-fails-inside-the-sandbox-on-linux). ### Scope diff --git a/content/en/docs/claude-code/settings-reference.md b/content/en/docs/claude-code/settings-reference.md index 84df4a7a85..802180e538 100644 --- a/content/en/docs/claude-code/settings-reference.md +++ b/content/en/docs/claude-code/settings-reference.md @@ -925,8 +925,9 @@ The three rule arrays share one syntax; see [Permission rule syntax](#permission Choose whether Claude Code uses the auto mode classifier to review shell commands in plan mode. With the default `true`, the classifier reviews each command during planning when auto mode is available and you see no prompt, except for [critical-path removals](https://code.claude.com/docs/en/permission-modes.md#critical-paths). Set `false` to get a permission prompt for every command outside the built-in read-only set. Appears in `/config` as **Use auto mode during plan**. * **Scope**: [`User, local, or managed`](#scopes). A repository can't turn it off for you. + * A `false` in any of these files or in `--settings` turns it off, unless you leave that user or local file out with an option such as [`--setting-sources`](https://code.claude.com/docs/en/cli-reference#cli-flags). Ignoring a left-out file requires Claude Code v2.1.314 or later * **Type**: Boolean - * `true`: the same as unset; when auto mode is available, the classifier reviews each shell command during planning instead of prompting you for it, except [critical-path removals](https://code.claude.com/docs/en/permission-modes.md#critical-paths). A `false` in any of these files still turns it off + * `true`: the same as unset; when auto mode is available, the classifier reviews shell commands during planning * `false`: you get a permission prompt for every command outside the built-in read-only set * **Default**: `true` @@ -1063,12 +1064,12 @@ Claude Code also writes `true` here when you choose to block such reads on [auto } ``` +To lift the block, remove the key from every settings file that sets it, then restart each running session. + Directories you add with `--add-dir`, `/add-dir`, or `additionalDirectories` in your user or managed settings count as working directories for the block. Directories added only in repository settings don't count: those in `.claude/settings.json`, and those in `.claude/settings.local.json` unless git reports that file as untracked. In a directory that isn't a git repository, or when git tracks the file, Claude Code treats `.claude/settings.local.json` as repository settings, so put directories you want to keep readable in your user settings instead. When [`autoMemoryDirectory`](#automemorydirectory) comes from the project's `.claude/settings.json`, or from a `.claude/settings.local.json` [treated as repository-supplied](https://code.claude.com/docs/en/permissions.md#when-your-local-settings-file-needs-trust), Claude Code loads no [auto memory](https://code.claude.com/docs/en/memory.md#storage-location) from that directory and saves none to it. -To lift the block, remove the key from every settings file that sets it, then start a new session. - #### Sandboxed commands under the block When [sandboxing](https://code.claude.com/docs/en/sandboxing.md) is on, the block also covers sandboxed commands. Claude Code denies them read access to your home directory and to the other roots that hold user files: `/Users`, `/home`, `/root`, `/Volumes`, `/mnt`, `/media`, `/run/media`, and `/srv`. It then re-opens the working directories, [worktrees](https://code.claude.com/docs/en/worktrees.md) Claude Code creates in the session, the session temp directory, and the parts of `~/.claude` that commands need, such as skills and plugins. While the block is in force, `allowRead` and `allowWrite` entries from repository settings don't count. @@ -2073,7 +2074,7 @@ Let sandboxed commands on macOS listen on network ports, for example to start a ### `sandbox.network.allowMachLookup` -List additional XPC and Mach service names the macOS sandbox may look up. Tools that communicate over XPC, such as the iOS Simulator or Playwright, need their services listed here. +List additional XPC and Mach service names the macOS sandbox may look up. Tools that communicate over XPC, such as the iOS Simulator or Playwright, need their services listed here. Sandboxed commands can reach outside the sandbox to each service that you list, and the sandbox [doesn't confine what those services do for those commands](https://code.claude.com/docs/en/sandboxing.md#security-limitations). * **Scope**: [`Any file`](#scopes), with [limits on project and local settings](https://code.claude.com/docs/en/sandboxing.md#repository-settings-under-an-admin-required-sandbox) * **Type**: array of strings, each a service name; a single trailing `*` matches a prefix, and `"*"` alone matches every service @@ -2422,6 +2423,7 @@ This example turns off automatic compaction and routes API requests through a pr Ignoring this group in project and local settings requires Claude Code v2.1.282 or later. * Variables that change how Claude Code starts or syncs, such as `CLAUDE_CODE_PROCESS_WRAPPER`, `CLAUDE_CODE_SYNC_SKILLS`, `CLAUDE_CODE_SYNC_PLUGINS`, `CLAUDE_CODE_PLUGIN_CACHE_DIR`, and `CLAUDE_CODE_PLUGIN_SEED_DIR`. + * Variables that set your claude.ai sign-in, such as [`CLAUDE_CODE_OAUTH_TOKEN`, `CLAUDE_CODE_OAUTH_REFRESH_TOKEN`, and `CLAUDE_CODE_OAUTH_SCOPES`](https://code.claude.com/docs/en/env-vars#variables). * The [screen reader mode](https://code.claude.com/docs/en/accessibility.md) variable `CLAUDE_AX_SCREEN_READER` and the other variables whose names start with `CLAUDE_AX_`, such as [`CLAUDE_AX_STARTUP_QUIET_MS`](https://code.claude.com/docs/en/env-vars#variables). * [`CLAUDE_CODE_USER_DIALOG_TIMEOUT_MS`](https://code.claude.com/docs/en/env-vars#variables), which sets the timer on an unanswered dialog. * [`CLAUDE_CODE_DISABLE_ATTACHMENTS`](https://code.claude.com/docs/en/env-vars#variables), which turns off attachment processing. @@ -2469,7 +2471,6 @@ Idle compaction is on by default for conversations that meet all of these condit * **Session**: you're in an interactive terminal session, in the VS Code extension's chat panel, or in the desktop app's Code tab when the session runs on your machine or over SSH * **Auto-compaction**: [`autoCompactEnabled`](#autocompactenabled) is on * **Prompt cache**: the conversation is on the [one-hour prompt cache TTL](https://code.claude.com/docs/en/prompt-caching.md#which-ttl-each-request-gets) -* **Feature flags**: Claude Code can [fetch feature flags from Anthropic](https://code.claude.com/docs/en/env-vars.md#features-that-need-feature-flag-fetching) * **Size**: the conversation's context has reached the token threshold, which you can [change](#change-the-idle-compaction-threshold) from its default of 200,000 * **Idle time**: about an hour has passed since the last request, and your computer stays awake until then @@ -2491,7 +2492,7 @@ To turn idle compaction off, set this key to `false`. To turn idle compaction off or on from inside a terminal session, run `/config` and change the **Idle compaction** row. Your choice is saved to your user settings and applies right away. The row requires Claude Code v2.1.302 or later. If you run one of those versions and `/config` doesn't show the row, check for these causes: * **Another settings source sets the key**: a value in managed settings, the `--settings` flag, or a project or local settings file overrides your user settings. Change the key in that source instead -* **Feature flags are unavailable**: where Claude Code can't [fetch feature flags from Anthropic](https://code.claude.com/docs/en/env-vars.md#features-that-need-feature-flag-fetching), idle compaction doesn't run, so there is nothing to turn off +* **Feature flags are unavailable on a version before v2.1.314**: where Claude Code can't [fetch feature flags from Anthropic](https://code.claude.com/docs/en/env-vars.md#features-that-need-feature-flag-fetching), idle compaction doesn't run, so there is nothing to turn off The key requires Claude Code v2.1.290 or later. On an earlier version, which ignores this key, turn off [`autoCompactEnabled`](#autocompactenabled) to stop idle compaction. diff --git a/content/en/docs/claude-code/settings.md b/content/en/docs/claude-code/settings.md index af0daa7bf7..2a8a665bce 100644 --- a/content/en/docs/claude-code/settings.md +++ b/content/en/docs/claude-code/settings.md @@ -184,6 +184,8 @@ Claude Code reads some keys only once, at session start, so an edit to one of th * [`model`](https://code.claude.com/docs/en/settings-reference#model): use [`/model`](https://code.claude.com/docs/en/model-config#setting-your-model) to switch mid-session. Each model has its own prompt cache, so the first request after a switch re-reads the whole conversation uncached; see [Switching models](https://code.claude.com/docs/en/prompt-caching.md#switching-models) * [`effortLevel`](https://code.claude.com/docs/en/settings-reference#effortlevel) and [`modelSettings`](https://code.claude.com/docs/en/settings-reference#modelsettings): use [`/effort`](https://code.claude.com/docs/en/model-config#adjust-effort-level) to change effort mid-session +If you remove [`permissions.blockReadsOutsideWorkingDirectories`](https://code.claude.com/docs/en/settings-reference#permissions-blockreadsoutsideworkingdirectories) mid-session, the file tools keep the block in the running session. To lift it, remove the key from every settings file that sets it, then restart each running session. + ### Confirm what loaded Run `/status` inside Claude Code to see which settings sources are active. The **Status** tab includes a `Setting sources` line that lists each settings file Claude Code loaded for the current session, such as `User settings` or `Project local settings`. When [managed settings](https://code.claude.com/docs/en/admin-setup.md#decide-how-settings-reach-devices) are in effect, the managed settings entry shows in parentheses how they reached your machine. @@ -311,7 +313,7 @@ For a few keys whose values restrict a session, Claude Code honors a restrictive | [`autoMode.classifyAllShell`](https://code.claude.com/docs/en/settings-reference#automode-classifyallshell) | `true` from `~/.claude/settings.json` or `--settings` | Honored even when a managed source sets `false` | | [`remoteControlAtStartup`](https://code.claude.com/docs/en/settings-reference#remotecontrolatstartup) | `false` from `.claude/settings.json` or `.claude/settings.local.json` | Honored even when a managed source sets `true`; a project or local `true` is ignored | | [`crossSessionInbound`](https://code.claude.com/docs/en/settings-reference#crosssessioninbound) | A stricter value from `.claude/settings.json` or `.claude/settings.local.json`, on the `accept` \< `hold` \< `refuse` ladder | Honored over managed, `--settings`, and user values; a project or local value that isn't stricter is ignored | -| [`useAutoModeDuringPlan`](https://code.claude.com/docs/en/settings-reference#useautomodeduringplan) | `false` from any managed source, `--settings`, `~/.claude/settings.json`, or `.claude/settings.local.json` | Honored even when the winning managed source sets `true`; a `false` in `.claude/settings.json` is ignored | +| [`useAutoModeDuringPlan`](https://code.claude.com/docs/en/settings-reference#useautomodeduringplan) | `false` from any managed source, `--settings`, `~/.claude/settings.json`, or `.claude/settings.local.json` | Honored even when the winning managed source sets `true`; a `false` in `.claude/settings.json` is ignored. See [the key's entry](https://code.claude.com/docs/en/settings-reference.md#useautomodeduringplan) for a file you leave out at launch | | [`syncClaudeAiSkills`](https://code.claude.com/docs/en/settings-reference#syncclaudeaiskills) | `false` from any managed source, `--settings`, `~/.claude/settings.json`, or `.claude/settings.local.json` | Honored even when the winning managed source sets `true`; a `false` in `.claude/settings.json` is ignored | | [`syncClaudeAiPlugins`](https://code.claude.com/docs/en/settings-reference#syncclaudeaiplugins) | `false` from any managed source, `--settings`, `~/.claude/settings.json`, or `.claude/settings.local.json` | Honored even when the winning managed source sets `true`; a `false` in `.claude/settings.json` is ignored | | [`maxEffortLevel`](https://code.claude.com/docs/en/settings-reference#maxeffortlevel) | A lower cap from any scope, including `--settings` | Honored even when the managed settings Claude Code applies set a higher cap; the lowest cap applies. Requires Claude Code v2.1.267 or later | diff --git a/content/en/docs/claude-code/sub-agents.md b/content/en/docs/claude-code/sub-agents.md index b9d3636516..e59564132f 100644 --- a/content/en/docs/claude-code/sub-agents.md +++ b/content/en/docs/claude-code/sub-agents.md @@ -1048,7 +1048,7 @@ Use **subagents** when: Consider [Skills](https://code.claude.com/docs/en/skills.md) instead when you want reusable prompts or workflows that run in the main conversation context rather than isolated subagent context. -For a question about something already in your conversation, use [`/btw`](https://code.claude.com/docs/en/interactive-mode#side-questions-with-%2Fbtw) instead of a subagent. It sees your full context but has no tool access, and the answer isn't added to history. +For a question about something already in your conversation, use [`/btw`](https://code.claude.com/docs/en/interactive-mode#side-questions-with-%2Fbtw) instead of a subagent. It has no tool access, and the answer isn't added to history. ### Let subagents spawn their own subagents @@ -1242,7 +1242,7 @@ Use these keys to interact with the panel: | `x` | Stop the selected fork if it's running, or dismiss its row if it's no longer running. On the main session row, or on the row of the fork whose transcript you opened with `Enter`, `x` types into the prompt instead | | `Esc` | Return focus to the prompt input | -With a fork's or subagent's transcript open, follow-up messages and [skills](https://code.claude.com/docs/en/skills.md) go to that agent, and built-in commands go to your main conversation, with these safeguards: +With a fork's or subagent's transcript open, follow-up messages and [skills](https://code.claude.com/docs/en/skills.md) go to that agent. On Claude Code v2.1.314 or later, [`/btw`](https://code.claude.com/docs/en/interactive-mode#ask-btw-about-a-subagent) answers from the open transcript. Other built-in commands go to your main conversation, with these safeguards: * `/compact`, `/clear`, and `/rewind` act on the main conversation, so Claude Code asks you to confirm before running one of them from this view. * `/model` and `/fast` set the main conversation's model and fast mode, not the viewed agent's, so they don't run from this view. A notice tells you why. diff --git a/content/en/docs/claude-code/tools-reference.md b/content/en/docs/claude-code/tools-reference.md index 24fed7b927..e41a7f5812 100644 --- a/content/en/docs/claude-code/tools-reference.md +++ b/content/en/docs/claude-code/tools-reference.md @@ -303,7 +303,7 @@ The tool appears only when all of the following are true: The EnterWorktree tool creates an isolated [git worktree](https://code.claude.com/docs/en/worktrees.md) and switches into it. Given a `path`, it switches into an existing worktree instead of creating a new one. -* **Which worktrees `path` can name**: on first entry the target may be a worktree of the current repository. In a repository that holds other repositories, it may also be a worktree of a repository nested inside it. Before v2.1.203, a nested repository's worktree was rejected. +* **Which worktrees `path` can name**: on first entry the target may be a worktree of the current repository. In a repository that holds other repositories, it may also be a worktree of a repository nested inside it. * **When you're prompted**: a `path` outside `.claude/worktrees/` prompts for your approval before entering, since it moves the session's working directory and write access to that location. New-worktree creation and paths under `.claude/worktrees/` don't prompt. Before v2.1.206, Claude entered paths outside `.claude/worktrees/` without a prompt. * **From inside a worktree**: from within a worktree session, only the `path` form is available and the target must be under `.claude/worktrees/` of the session's repository. The same holds for a subagent with a pinned working directory, such as [`isolation: worktree`](https://code.claude.com/docs/en/sub-agents#supported-frontmatter-fields). * **When the tool is missing**: once [`permissions.blockWritesOutsideWorkingDirectories`](https://code.claude.com/docs/en/settings-reference#permissions-blockwritesoutsideworkingdirectories) is on, Claude Code removes `EnterWorktree` and `ExitWorktree` or refuses calls to them. To keep working in worktrees, see [Claude has no `EnterWorktree` tool](https://code.claude.com/docs/en/worktrees#claude-has-no-enterworktree-tool). diff --git a/content/en/docs/claude-code/web-scheduled-tasks.md b/content/en/docs/claude-code/web-scheduled-tasks.md index 3d80c2ba1c..94a36de1c5 100644 --- a/content/en/docs/claude-code/web-scheduled-tasks.md +++ b/content/en/docs/claude-code/web-scheduled-tasks.md @@ -105,7 +105,7 @@ Each repository is cloned at the start of a run. Claude creates `claude/`-prefix **5. Select an environment** -After you select a repository, **Cloud environment** appears below it. Pick a [cloud environment](https://code.claude.com/docs/en/cloud-environments.md) for the task. Environments control what the cloud session has access to: +After you select a repository, **Cloud environment** appears below it. Pick a [cloud environment](https://code.claude.com/docs/en/cloud-environments.md) for the task. If an environment is already selected, you can keep it or select a different one. Environments control what the cloud session has access to: * **Network access**: set the level of internet access available during each run * **Environment variables**: provide values Claude can use during each run. They're [visible to anyone who uses the environment](https://code.claude.com/docs/en/cloud-environments.md#what-carries-over-from-your-setup), so in an Anthropic-hosted environment, store keys for the APIs Claude calls during a run as [network secrets](https://code.claude.com/docs/en/cloud-environments.md#add-network-secrets) instead. That section also lists the requests that never get a secret diff --git a/content/en/manage-claude/cmek-coverage-claude-enterprise.md b/content/en/manage-claude/cmek-coverage-claude-enterprise.md index 268b16a610..bf40f90b3e 100644 --- a/content/en/manage-claude/cmek-coverage-claude-enterprise.md +++ b/content/en/manage-claude/cmek-coverage-claude-enterprise.md @@ -37,7 +37,7 @@ This list is not exhaustive. Review it with your team before you set up CMEK. | [Skill and plugin security scanning](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/enterprise#skill-content-scanning) | Off. The setting can’t be turned on, and skills and plugins are installed without a scan. | | Claude in Slack (beta) | Off. Claude declines requests, even if an admin turns the product on. | | Analytics: smart reports and contribution metrics | Off. Certain analytics are disabled, regardless of admin settings: Claude smart reports (under claude.ai/analytics/insights) and Claude Code contribution metrics from GitHub (beta, under claude.ai/analytics/claude-code). | -| Claude Security (beta) and routines (research preview) | Off. Beta and research preview features, turned off regardless of admin settings. | +| Claude Security (beta) and cloud scheduled tasks, formerly routines (research preview) | Off. Beta and research preview features, turned off regardless of admin settings. | | Standalone Claude Design app (being deprecated) | Not supported. See [Encrypted with Anthropic’s key](https://platform.claude.com/docs/en/manage-claude/cmek-coverage-claude-enterprise#encrypted-with-anthropics-key). | ## Encrypted with Anthropic’s key diff --git a/content/en/manage-claude/compliance-content-data.md b/content/en/manage-claude/compliance-content-data.md index cdb5af1d73..d768009602 100644 --- a/content/en/manage-claude/compliance-content-data.md +++ b/content/en/manage-claude/compliance-content-data.md @@ -146,6 +146,13 @@ The messages endpoint returns the chat’s metadata plus a `chat_messages` array "mime_type": "text/csv", "size_bytes": 2048, "md5": "89968669461d95416549937168269d6b" + }, + { + "id": "claude_file_01Qm7RzKdTgWnYbVx3HcLpE5", + "filename": "requirements_tracker.xlsx", + "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "size_bytes": 18432, + "md5": "5ccf4e7dd3bdfa729883d6764631ac60" } ], "artifacts": [ @@ -164,13 +171,13 @@ The messages endpoint returns the chat’s metadata plus a `chat_messages` array } ``` -`files`, `generated_files`, and `artifacts` can each be `null` on a given message. `files` are the files and text attachments (for example, PDFs, images, spreadsheets, documents, and pasted text) the user attached to the message, as claude.ai stored them. `generated_files` are binary files the assistant created during the conversation through tool use (for example, PDFs, spreadsheets, or slide decks). `artifacts` are versioned documents (for example, code or markdown) the assistant generated or updated in its response; an artifact can be revised across multiple assistant turns in the same chat, and each revision appears as a new `version_id` under the same artifact `id`. Pass each entry’s `id` (or `version_id` for artifacts) to the matching content endpoint in [Retrieve files and artifacts](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-files-and-artifacts) to download it. +`files`, `generated_files`, and `artifacts` can each be `null` on a given message. `files` are the files and text attachments (for example, PDFs, images, spreadsheets, documents, and pasted text) the user attached to the message, as claude.ai stored them. `generated_files` are binary files the assistant created during the conversation through tool use (for example, PDFs, spreadsheets, or slide decks). `artifacts` are versioned documents (for example, code or markdown) the assistant generated or updated in its response; an artifact can be revised across multiple assistant turns in the same chat, and each revision appears as a new `version_id` under the same artifact `id`. Pass each entry’s `id` (or `version_id` for artifacts) to the matching content endpoint in [Retrieve files and artifacts](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-files-and-artifacts) to download it. An `id` in `generated_files` starts with either `claude_gen_file_` or `claude_file_`. Choose the endpoint by the prefix, not by the array the entry came from. ## Retrieve files and artifacts -Files and artifacts are downloaded by ID. Except for Claude Docs documents (see the end of this section), they aren’t listed independently. The IDs come from the chat messages endpoint in [Retrieve chats and messages](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-chats-and-messages) (the `files`, `generated_files`, and `artifacts` arrays on each message) or, for project-level uploads, from the [project attachments endpoint](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-projects-and-attachments). +Files and artifacts are downloaded by ID. They aren’t listed independently, except for the artifacts returned by [List code artifacts](https://platform.claude.com/docs/en/api/compliance/apps/code/artifacts/list), such as Claude Docs documents (see the end of this section). All other IDs come from the chat messages endpoint in [Retrieve chats and messages](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-chats-and-messages) (the `files`, `generated_files`, and `artifacts` arrays on each message) or, for project-level uploads, from the [project attachments endpoint](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-projects-and-attachments). -Pick the endpoint that matches your ID type and the data you need. The same file content endpoint serves both chat files and project files. +Pick the endpoint that matches your ID’s prefix and the data you need. The same file content endpoint serves chat files, project files, and the `generated_files` entries whose IDs start with `claude_file_`. The file endpoints and the generated-file endpoints each reject the other’s IDs with a 400 error; see [Invalid file ID](https://platform.claude.com/docs/en/manage-claude/compliance-errors#invalid-file-id). | You have | You want | Use this endpoint | | ------------------------------ | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | @@ -187,7 +194,7 @@ The file content endpoint streams the content that claude.ai stored for the file The response carries these headers: -* `Content-Disposition: attachment; filename*=utf-8''` carries the original upload file name in RFC 5987 extended form. The extended form is used for every file name, not only non-ASCII ones. +* `Content-Disposition: attachment; filename*=utf-8''` carries the file name in RFC 5987 extended form. The extended form is used for every file name, not only non-ASCII ones. * `Content-Type` carries the MIME type recorded for the stored content, which for a document stored as extracted text can still name the original document format. * `Content-MD5` carries the MD5 digest of the served bytes, base64-encoded as specified in RFC 1864. * `Transfer-Encoding: chunked` is always set. @@ -200,7 +207,7 @@ curl --fail-with-body -sS \ --output "dashboard_mockup_v1.pdf" ``` -In curl, the `--remote-header-name` (`-J`) option, which normally saves a download under the `Content-Disposition` file name, does not read the `filename*` form, so name the saved file yourself with `--output`. In a script, take the name from the file’s `filename` field in the chat messages or [Get file metadata](https://platform.claude.com/docs/en/api/compliance/apps/chats/files/retrieve) response, or decode `filename*`. Either way, it is the name the user gave the upload, so treat it as untrusted before using it as an output path: +In curl, the `--remote-header-name` (`-J`) option, which normally saves a download under the `Content-Disposition` file name, does not read the `filename*` form, so name the saved file yourself with `--output`. In a script, take the name from the file’s `filename` field in the chat messages or [Get file metadata](https://platform.claude.com/docs/en/api/compliance/apps/chats/files/retrieve) response, or decode `filename*`. Either way, treat it as untrusted before using it as an output path: * Keep only the base name. * Allow only characters that are safe on your filesystem. diff --git a/content/en/manage-claude/compliance-errors.md b/content/en/manage-claude/compliance-errors.md index 387eca5162..661390db22 100644 --- a/content/en/manage-claude/compliance-errors.md +++ b/content/en/manage-claude/compliance-errors.md @@ -132,6 +132,22 @@ The page cursor has expired. Restart the walk without a page parameter; results For the first body, resend the unmodified `next_page` value from the previous response to the endpoint and session that issued it. For an expired cursor, restart without a `page` parameter; the new walk reflects the retention boundary in effect when it starts, so messages that aged out of the retention period in the meantime are no longer returned (see [Retrieve a local session transcript](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-a-local-session-transcript)). +### Invalid file ID + +**Type:** `invalid_request_error` + +```text wrap +Invalid claude_gen_file_id format: 'claude_file_01Qm7RzKdTgWnYbVx3HcLpE5' +``` + +```text wrap +Invalid claude_file_id format: 'claude_gen_file_01TbR8wAcCeFhJkLnPqStUvX' +``` + +**Cause:** The ID in the path is not in the form the endpoint accepts. The generated-file endpoints (`/v1/compliance/apps/chats/generated-files/*`) accept only `claude_gen_file_...` IDs and return the first body for any other value. The file endpoints (`/v1/compliance/apps/chats/files/*`) accept only `claude_file_...` IDs and return the second body. The `generated_files` array on a chat message can hold both kinds of ID. + +**Fix:** Choose the endpoint by the ID’s prefix, not by the array the ID came from; see [Retrieve files and artifacts](https://platform.claude.com/docs/en/manage-claude/compliance-content-data#retrieve-files-and-artifacts). If the prefix already matches the endpoint, the ID was truncated or altered; copy it again from the response that returned it. + ### Transcript page too large **Type:** `invalid_request_error` diff --git a/content/en/manage-claude/compliance-faq.md b/content/en/manage-claude/compliance-faq.md index 248dcdae7a..23fee85b4e 100644 --- a/content/en/manage-claude/compliance-faq.md +++ b/content/en/manage-claude/compliance-faq.md @@ -72,7 +72,7 @@ description: Answers to common questions about Compliance API access, scopes, re Yes. Cowork sessions in Claude Desktop that run on users’ machines, Claude Code sessions (in the terminal, in Claude Desktop, or in an IDE extension), sessions in the Claude Science desktop app, Claude for Microsoft 365 sessions (in Excel, PowerPoint, Word, and Outlook), sessions in the Claude add-ins for Google Docs, Google Sheets, and Google Slides, and chats in the Claude in Chrome browser extension are captured while users are signed in with their Claude Enterprise account and are available through the [local session endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-local-sessions). Cowork sessions started on claude.ai web or mobile, which run in the cloud in Anthropic-managed environments, are available through the [remote session endpoints](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions). Each family has a list endpoint that returns session metadata and a messages endpoint that returns the session transcript (user prompts, assistant responses, and tool calls and results). The local family adds a third endpoint that retrieves one session’s metadata. All of these endpoints use your existing Compliance Access Key with `read:compliance_user_data`; no new key or scope is needed. - Local sessions are captured as their requests reach the Claude API, so nothing is installed on the device, and on-device activity that never reaches the API is not captured. Claude Code sessions authenticated with a Claude Console API key, Claude Code sessions run through a third-party cloud platform (Amazon Bedrock, Google Cloud, or Microsoft Foundry), and [Claude Code cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web), which run on cloud infrastructure instead of the user’s machine, are not captured. These cloud sessions are not remote sessions, even though both run in the cloud; the remote session endpoints return Cowork sessions only. Each run of a Cowork scheduled task in the cloud is a remote session: the remote session list endpoint returns it as an [agent-owned session](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions) (`agent_id` is set, and `started_by_user` identifies the human who initiated the run), and the messages endpoint returns its transcript, but neither returns the task’s name or schedule. Claude Code routines that run in the cloud are Claude Code cloud sessions, so the session endpoints do not return them. Organizations with [HIPAA readiness](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#hipaa-readiness) enabled get local session data for Cowork and Claude Code only, stored for 30 days, and sessions for which [zero data retention (ZDR)](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#zero-data-retention-zdr-scope) is in effect are excluded. + Local sessions are captured as their requests reach the Claude API, so nothing is installed on the device, and on-device activity that never reaches the API is not captured. Claude Code sessions authenticated with a Claude Console API key, Claude Code sessions run through a third-party cloud platform (Amazon Bedrock, Google Cloud, or Microsoft Foundry), and [Claude Code cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web), which run on cloud infrastructure instead of the user’s machine, are not captured. These cloud sessions are not remote sessions, even though both run in the cloud; the remote session endpoints return Cowork sessions only. Each run of a Cowork scheduled task in the cloud is a remote session: the remote session list endpoint returns it as an [agent-owned session](https://platform.claude.com/docs/en/manage-claude/compliance-sessions#retrieve-remote-sessions) (`agent_id` is set, and `started_by_user` identifies the human who initiated the run), and the messages endpoint returns its transcript, but neither returns the task’s name or schedule. Each run of a Claude Code cloud scheduled task (formerly a routine) is a Claude Code cloud session, so the session endpoints do not return it. Organizations with [HIPAA readiness](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#hipaa-readiness) enabled get local session data for Cowork and Claude Code only, stored for 30 days, and sessions for which [zero data retention (ZDR)](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#zero-data-retention-zdr-scope) is in effect are excluded. The local and remote session endpoints are stable for Cowork, Claude Code, and Claude for Microsoft 365 sessions. Coverage of sessions in Claude Science, the Claude add-ins for Google Docs, Google Sheets, and Google Slides, and Claude in Chrome is in beta. @@ -109,9 +109,9 @@ description: Answers to common questions about Compliance API access, scopes, re The Compliance API has known coverage boundaries: the Activity Feed records resource events but not prompt or response text, Claude Console and Claude API workloads authenticated with an API key expose no message content at all, and content removed by your retention policy, deleted by a user in claude.ai, or hard-deleted through the Compliance API is not recoverable. For the full coverage boundaries and delivery contract, see [Delivery guarantees and completeness](https://platform.claude.com/docs/en/manage-claude/compliance-integration-patterns#delivery-guarantees-and-completeness). - Session transcripts have boundaries of their own. Local sessions are captured only as their requests reach the Claude API, so on-device activity that never reaches the API is not captured. Claude Code sessions authenticated with a Claude Console API key, Claude Code sessions run through a third-party cloud platform (Amazon Bedrock, Google Cloud, or Microsoft Foundry), and [Claude Code cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web) (including Claude Code routines that run in the cloud), which run on cloud infrastructure instead of the user’s machine, are not captured either; organizations with HIPAA readiness enabled get local session data for Cowork and Claude Code only, stored for 30 days; and sessions for which zero data retention is in effect are excluded. No session transcript, local or remote, includes thinking blocks or tool definitions. Organizations that use [customer-managed encryption keys](https://platform.claude.com/docs/en/manage-claude/cmek) receive local session transcripts as usual. While the key cannot be used, the messages endpoint returns [503 Service Unavailable](https://platform.claude.com/docs/en/manage-claude/compliance-errors#local-sessions-temporarily-unavailable) instead of transcript content, and session metadata is still listed. + Session transcripts have boundaries of their own. Local sessions are captured only as their requests reach the Claude API, so on-device activity that never reaches the API is not captured. Claude Code sessions authenticated with a Claude Console API key, Claude Code sessions run through a third-party cloud platform (Amazon Bedrock, Google Cloud, or Microsoft Foundry), and [Claude Code cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web) (including Claude Code cloud scheduled tasks, formerly routines), which run on cloud infrastructure instead of the user’s machine, are not captured either; organizations with HIPAA readiness enabled get local session data for Cowork and Claude Code only, stored for 30 days; and sessions for which zero data retention is in effect are excluded. No session transcript, local or remote, includes thinking blocks or tool definitions. Organizations that use [customer-managed encryption keys](https://platform.claude.com/docs/en/manage-claude/cmek) receive local session transcripts as usual. While the key cannot be used, the messages endpoint returns [503 Service Unavailable](https://platform.claude.com/docs/en/manage-claude/compliance-errors#local-sessions-temporarily-unavailable) instead of transcript content, and session metadata is still listed. - No Compliance API endpoint lists an organization’s Cowork scheduled tasks or Claude Code routines. + No Compliance API endpoint lists an organization’s Cowork scheduled tasks or Claude Code cloud scheduled tasks. diff --git a/content/en/manage-claude/compliance-sessions.md b/content/en/manage-claude/compliance-sessions.md index f7f2e24d1a..3d50759a1a 100644 --- a/content/en/manage-claude/compliance-sessions.md +++ b/content/en/manage-claude/compliance-sessions.md @@ -35,7 +35,7 @@ The following table maps each product, and where it runs, to the endpoint family Capture of local sessions is tied to the Compliance API being enabled for your organization and applies while users are signed in with their Claude Enterprise account. The session endpoints do not return the following: * Claude Code sessions authenticated with a Claude Console API key, or run through a third-party cloud platform such as Amazon Bedrock, Google Cloud, or Microsoft Foundry. -* [Claude Code cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web) (including Claude Code routines that run in the cloud), which run on cloud infrastructure instead of the user’s machine. These cloud sessions are not remote sessions, even though both run in the cloud; the remote session endpoints return Cowork sessions only. +* [Claude Code cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web) (including Claude Code cloud scheduled tasks, formerly routines), which run on cloud infrastructure instead of the user’s machine. These cloud sessions are not remote sessions, even though both run in the cloud; the remote session endpoints return Cowork sessions only. * Local sessions from products other than Cowork and Claude Code in organizations with [HIPAA readiness](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#hipaa-readiness) enabled. In those organizations, the local session endpoints return Cowork and Claude Code sessions only, and captured session content is stored for 30 days. * Local sessions for which [zero data retention (ZDR)](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#zero-data-retention-zdr-scope) is in effect. These sessions are excluded from list results, and the retrieve and messages endpoints return 404 for them. diff --git a/content/en/manage-claude/inference-hooks-configuration.md b/content/en/manage-claude/inference-hooks-configuration.md index cd96422e7b..4fe8fa132f 100644 --- a/content/en/manage-claude/inference-hooks-configuration.md +++ b/content/en/manage-claude/inference-hooks-configuration.md @@ -123,7 +123,7 @@ While **Only selected roles** is set: * If no member set to **Custom roles** is assigned a selected role, no member is inspected. * Requests with no member behind them are not inspected, such as requests made with API keys, and Claude Tag conversations in Slack. -The switch and changes to the inspected roles are recorded in your organization’s [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed). +Changes to **Inspect** and to the inspected roles are recorded in your organization’s [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed). ## Custom blocked prompt message diff --git a/content/en/managed-agents/events-and-streaming.md b/content/en/managed-agents/events-and-streaming.md index 3dbdf9933f..e08711c3a9 100644 --- a/content/en/managed-agents/events-and-streaming.md +++ b/content/en/managed-agents/events-and-streaming.md @@ -223,12 +223,7 @@ Stream events from the session to receive real-time updates as the agent works. break events; } case SESSION_ERROR -> { - // The `message` field spans all error variants; read it from the raw JSON. - var errorMessage = - event.asSessionError().error()._json().orElse(null) instanceof JsonObject json - ? json.values().get("message").asStringOrThrow() - : "unknown"; - IO.println("\n[Error: " + errorMessage + "]"); + IO.println("\n[Error: " + event.asSessionError().error().message() + "]"); break events; } } @@ -449,18 +444,14 @@ To reconnect to an existing session without missing events, combine a new stream ```java Java try (var stream = client.beta().sessions().events().streamStreaming(session.id())) { // Stream is open and buffering. List history before tailing live. - // Every event variant carries `id`; read it from the raw JSON to dedup across variants. var seenEventIds = new HashSet(); for (var pastEvent : client.beta().sessions().events().list(session.id()).autoPager()) { - if (pastEvent._json().orElseThrow() instanceof JsonObject json) { - seenEventIds.add(json.values().get("id").asStringOrThrow()); - } + seenEventIds.add(pastEvent.id()); } // Tail live events; Set.add returns false for already-seen IDs, skipping the replay. stream.stream() - .filter(event -> event._json().orElseThrow() instanceof JsonObject json - && seenEventIds.add(json.values().get("id").asStringOrThrow())) + .filter(event -> event.id().map(seenEventIds::add).orElse(true)) .takeWhile(event -> !event.isSessionStatusIdle()) .filter(BetaManagedAgentsStreamSessionEvents::isAgentMessage) .forEach(event -> event.asAgentMessage().content() @@ -1481,7 +1472,7 @@ Retrieve the full event history for a session: var events = await client.Beta.Sessions.Events.List(session.ID); foreach (var sessionEvent in events.Items) { - Console.WriteLine($"[{sessionEvent.Json.GetProperty("type").GetString()}] {sessionEvent.ProcessedAt}"); + Console.WriteLine($"[{sessionEvent.Type.Raw()}] {sessionEvent.ProcessedAt}"); } ``` @@ -1498,10 +1489,7 @@ Retrieve the full event history for a session: ```java Java var events = client.beta().sessions().events().list(session.id()); for (var event : events.data()) { - var eventJson = event._json().orElseThrow().convert(JsonNode.class); - var processedAt = eventJson.path("processed_at"); - IO.println("[" + eventJson.get("type").asText() + "] " - + (processedAt.isTextual() ? processedAt.asText() : "null")); + IO.println("[" + event.type().asString() + "] " + event.processedAt().orElse(null)); } ``` @@ -1560,7 +1548,7 @@ Pass a `types` (curl: `types[]`; cli: `--type`; csharp, go: `Types`) filter to r }); foreach (var sessionEvent in events.Items) { - Console.WriteLine($"[{sessionEvent.Json.GetProperty("type").GetString()}] {sessionEvent.ProcessedAt}"); + Console.WriteLine($"[{sessionEvent.Type.Raw()}] {sessionEvent.ProcessedAt}"); } ``` diff --git a/content/en/managed-agents/scheduled-deployments.md b/content/en/managed-agents/scheduled-deployments.md index 4f67ab4a0b..34d5b0ac07 100644 --- a/content/en/managed-agents/scheduled-deployments.md +++ b/content/en/managed-agents/scheduled-deployments.md @@ -452,9 +452,7 @@ List all deployment runs for a deployment as follows: ); await foreach (var run in runs.Paginate()) { - // The Error union exposes .Message directly; the discriminator is read - // from .Json until a common .Type accessor is added. - var outcome = run.SessionID ?? run.Error!.Json.GetProperty("type").GetString(); + var outcome = run.SessionID ?? run.Error!.Type.Raw(); Console.WriteLine($"{run.CreatedAt} {outcome}"); } ``` @@ -481,10 +479,8 @@ List all deployment runs for a deployment as follows: DeploymentRunListParams.builder() .deploymentId(deployment.id()) .build()).autoPager()) { - // The Error union does not yet expose common .type()/.message() - // accessors; .toString() includes both. IO.println(run.createdAt() + " " - + run.sessionId().orElseGet(() -> run.error().orElseThrow().toString())); + + run.sessionId().orElseGet(() -> run.error().orElseThrow().type().asString())); } ``` @@ -544,7 +540,7 @@ You can additionally filter on deployment runs with errors: await foreach (var failedRun in failedRuns.Paginate()) { var error = failedRun.Error!; - var errorType = error.Json.GetProperty("type").GetString(); + var errorType = error.Type.Raw(); Console.WriteLine($"{failedRun.CreatedAt} {errorType} {error.Message}"); } ``` @@ -569,7 +565,8 @@ You can additionally filter on deployment runs with errors: .deploymentId(deployment.id()) .hasError(true) .build()).autoPager()) { - IO.println(run.createdAt() + " " + run.error().orElseThrow()); + var error = run.error().orElseThrow(); + IO.println(run.createdAt() + " " + error.type().asString() + " " + error.message()); } ``` diff --git a/content/en/managed-agents/session-threads.md b/content/en/managed-agents/session-threads.md index b508801ed5..d5d721cf53 100644 --- a/content/en/managed-agents/session-threads.md +++ b/content/en/managed-agents/session-threads.md @@ -79,7 +79,7 @@ List all threads associated with a session as follows: ```csharp C# await foreach (var sessionThread in (await client.Beta.Sessions.Threads.List(session.ID)).Paginate()) { - var label = sessionThread.Agent.Name ?? sessionThread.Agent.Json.GetProperty("type").GetString(); + var label = sessionThread.Agent.Name ?? sessionThread.Agent.Type.Raw(); Console.WriteLine($"[{label}] {sessionThread.Status.Raw()}"); } ``` @@ -616,7 +616,7 @@ A thread’s stream doesn’t replay earlier events. Right after `session.thread var page = await client.Beta.Sessions.Threads.Events.List(thread.ID, new() { SessionID = session.ID }); await foreach (var evt in page.Paginate()) { - Console.WriteLine($"[{evt.Json.GetProperty("type").GetString()}] {evt.ProcessedAt}"); + Console.WriteLine($"[{evt.Type.Raw()}] {evt.ProcessedAt}"); } ``` @@ -640,11 +640,8 @@ A thread’s stream doesn’t replay earlier events. Right after `session.thread .sessionId(session.id()) .build() ).autoPager()) { - var type = event._json().orElseThrow() instanceof JsonObject json - ? json.values().get("type").asStringOrThrow() - : "unknown"; var processedAt = event.processedAt().map(OffsetDateTime::toString).orElse("pending"); - IO.println("[" + type + "] " + processedAt); + IO.println("[" + event.type().asString() + "] " + processedAt); } ``` diff --git a/content/en/managed-agents/workflow-runs.md b/content/en/managed-agents/workflow-runs.md index 86073fad87..884e6e86d3 100644 --- a/content/en/managed-agents/workflow-runs.md +++ b/content/en/managed-agents/workflow-runs.md @@ -441,7 +441,7 @@ This sample follows a session from your message to the agent’s answer. It open // On any other stop reason, print it and stop. if (!finished && idle.StopReason?.Value is not BetaManagedAgentsSessionRequiresAction) { - var reason = idle.StopReason?.Json.GetProperty("type").GetString(); + var reason = idle.StopReason?.Type.Raw(); Console.WriteLine($"Session idle: {reason}"); break; } diff --git a/content/en/models/haiku-5-5/migration-guide.md b/content/en/models/haiku-5-5/migration-guide.md index f1bdd4b5d6..26685bf0e3 100644 --- a/content/en/models/haiku-5-5/migration-guide.md +++ b/content/en/models/haiku-5-5/migration-guide.md @@ -28,7 +28,7 @@ Work down the groups and stop after the one that names your current model. If yo 4. If your code reads the first content block as the answer, select blocks by `type` instead. See [Configure thinking](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#configure-thinking). 5. Remove `temperature`, `top_p`, and `top_k` from your requests. See [Remove sampling parameters](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#remove-sampling-parameters). 6. If your requests end `messages` with an assistant turn for the model to continue, end them with a user turn instead. See [Replace assistant prefill](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#replace-assistant-prefill). -7. If you use computer use, replace `computer_20250124`: on the Claude API and Claude Models on Google Cloud (Google managed), with the `computer_toolset_20260801` toolset; on Amazon Bedrock, with `computer_20251124` and the `computer-use-2025-11-24` beta header. See [Move computer use to the toolset](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#computer-use-toolset). +7. If you use computer use, replace `computer_20250124` with the `computer_toolset_20260801` toolset. On Amazon Bedrock, `computer_20251124` also works. See [Move computer use to the toolset](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#computer-use-toolset). 8. If you replay stored conversations through a different account, replay each one through the account that produced it. See [Replay thinking blocks through the account that produced them](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#replay-thinking-blocks-through-the-producing-account). 9. If your code changes `system`, `tools`, or earlier `messages` between requests in a conversation and sends thinking blocks back, keep the conversation append-only. See [Keep earlier turns unchanged](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#keep-earlier-turns-unchanged). 10. Handle `stop_reason: "refusal"`. Claude Haiku 5.5 runs safety classifiers that can decline a request, and it has no server-side fallback. See [Safeguard refusals](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-haiku-5-5#safeguard-refusals). @@ -126,11 +126,13 @@ A prefill is a final assistant turn in `messages` that the model continues. Clau ## Move computer use to the toolset -Claude Haiku 4.5 supports [computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) through the `computer_20250124` tool, with the `computer-use-2025-01-24` beta header. On the Claude API and Claude Models on Google Cloud (Google managed), Claude Haiku 5.5 supports computer use only through the `computer_toolset_20260801` toolset, and a request that declares `computer_20250124` returns a 400 error. On Amazon Bedrock, Claude Haiku 5.5 doesn’t accept `computer_20250124` either; use the `computer_20251124` tool version with the `computer-use-2025-11-24` beta header. +Claude Haiku 4.5 supports [computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) through the `computer_20250124` tool, with the `computer-use-2025-01-24` beta header. Claude Haiku 5.5 supports computer use through the `computer_toolset_20260801` toolset. A request to Claude Haiku 5.5 that declares `computer_20250124` returns a 400 error. -To move an integration to the toolset, drop the `computer-use-2025-01-24` beta header and replace the `tools` entry with `{"type": "computer_toolset_20260801"}`. Then make the other request and agent-loop changes in [Migrate from `computer_20251124`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124): dispatch on each member `tool_use` block’s `name` and `toolset_name` rather than on `input.action`, handle every such block in a turn, and echo `toolset_name` on results. Zoom is on by default in the toolset; if your environment doesn’t implement it, add `"configs": {"zoom": {"enabled": false}}`. If you send the `fine-grained-tool-streaming-2025-05-14` beta header, remove it. Alongside a toolset entry, it returns a 400 error. For other platforms, see the computer use tool’s [API support](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#availability-feature-support) section. +To move an integration to the toolset, drop the `computer-use-2025-01-24` beta header and replace the `tools` entry with `{"type": "computer_toolset_20260801"}`. Then make the other request and agent-loop changes in [Migrate from `computer_20251124`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124). Dispatch on each member `tool_use` block’s `name` and `toolset_name` rather than on `input.action`. Handle every such block in a turn and echo `toolset_name` on results. Zoom is on by default in the toolset; if your environment doesn’t implement it, add `"configs": {"zoom": {"enabled": false}}`. If you send the `fine-grained-tool-streaming-2025-05-14` beta header, remove it. Alongside a toolset entry, it returns a 400 error. -On the Claude API and Claude Models on Google Cloud (Google managed), Claude Haiku 5.5 also supports the [browser use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool) (`browser_toolset_20260801`) for tasks inside webpages. Claude Haiku 4.5 doesn’t support it. +On Amazon Bedrock, Claude Haiku 5.5 also accepts the `computer_20251124` tool with the `computer-use-2025-11-24` beta header. + +Claude Haiku 5.5 supports the [browser use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool) (`browser_toolset_20260801`) for tasks inside webpages. Claude Haiku 4.5 doesn’t support it. ## Replay thinking blocks through the account that produced them diff --git a/content/en/models/haiku-5-5/whats-new-haiku-5-5.md b/content/en/models/haiku-5-5/whats-new-haiku-5-5.md index e86c013b66..9b5f7145ff 100644 --- a/content/en/models/haiku-5-5/whats-new-haiku-5-5.md +++ b/content/en/models/haiku-5-5/whats-new-haiku-5-5.md @@ -12,24 +12,24 @@ For code changes, see the [migration guide](https://platform.claude.com/docs/en/ Each row names one change, whether it is new, changed, or breaking, and what your code has to do. -| Change | Type | Action needed | -| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [Adaptive thinking and effort](https://platform.claude.com/docs/en/models/haiku-5-5/whats-new-haiku-5-5#adaptive-thinking-and-effort) | New | Optional: set `effort` to trade response quality against speed and cost. | -| [Larger context window and output](https://platform.claude.com/docs/en/models/haiku-5-5/whats-new-haiku-5-5#larger-context-window-and-output) | New | None. Existing `max_tokens` values stay valid, but thinking tokens count toward them. Long prompts are billed at higher prices; see [Long context pricing](https://platform.claude.com/docs/en/about-claude/pricing#long-context-pricing). | -| [Browser use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool) | New | None. Available on the Claude API and Claude Models on Google Cloud (Google managed). | -| [Safety classifiers can decline a request](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#refusal-response) | New | Handle `stop_reason: "refusal"` in your client. Server-side fallback isn’t available. | -| [Manual extended thinking returns an error](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#configure-thinking) | Breaking | Replace `budget_tokens` with adaptive thinking. | -| [Sampling parameters can return an error](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#remove-sampling-parameters) | Breaking | Omit `temperature`, `top_p`, and `top_k`. | -| [Assistant message prefill returns an error](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#replace-assistant-prefill) | Breaking | End `messages` with a user turn. | -| [`computer_20250124` returns an error](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#computer-use-toolset) on the Claude API, Claude Models on Google Cloud (Google managed), and Amazon Bedrock | Breaking | Replace it with `computer_toolset_20260801` on the Claude API and Claude Models on Google Cloud (Google managed), or with `computer_20251124` on Amazon Bedrock. | -| [Changing earlier turns invalidates thinking blocks](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#keep-earlier-turns-unchanged) | Breaking | Keep conversations append-only if you send thinking blocks back. | -| [Responses can start with thinking blocks](https://platform.claude.com/docs/en/models/haiku-5-5/whats-new-haiku-5-5#responses-can-begin-with-thinking-blocks) | Changed | Select content blocks by `type`, not by position. | -| [Thinking text is omitted by default](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#configure-thinking) | Changed | To receive summarized thinking, set `thinking.display` to `"summarized"`. | -| [Same text counts as more tokens](https://platform.claude.com/docs/en/models/haiku-5-5/whats-new-haiku-5-5#same-text-counts-as-more-tokens) | Changed | Recount prompts and revisit `max_tokens` and cost estimates. | -| [Replaying thinking blocks across accounts](https://platform.claude.com/docs/en/models/haiku-5-5/whats-new-haiku-5-5#replaying-thinking-blocks-across-accounts) | Changed | If you replay stored conversations through a different account, replay each through the account that produced it. | -| [Earlier thinking blocks stay in context](https://platform.claude.com/docs/en/models/haiku-5-5/whats-new-haiku-5-5#earlier-thinking-blocks-stay-in-context) | Changed | Expect more input tokens in multi-turn conversations. To remove older blocks, use [thinking block clearing](https://platform.claude.com/docs/en/build-with-claude/context-editing#thinking-block-clearing). | -| [Shorter prompts can be cached](https://platform.claude.com/docs/en/build-with-claude/prompt-caching#cache-limitations) | Changed | None. The minimum cacheable prompt length is 512 tokens, down from 4,096 on Claude Haiku 4.5, so a prompt in between that sets `cache_control` is cached on Claude Haiku 5.5. | -| [Context awareness tags aren’t injected](https://platform.claude.com/docs/en/build-with-claude/context-windows#context-awareness) | Changed | To give the model an explicit budget for an agentic loop, use [task budgets](https://platform.claude.com/docs/en/build-with-claude/task-budgets) (beta). | +| Change | Type | Action needed | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| [Adaptive thinking and effort](https://platform.claude.com/docs/en/models/haiku-5-5/whats-new-haiku-5-5#adaptive-thinking-and-effort) | New | Optional: set `effort` to trade response quality against speed and cost. | +| [Larger context window and output](https://platform.claude.com/docs/en/models/haiku-5-5/whats-new-haiku-5-5#larger-context-window-and-output) | New | None. Existing `max_tokens` values stay valid, but thinking tokens count toward them. Long prompts are billed at higher prices; see [Long context pricing](https://platform.claude.com/docs/en/about-claude/pricing#long-context-pricing). | +| [Browser use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool) | New | None. | +| [Safety classifiers can decline a request](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#refusal-response) | New | Handle `stop_reason: "refusal"` in your client. Server-side fallback isn’t available. | +| [Manual extended thinking returns an error](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#configure-thinking) | Breaking | Replace `budget_tokens` with adaptive thinking. | +| [Sampling parameters can return an error](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#remove-sampling-parameters) | Breaking | Omit `temperature`, `top_p`, and `top_k`. | +| [Assistant message prefill returns an error](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#replace-assistant-prefill) | Breaking | End `messages` with a user turn. | +| [`computer_20250124` returns an error](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#computer-use-toolset) | Breaking | Replace it with `computer_toolset_20260801`. On Amazon Bedrock, `computer_20251124` also works. | +| [Changing earlier turns invalidates thinking blocks](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#keep-earlier-turns-unchanged) | Breaking | Keep conversations append-only if you send thinking blocks back. | +| [Responses can start with thinking blocks](https://platform.claude.com/docs/en/models/haiku-5-5/whats-new-haiku-5-5#responses-can-begin-with-thinking-blocks) | Changed | Select content blocks by `type`, not by position. | +| [Thinking text is omitted by default](https://platform.claude.com/docs/en/models/haiku-5-5/migration-guide#configure-thinking) | Changed | To receive summarized thinking, set `thinking.display` to `"summarized"`. | +| [Same text counts as more tokens](https://platform.claude.com/docs/en/models/haiku-5-5/whats-new-haiku-5-5#same-text-counts-as-more-tokens) | Changed | Recount prompts and revisit `max_tokens` and cost estimates. | +| [Replaying thinking blocks across accounts](https://platform.claude.com/docs/en/models/haiku-5-5/whats-new-haiku-5-5#replaying-thinking-blocks-across-accounts) | Changed | If you replay stored conversations through a different account, replay each through the account that produced it. | +| [Earlier thinking blocks stay in context](https://platform.claude.com/docs/en/models/haiku-5-5/whats-new-haiku-5-5#earlier-thinking-blocks-stay-in-context) | Changed | Expect more input tokens in multi-turn conversations. To remove older blocks, use [thinking block clearing](https://platform.claude.com/docs/en/build-with-claude/context-editing#thinking-block-clearing). | +| [Shorter prompts can be cached](https://platform.claude.com/docs/en/build-with-claude/prompt-caching#cache-limitations) | Changed | None. The minimum cacheable prompt length is 512 tokens, down from 4,096 on Claude Haiku 4.5, so a prompt in between that sets `cache_control` is cached on Claude Haiku 5.5. | +| [Context awareness tags aren’t injected](https://platform.claude.com/docs/en/build-with-claude/context-windows#context-awareness) | Changed | To give the model an explicit budget for an agentic loop, use [task budgets](https://platform.claude.com/docs/en/build-with-claude/task-budgets) (beta). | ## New capabilities diff --git a/content/en/models/opus-5-5/migration-guide.md b/content/en/models/opus-5-5/migration-guide.md index 10cefe23f7..feec2e7059 100644 --- a/content/en/models/opus-5-5/migration-guide.md +++ b/content/en/models/opus-5-5/migration-guide.md @@ -28,7 +28,7 @@ Whichever model you are coming from, a request to `claude-opus-5-5` must meet th * **Tool choice:** Use `tool_choice` `{"type": "auto"}` (the default) or `{"type": "none"}`. Forcing a tool call with `{"type": "any"}` or `{"type": "tool", "name": "..."}` is rejected. See the [before and after for tool choice](https://platform.claude.com/docs/en/models/opus-5-5/migration-guide#forced-tool-use). * **Sampling parameters:** Omit `temperature`, `top_p`, and `top_k`. Use prompting to guide the model’s behavior. * **Prefill:** Don’t end `messages` with a prefilled assistant turn: it is rejected. Use [structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs) or system prompt instructions instead. -* **Computer use:** On the Claude API and Claude Models on Google Cloud (Google managed), declare computer use as the `computer_toolset_20260801` toolset; the earlier `computer_20251124` tool is rejected there. See the [computer use breaking change](https://platform.claude.com/docs/en/models/opus-5-5/migration-guide#computer-use-toolset). +* **Computer use:** Declare computer use as the `computer_toolset_20260801` toolset. On Amazon Bedrock, `computer_20251124` also works. See the [computer use breaking change](https://platform.claude.com/docs/en/models/opus-5-5/migration-guide#computer-use-toolset). * **Context window:** No context-window beta header is needed. The [1M token context window](https://platform.claude.com/docs/en/build-with-claude/context-windows) is the default, and a header sent for older models has no effect. The following request satisfies every item in the list: effort is set, and there is no `thinking` field. Where the example prints text, it finds the text block by its type, because `thinking` blocks come first. @@ -279,7 +279,7 @@ Work down the groups and stop after the one that names your current model: every * Remove `thinking: {"type": "disabled"}` and `thinking: {"type": "enabled", ...}`; choose an effort level instead. * Set `effort` explicitly: the default is `medium`, where Claude Opus 5’s is `high`. * Replace `tool_choice` types `any` and `tool` with `auto` plus strict tool use or structured outputs. -* If you use computer use on the Claude API or Claude Models on Google Cloud (Google managed), declare `computer_toolset_20260801` (no beta header) instead of `computer_20251124` and update your agent loop for the toolset. On Amazon Bedrock, keep `computer_20251124`; check the computer use tool’s [API support](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#availability-feature-support) section for other platforms. +* If you use an earlier computer use tool version, declare `computer_toolset_20260801` (no beta header) instead and update your agent loop for the toolset. On Amazon Bedrock, `computer_20251124` also works. * If a router or fallback can move a conversation from Claude Opus 5.5 to another model, expect that model to run without Claude Opus 5.5’s thinking blocks (Claude Fable 5.1 and Claude Mythos 5.1 on the Claude API are the exception and keep them). Claude Opus 5.5 itself reads thinking from Claude Opus 5, from earlier Opus, Sonnet, and Haiku models, and, on the Claude API and Claude Models on Google Cloud (Google managed), from Claude Sonnet 5.5 and Claude Haiku 5.5, but not from Claude Fable or Claude Mythos models. * Read content blocks by `type`, and pass `thinking` blocks back unmodified in tool-use loops. * If your interface renders text between tool calls, set `display: "updates"` (beta) or `"summarized"` and render the non-empty `thinking` blocks. @@ -878,11 +878,13 @@ After: On the Claude API, Claude Fable 5.1 and Claude Mythos 5.1 read Claude Opus 5.5 thinking blocks; no other model does. A router or fallback that moves a conversation from Claude Opus 5.5 to any other model runs those turns without them. In the other direction, Claude Opus 5.5 reads thinking blocks from Claude Opus 5, from earlier Opus, Sonnet, and Haiku models, and, on the Claude API and Claude Models on Google Cloud (Google managed), from Claude Sonnet 5.5 and Claude Haiku 5.5, but not from Claude Fable or Claude Mythos models. Keep the conversation append-only (no edits to the `system` prompt, `tools`, or earlier messages mid-conversation) so the blocks stay valid; Claude Code, claude.ai, Claude Managed Agents, and the Claude Agent SDK already do. On accounts created on or after August 31, 2026, 00:00 UTC, on the Claude API and on cloud platforms, a request that replays a thinking block after such an edit and leaves `thinking.block_binding.prefix_mismatch_behavior` unset gets a 400 error. There is no code change for append-only integrations. See [Thinking blocks are tied to the model and the conversation](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#thinking-blocks-are-tied-to-the-model-that-produced-them) and [Preserved thinking](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking). -#### The `computer_20251124` computer use tool is not supported on the Claude API and Claude Models on Google Cloud (Google managed) +#### Some computer use tool versions are not supported -On the Claude API and Claude Models on Google Cloud (Google managed), a `tools` entry of type `computer_20251124` returns a 400 error (`'claude-opus-5-5' does not support tool types: computer_20251124.`, followed by the tool types the model accepts). Declare the `computer_toolset_20260801` toolset instead: drop the beta header and send the entry with no `name` or display dimensions. In your agent loop, handle member `tool_use` blocks (the action is the block’s `name`, not `input.action`), several of them per turn, and echo `toolset_name` on every result. The request change is shown below; the agent-loop changes are listed in [Migrate from `computer_20251124`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124). On Amazon Bedrock, the earlier `computer_20251124` tool continues to work on Claude Opus 5.5 as it does on Claude Opus 5, so no change is needed there; for other platforms, see the computer use tool’s [API support](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#availability-feature-support) section. See [The `computer_20251124` computer use tool is not supported on the Claude API and Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#computer-20251124-is-not-supported). +Claude Opus 5.5 supports computer use through the `computer_toolset_20260801` toolset. On Amazon Bedrock, Claude Opus 5.5 also accepts the `computer_20251124` tool with the `computer-use-2025-11-24` beta header. Claude Opus 5.5 returns a 400 error for any computer use tool version it doesn’t accept, such as `computer_20251124` on the Claude API. It doesn’t accept `computer_20250124` on any platform. On the Claude API, the error message begins `'claude-opus-5-5' does not support tool types: computer_20251124.` and then lists the tool types the model accepts. -Before. Claude Opus 5 accepts this request, and on the Claude API and Claude Models on Google Cloud (Google managed), Claude Opus 5.5 rejects it with a 400 error: +Integrations that use the toolset need no change. To move a `computer_20251124` integration to the toolset, drop the beta header and send the `computer_toolset_20260801` entry with no `name` or display dimensions. In your agent loop, handle every member `tool_use` block in a turn and echo `toolset_name` on every result. Read the action from each block’s `name`, not from `input.action`. [Migrate from `computer_20251124`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124) lists the agent-loop changes. + +Before. Claude Opus 5 accepts this request, and Claude Opus 5.5 rejects it with a 400 error on the Claude API: ```bash cURL @@ -1198,7 +1200,7 @@ None of these items adds a breaking change to those in the earlier sections; the 5. **Fast mode:** Claude Opus 5.5 supports [fast mode](https://platform.claude.com/docs/en/build-with-claude/fast-mode) on the Claude API. Fast mode is not available on Claude Opus 4.7, where requests with `speed: "fast"` return an error. Set `speed: "fast"` on your requests. Claude Opus 5.5 doesn’t need a beta header. -6. **Computer use toolset and browser use tool:** On the Claude API and Claude Models on Google Cloud (Google managed), Claude Opus 5.5 supports [computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) as the `computer_toolset_20260801` toolset and the [browser use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool) for tasks inside webpages. Claude Opus 4.7 supports neither. On those platforms Claude Opus 5.5 doesn’t accept the earlier `computer_20251124` tool; see the [computer use breaking change](https://platform.claude.com/docs/en/models/opus-5-5/migration-guide#computer-use-toolset). +6. **Computer use toolset and browser use tool:** Claude Opus 5.5 supports [computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) as the `computer_toolset_20260801` toolset and the [browser use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool) for tasks inside webpages. Claude Opus 4.7 supports neither. To move a `computer_20251124` integration to the toolset, see the [computer use breaking change](https://platform.claude.com/docs/en/models/opus-5-5/migration-guide#computer-use-toolset). ## Migrating to Claude Opus 5.5 from Claude Opus 4.6 and earlier Opus models @@ -1631,7 +1633,7 @@ If you’re migrating from Claude Opus 4.1 or earlier models directly to Claude * **Text editor:** Use `text_editor_20250728` and `str_replace_based_edit_tool`. See the [Text editor tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/text-editor-tool) documentation for details. * **Code execution:** Upgrade to `code_execution_20260521`. See the [Code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool#upgrade-to-latest-tool-version) documentation for migration instructions. - * **Computer use:** On the Claude API and Claude Models on Google Cloud (Google managed), Claude Opus 5.5 accepts computer use only as the `computer_toolset_20260801` toolset: the earlier `computer_20250124` and `computer_20251124` tools are rejected there. See the [computer use breaking change](https://platform.claude.com/docs/en/models/opus-5-5/migration-guide#computer-use-toolset). + * **Computer use:** Use the `computer_toolset_20260801` toolset in place of `computer_20250124`, which Claude Opus 5.5 doesn’t accept. On Amazon Bedrock, `computer_20251124` also works. See the [computer use breaking change](https://platform.claude.com/docs/en/models/opus-5-5/migration-guide#computer-use-toolset). 3. **Handle the `refusal` stop reason** diff --git a/content/en/models/opus-5-5/overview.md b/content/en/models/opus-5-5/overview.md index 5454ad1481..17c3763a7a 100644 --- a/content/en/models/opus-5-5/overview.md +++ b/content/en/models/opus-5-5/overview.md @@ -16,7 +16,14 @@ Context window: 1M tokens · Max output: 128K tokens · Input pricing: $4 / MTok ## Overview -Claude Opus 5.5 is built for long-running agentic coding and knowledge work, priced at $4 / $20 USD per million input / output tokens. Four breaking changes affect code already running on Claude Opus 5: [thinking can’t be disabled](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#thinking-cant-be-disabled), [forced tool use returns an error](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#forced-tool-use-is-not-supported), [thinking blocks are tied to the model and the conversation](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#thinking-blocks-are-tied-to-the-model-that-produced-them), and, on the Claude API and Claude Models on Google Cloud (Google managed), [the earlier `computer_20251124` computer use tool is not accepted](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#computer-20251124-is-not-supported). The first three also apply on Claude Fable 5.1. A further change alters the response shape without failing any request: [text between tool calls comes back in `thinking` blocks](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#text-between-tool-calls) whose text is empty at the default `display` setting. An application that streams that text to its users as progress updates goes quiet between tool calls until it sets a `display` value that returns the text. +Claude Opus 5.5 is built for long-running agentic coding and knowledge work, priced at $4 / $20 USD per million input / output tokens. Four breaking changes can affect code already running on Claude Opus 5: + +* [Thinking can’t be disabled](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#thinking-cant-be-disabled). +* [Forced tool use returns an error](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#forced-tool-use-is-not-supported). +* [Thinking blocks are tied to the model and the conversation](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#thinking-blocks-are-tied-to-the-model-that-produced-them). +* [Some computer use tool versions are not supported](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#computer-20251124-is-not-supported). + +The first three also apply on Claude Fable 5.1. A further change alters the response shape without failing any request: [text between tool calls comes back in `thinking` blocks](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#text-between-tool-calls) whose text is empty at the default `display` setting. An application that streams that text to its users as progress updates goes quiet between tool calls until it sets a `display` value that returns the text. [What’s new in Claude Opus 5.5](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5) diff --git a/content/en/models/opus-5-5/whats-new-opus-5-5.md b/content/en/models/opus-5-5/whats-new-opus-5-5.md index 334ba6d5b5..befcb27f53 100644 --- a/content/en/models/opus-5-5/whats-new-opus-5-5.md +++ b/content/en/models/opus-5-5/whats-new-opus-5-5.md @@ -4,7 +4,14 @@ url: https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5 description: Overview of breaking changes, feature support, and behavior differences in Claude Opus 5.5. --- -Claude Opus 5.5 is built for long-running agentic coding and knowledge work, priced at $4 / $20 USD per million input / output tokens. Four breaking changes affect code already running on Claude Opus 5: [thinking can’t be disabled](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#thinking-cant-be-disabled), [forced tool use returns an error](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#forced-tool-use-is-not-supported), [thinking blocks are tied to the model and the conversation](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#thinking-blocks-are-tied-to-the-model-that-produced-them), and, on the Claude API and Claude Models on Google Cloud (Google managed), [the earlier `computer_20251124` computer use tool is not accepted](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#computer-20251124-is-not-supported). The first three also apply on Claude Fable 5.1. A further change alters the response shape without failing any request: [text between tool calls comes back in `thinking` blocks](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#text-between-tool-calls) whose text is empty at the default `display` setting. An application that streams that text to its users as progress updates goes quiet between tool calls until it sets a `display` value that returns the text. +Claude Opus 5.5 is built for long-running agentic coding and knowledge work, priced at $4 / $20 USD per million input / output tokens. Four breaking changes can affect code already running on Claude Opus 5: + +* [Thinking can’t be disabled](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#thinking-cant-be-disabled). +* [Forced tool use returns an error](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#forced-tool-use-is-not-supported). +* [Thinking blocks are tied to the model and the conversation](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#thinking-blocks-are-tied-to-the-model-that-produced-them). +* [Some computer use tool versions are not supported](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#computer-20251124-is-not-supported). + +The first three also apply on Claude Fable 5.1. A further change alters the response shape without failing any request: [text between tool calls comes back in `thinking` blocks](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#text-between-tool-calls) whose text is empty at the default `display` setting. An application that streams that text to its users as progress updates goes quiet between tool calls until it sets a `display` value that returns the text. ## New model @@ -48,19 +55,19 @@ Every thinking block records which model produced it, and each model reads its o The API also checks whether anything before a Claude Opus 5.5 thinking block (the `system` prompt, the `tools`, or an earlier message) has changed since the block was produced. Keep the conversation append-only: change instructions or tools with [mid-conversation system messages](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages) rather than edits. A request that replays a block after such a change and leaves `thinking.block_binding.prefix_mismatch_behavior` unset gets a 400 error on accounts created on or after August 31, 2026, 00:00 UTC. This applies on the Claude API and on cloud platforms. On accounts created before that date, the request gets the error only when it sets the field to `"error"`. To drop the affected blocks instead, send the `thinking-binding-controls-2026-08-01` beta header and set the field to `"drop_block"`. See [Preserved thinking](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking) and the migration guide’s [note on thinking blocks](https://platform.claude.com/docs/en/models/opus-5-5/migration-guide#thinking-blocks). -### The `computer_20251124` computer use tool is not supported on the Claude API and Claude Models on Google Cloud (Google managed) +### Some computer use tool versions are not supported -Claude Opus 5 accepts [computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) both as the `computer_toolset_20260801` toolset and, with the `computer-use-2025-11-24` beta header, as the earlier `computer_20251124` tool. On the Claude API and Claude Models on Google Cloud (Google managed), Claude Opus 5.5 supports only the toolset: a request that declares a `computer_20251124` tool returns a 400 `invalid_request_error`. The message names the rejected type, then lists the tool types the model does accept (`computer_toolset_20260801` among them) after `Did you mean one of`; it begins: +Claude Opus 5.5 supports [computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) through the `computer_toolset_20260801` toolset. On Amazon Bedrock, Claude Opus 5.5 also accepts the `computer_20251124` tool with the `computer-use-2025-11-24` beta header. Claude Opus 5.5 returns a 400 error for any computer use tool version it doesn’t accept, such as `computer_20251124` on the Claude API. The Claude API’s `invalid_request_error` message names the rejected type and, after `Did you mean one of`, lists the tool types the model accepts. The message begins: ```text wrap 'claude-opus-5-5' does not support tool types: computer_20251124. ``` -To move an existing integration on the Claude API or Claude Models on Google Cloud (Google managed), follow [Migrate from `computer_20251124`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124): drop the beta header, replace the `tools` entry with `{"type": "computer_toolset_20260801"}`, and update your agent loop for member `tool_use` blocks, batch actions, and `toolset_name` on results. On Amazon Bedrock, the earlier `computer_20251124` tool continues to work on Claude Opus 5.5 as it does on Claude Opus 5, so no change is needed there. For other platforms, see the computer use tool’s [API support](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#availability-feature-support) section. Integrations that already use the toolset, and the [browser use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool), need no change. The migration guide shows the request [before and after](https://platform.claude.com/docs/en/models/opus-5-5/migration-guide#computer-use-toolset). +Integrations that use the toolset need no change. To move a `computer_20251124` integration to the toolset, follow [Migrate from `computer_20251124`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124). Drop the beta header and replace the `tools` entry with `{"type": "computer_toolset_20260801"}`. Then update your agent loop for member `tool_use` blocks, batch actions, and `toolset_name` on results. The migration guide shows the request [before and after](https://platform.claude.com/docs/en/models/opus-5-5/migration-guide#computer-use-toolset). ## Feature support -Claude Opus 5.5 supports [per-message effort](https://platform.claude.com/docs/en/build-with-claude/effort#change-effort-mid-conversation-beta) (beta), [mid-conversation system messages](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages), [task budgets](https://platform.claude.com/docs/en/build-with-claude/task-budgets), [prompt caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching) with a 512-token minimum cacheable prompt, [batch processing](https://platform.claude.com/docs/en/build-with-claude/batch-processing), the [Files API](https://platform.claude.com/docs/en/build-with-claude/files), [PDF support](https://platform.claude.com/docs/en/build-with-claude/pdf-support), [vision](https://platform.claude.com/docs/en/build-with-claude/vision), and server-side and client-side [tools](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview). On the Claude API and Claude Models on Google Cloud (Google managed), computer use requires the `computer_toolset_20260801` toolset (see the [computer use breaking change](https://platform.claude.com/docs/en/models/opus-5-5/whats-new-opus-5-5#computer-20251124-is-not-supported)). See each feature’s page for model availability. +Claude Opus 5.5 supports [per-message effort](https://platform.claude.com/docs/en/build-with-claude/effort#change-effort-mid-conversation-beta) (beta), [mid-conversation system messages](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages), [task budgets](https://platform.claude.com/docs/en/build-with-claude/task-budgets), [prompt caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching) with a 512-token minimum cacheable prompt, [batch processing](https://platform.claude.com/docs/en/build-with-claude/batch-processing), the [Files API](https://platform.claude.com/docs/en/build-with-claude/files), [PDF support](https://platform.claude.com/docs/en/build-with-claude/pdf-support), [vision](https://platform.claude.com/docs/en/build-with-claude/vision), and server-side and client-side [tools](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview). See each feature’s page for model availability. ### Fast mode @@ -144,7 +151,7 @@ Update your model ID: ``` -Then remove any `thinking: {"type": "disabled"}` or `thinking: {"type": "enabled", ...}` settings and choose an [effort](https://platform.claude.com/docs/en/build-with-claude/effort) level instead. Replace `tool_choice` types `any` and `tool` with `auto` plus [strict tool use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/strict-tool-use). If you use computer use through `computer_20251124` on the Claude API or Claude Models on Google Cloud (Google managed), [move to the toolset](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124). If your interface shows the text between tool calls, also set `thinking.display`; see [Text between tool calls is returned in thinking blocks](https://platform.claude.com/docs/en/models/opus-5-5/migration-guide#text-between-tool-calls). See the [migration guide](https://platform.claude.com/docs/en/models/opus-5-5/migration-guide) for step-by-step instructions from Claude Opus 5 and earlier models, and the full checklist. +Then remove any `thinking: {"type": "disabled"}` or `thinking: {"type": "enabled", ...}` settings and choose an [effort](https://platform.claude.com/docs/en/build-with-claude/effort) level instead. Replace `tool_choice` types `any` and `tool` with `auto` plus [strict tool use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/strict-tool-use). If you use computer use through `computer_20251124`, [move to the toolset](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124). On Amazon Bedrock, `computer_20251124` also works. If your interface shows the text between tool calls, also set `thinking.display`; see [Text between tool calls is returned in thinking blocks](https://platform.claude.com/docs/en/models/opus-5-5/migration-guide#text-between-tool-calls). See the [migration guide](https://platform.claude.com/docs/en/models/opus-5-5/migration-guide) for step-by-step instructions from Claude Opus 5 and earlier models, and the full checklist. ## Next steps diff --git a/content/en/models/sonnet-5-5/migration-guide.md b/content/en/models/sonnet-5-5/migration-guide.md index d3ee6aa353..5f83e3f0db 100644 --- a/content/en/models/sonnet-5-5/migration-guide.md +++ b/content/en/models/sonnet-5-5/migration-guide.md @@ -470,7 +470,7 @@ Work down the groups and stop after the one that names your model. On Claude Hai * To keep running without up-front thinking, send the [lowest thinking setting](https://platform.claude.com/docs/en/models/sonnet-5-5/migration-guide#turn-off-up-front-thinking) at `high` effort or below. * Replace [forced tool use](https://platform.claude.com/docs/en/models/sonnet-5-5/migration-guide#forced-tool-use) with `auto` and strict tools. * Keep conversations [append-only](https://platform.claude.com/docs/en/models/sonnet-5-5/migration-guide#thinking-blocks). -* On the Claude API and Claude Models on Google Cloud (Google managed), move computer use to the [toolset](https://platform.claude.com/docs/en/models/sonnet-5-5/migration-guide#computer-use-toolset), without the `fine-grained-tool-streaming-2025-05-14` beta header. +* Move computer use to the [toolset](https://platform.claude.com/docs/en/models/sonnet-5-5/migration-guide#computer-use-toolset), without the `fine-grained-tool-streaming-2025-05-14` beta header. On Amazon Bedrock, `computer_20251124` also works. * [Pair the advisor tool](https://platform.claude.com/docs/en/models/sonnet-5-5/migration-guide#advisor-tool) with a supported advisor, and expect encrypted advice. * Read [text between tool calls](https://platform.claude.com/docs/en/models/sonnet-5-5/migration-guide#text-between-tool-calls) from `thinking` blocks. * [Handle refusals](https://platform.claude.com/docs/en/models/sonnet-5-5/migration-guide#safety-classifiers-and-fallback), and configure fallback. @@ -488,7 +488,6 @@ Work down the groups and stop after the one that names your model. On Claude Hai * Replace [assistant prefills](https://platform.claude.com/docs/en/models/sonnet-5-5/migration-guide#migrating-from-sonnet-45). * Parse tool call input with a standard JSON parser. -* On Amazon Bedrock, move computer use from `computer_20250124` to [`computer_20251124`](https://platform.claude.com/docs/en/models/sonnet-5-5/migration-guide#computer-use-toolset). * Set `output_config.effort` explicitly. * Remove any context-window beta header. * Remove `interleaved-thinking-2025-05-14`, and replace `fine-grained-tool-streaming-2025-05-14` with `eager_input_streaming`. @@ -843,19 +842,14 @@ Claude Sonnet 5.5 reads thinking blocks from Claude Sonnet 5, Claude Opus 4.8, C Each Claude Sonnet 5.5 thinking block is also signed over the conversation before it. Keep conversations append-only, and change instructions or tools with [mid-conversation system messages](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages). A request that replays a block after an edit to earlier history and leaves `thinking.block_binding.prefix_mismatch_behavior` unset gets a 400 error on accounts created on or after August 31, 2026, 00:00 UTC. This applies on the Claude API, Amazon Bedrock, and Claude Models on Google Cloud (Google managed). Thinking blocks that Claude Sonnet 5.5 produces work only in the account that produced them or in an account linked to it. See [Preserved thinking](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#account-bound-thinking). -### Computer use needs the toolset on the Claude API and Claude Models on Google Cloud (Google managed) +### Some computer use tool versions are not supported -On the Claude API and Claude Models on Google Cloud (Google managed), Claude Sonnet 5.5 supports computer use only through the `computer_toolset_20260801` toolset. There, `computer_20251124` returns a 400 error. Claude Sonnet 5.5 doesn’t accept `computer_20250124` on any platform. Find the version you send today: +Claude Sonnet 5.5 supports computer use through the `computer_toolset_20260801` toolset. On Amazon Bedrock, Claude Sonnet 5.5 also accepts the `computer_20251124` tool with the `computer-use-2025-11-24` beta header. Claude Sonnet 5.5 returns a 400 error for any computer use tool version it doesn’t accept, such as `computer_20251124` on the Claude API. It doesn’t accept `computer_20250124` on any platform. -| Version you send today | Starting models that send it | Send on the Claude API and Claude Models on Google Cloud (Google managed) | Send on Amazon Bedrock | -| ---------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------- | ---------------------- | -| `computer_20251124` | Claude Sonnet 5, Claude Sonnet 4.6 | `computer_toolset_20260801` | `computer_20251124` | -| `computer_20250124` | Claude Sonnet 4.5, Claude Haiku 4.5, Claude Sonnet 4 | `computer_toolset_20260801` | `computer_20251124` | +Integrations that use the toolset need no change. To move to the toolset, replace `computer_20251124` or `computer_20250124` with `computer_toolset_20260801`, and drop that version’s beta header. [Migrate from `computer_20251124`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124) lists the request and agent-loop changes. If you send the `fine-grained-tool-streaming-2025-05-14` beta header, remove it when you move to the toolset. Alongside a toolset entry, it returns a 400 error. Set `eager_input_streaming: true` on each tool that needs it instead. -Code that already sends the toolset needs no change. [Migrate from `computer_20251124`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124) lists the request and agent-loop changes. For other platforms, see [API support](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#availability-feature-support). - ### The advisor tool accepts fewer advisors With the [advisor tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/advisor-tool), a Claude Sonnet 5.5 executor needs one of these advisors: Claude Opus 5, Claude Opus 5.5, Claude Sonnet 5.5, Claude Fable 5, Claude Fable 5.1, Claude Mythos 5, or Claude Mythos 5.1. Claude Opus 4.8, Claude Opus 4.7, Claude Opus 4.6, Claude Sonnet 5, Claude Sonnet 4.6, and Claude Haiku 5.5 advisors return a 400 error. The advice comes back encrypted as an `advisor_redacted_result` block, so its text isn’t readable in the response. See [Model compatibility](https://platform.claude.com/docs/en/agents-and-tools/tool-use/advisor-tool#model-compatibility). @@ -1216,7 +1210,7 @@ Replace each prefill according to what it was for: **Tool input escaping.** Escaping in tool call arguments can differ. Parse `input` with a standard JSON parser. -**Computer use.** Claude Sonnet 5.5 doesn’t accept `computer_20250124`. See the [computer use table](https://platform.claude.com/docs/en/models/sonnet-5-5/migration-guide#computer-use-toolset). +**Computer use.** Claude Sonnet 5.5 doesn’t accept `computer_20250124`. See [Some computer use tool versions are not supported](https://platform.claude.com/docs/en/models/sonnet-5-5/migration-guide#computer-use-toolset). **Effort.** Claude Sonnet 4.5 has no effort parameter. Set an effort level explicitly, as [Recommended changes](https://platform.claude.com/docs/en/models/sonnet-5-5/migration-guide#recommended-changes) describes. diff --git a/content/en/models/sonnet-5-5/overview.md b/content/en/models/sonnet-5-5/overview.md index 8523b2b57e..3c1e5c77c1 100644 --- a/content/en/models/sonnet-5-5/overview.md +++ b/content/en/models/sonnet-5-5/overview.md @@ -16,12 +16,12 @@ Context window: 1M tokens · Max output: 128K tokens · Input pricing: $2 / MTok ## Overview -Claude Sonnet 5.5 offers the best combination of speed and intelligence. Five breaking changes affect code already running on Claude Sonnet 5: +Claude Sonnet 5.5 offers the best combination of speed and intelligence. Five breaking changes can affect code already running on Claude Sonnet 5: * [Turn off up-front thinking with `between_tools`](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5#turn-off-up-front-thinking). * [Forced tool use returns an error](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5#forced-tool-use-is-not-supported). * [Thinking blocks are tied to the model and the conversation](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5#thinking-blocks-are-tied-to-the-model-that-produced-them). -* On the Claude API and Claude Models on Google Cloud (Google managed), [the earlier `computer_20251124` computer use tool is not accepted](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5#computer-20251124-is-not-supported). +* [Some computer use tool versions are not supported](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5#computer-20251124-is-not-supported). * [The advisor tool rejects four models as advisors](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5#advisor-tool-pairings): Claude Opus 4.8, Claude Opus 4.7, Claude Sonnet 5, and Claude Haiku 5.5. One more change alters the response shape without failing any request: [text between tool calls comes back in `thinking` blocks](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5#text-between-tool-calls). An application that streams that text to its users goes quiet between tool calls until it sets a `display` value that returns the text, or turns off up-front thinking with `between_tools`. diff --git a/content/en/models/sonnet-5-5/whats-new-sonnet-5-5.md b/content/en/models/sonnet-5-5/whats-new-sonnet-5-5.md index 71990e1d59..e9470d153a 100644 --- a/content/en/models/sonnet-5-5/whats-new-sonnet-5-5.md +++ b/content/en/models/sonnet-5-5/whats-new-sonnet-5-5.md @@ -4,12 +4,12 @@ url: https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5 description: "What changes when you move from Claude Sonnet 5 to Claude Sonnet 5.5: breaking changes, feature support, behavior differences, pricing, and availability." --- -Claude Sonnet 5.5 offers the best combination of speed and intelligence. Five breaking changes affect code already running on Claude Sonnet 5: +Claude Sonnet 5.5 offers the best combination of speed and intelligence. Five breaking changes can affect code already running on Claude Sonnet 5: * [Turn off up-front thinking with `between_tools`](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5#turn-off-up-front-thinking). * [Forced tool use returns an error](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5#forced-tool-use-is-not-supported). * [Thinking blocks are tied to the model and the conversation](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5#thinking-blocks-are-tied-to-the-model-that-produced-them). -* On the Claude API and Claude Models on Google Cloud (Google managed), [the earlier `computer_20251124` computer use tool is not accepted](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5#computer-20251124-is-not-supported). +* [Some computer use tool versions are not supported](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5#computer-20251124-is-not-supported). * [The advisor tool rejects four models as advisors](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5#advisor-tool-pairings): Claude Opus 4.8, Claude Opus 4.7, Claude Sonnet 5, and Claude Haiku 5.5. One more change alters the response shape without failing any request: [text between tool calls comes back in `thinking` blocks](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5#text-between-tool-calls). An application that streams that text to its users goes quiet between tool calls until it sets a `display` value that returns the text, or turns off up-front thinking with `between_tools`. @@ -56,17 +56,15 @@ The API also checks whether anything before a Claude Sonnet 5.5 thinking block h See [Preserved thinking](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking) and the migration guide’s [note on thinking blocks](https://platform.claude.com/docs/en/models/sonnet-5-5/migration-guide#thinking-blocks). -### The `computer_20251124` computer use tool is not supported on the Claude API and Claude Models on Google Cloud (Google managed) +### Some computer use tool versions are not supported -On the Claude API and Claude Models on Google Cloud (Google managed), Claude Sonnet 5.5 supports [computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) only through the `computer_toolset_20260801` toolset. A request that declares the earlier `computer_20251124` tool returns a 400 `invalid_request_error`. On the Claude API, the message names the rejected type, then lists the tool types the model does accept. It begins: +Claude Sonnet 5.5 supports [computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) through the `computer_toolset_20260801` toolset. On Amazon Bedrock, Claude Sonnet 5.5 also accepts the `computer_20251124` tool with the `computer-use-2025-11-24` beta header. Claude Sonnet 5.5 returns a 400 error for any computer use tool version it doesn’t accept, such as `computer_20251124` on the Claude API. The Claude API’s `invalid_request_error` message names the rejected type and, after `Did you mean one of`, lists the tool types the model accepts. The message begins: ```text wrap 'claude-sonnet-5-5' does not support tool types: computer_20251124. ``` -On Amazon Bedrock, Claude Sonnet 5.5 accepts the earlier `computer_20251124` tool. - -To move an existing integration on the Claude API or Claude Models on Google Cloud (Google managed), follow [Migrate from `computer_20251124`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124), which shows the request before and after. Drop the beta header, replace the `tools` entry with `{"type": "computer_toolset_20260801"}`, and update your agent loop for member `tool_use` blocks, batch actions, and `toolset_name` on results. The toolset is available on both the Claude API and Claude Models on Google Cloud (Google managed). For other platforms, see the computer use tool’s [API support](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#availability-feature-support) section. Integrations that already use the toolset, and the [browser use tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool), need no change. +Integrations that use the toolset need no change. To move a `computer_20251124` integration to the toolset, follow [Migrate from `computer_20251124`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124), which shows the request before and after. Drop the beta header and replace the `tools` entry with `{"type": "computer_toolset_20260801"}`. Then update your agent loop for member `tool_use` blocks, batch actions, and `toolset_name` on results. ### Some advisor tool pairings are not supported @@ -74,7 +72,7 @@ With the [advisor tool](https://platform.claude.com/docs/en/agents-and-tools/too ## Feature support -Claude Sonnet 5.5 supports [per-message effort](https://platform.claude.com/docs/en/build-with-claude/effort#change-effort-mid-conversation-beta) (beta), [mid-conversation system messages](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages), [mid-conversation tool changes](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages#mid-conversation-tool-changes) (beta), [prompt caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching) with a 512-token minimum cacheable prompt, [batch processing](https://platform.claude.com/docs/en/build-with-claude/batch-processing), the [Files API](https://platform.claude.com/docs/en/build-with-claude/files), [PDF support](https://platform.claude.com/docs/en/build-with-claude/pdf-support), [vision](https://platform.claude.com/docs/en/build-with-claude/vision), and server-side and client-side [tools](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview). Per-message effort, mid-conversation system messages, and mid-conversation tool changes aren’t available on Claude Sonnet 5, whose minimum cacheable prompt is 1,024 tokens. On the Claude API and Claude Models on Google Cloud (Google managed), computer use requires the `computer_toolset_20260801` toolset (see the [computer use breaking change](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5#computer-20251124-is-not-supported)). See each feature’s page for model availability. +Claude Sonnet 5.5 supports [per-message effort](https://platform.claude.com/docs/en/build-with-claude/effort#change-effort-mid-conversation-beta) (beta), [mid-conversation system messages](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages), [mid-conversation tool changes](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages#mid-conversation-tool-changes) (beta), [prompt caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching) with a 512-token minimum cacheable prompt, [batch processing](https://platform.claude.com/docs/en/build-with-claude/batch-processing), the [Files API](https://platform.claude.com/docs/en/build-with-claude/files), [PDF support](https://platform.claude.com/docs/en/build-with-claude/pdf-support), [vision](https://platform.claude.com/docs/en/build-with-claude/vision), and server-side and client-side [tools](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview). Per-message effort, mid-conversation system messages, and mid-conversation tool changes aren’t available on Claude Sonnet 5, whose minimum cacheable prompt is 1,024 tokens. See each feature’s page for model availability. ### Compact on demand (beta) @@ -159,7 +157,7 @@ Then check six things: 1. If your code turns thinking off with `disabled`, send `between_tools` instead, at `high` effort or below. 2. Replace `tool_choice` types `any` and `tool` with `auto` plus [strict tool use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/strict-tool-use). 3. Keep conversations append-only. A request that replays a Claude Sonnet 5.5 thinking block after an edit to earlier history can return a 400 error. See [Thinking blocks are tied to the model and the conversation](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5#thinking-blocks-are-tied-to-the-model-that-produced-them). -4. If you use computer use through `computer_20251124` on the Claude API or Claude Models on Google Cloud (Google managed), [move to the toolset](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124). +4. If you use computer use through `computer_20251124`, [move to the toolset](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool#migrate-from-computer-20251124). On Amazon Bedrock, `computer_20251124` also works. 5. If you use the advisor tool with a Claude Opus 4.8, Claude Opus 4.7, Claude Sonnet 5, or Claude Haiku 5.5 advisor, [switch to an advisor that Claude Sonnet 5.5 accepts](https://platform.claude.com/docs/en/models/sonnet-5-5/whats-new-sonnet-5-5#advisor-tool-pairings). 6. If your interface shows the text between tool calls, set `thinking.display` when you use adaptive thinking. With `between_tools`, the text comes back without it. See [Text between tool calls is returned in thinking blocks](https://platform.claude.com/docs/en/models/sonnet-5-5/migration-guide#text-between-tool-calls). diff --git a/content/en/release-notes/overview.md b/content/en/release-notes/overview.md index a8e70ad7f5..78a2fb7c03 100644 --- a/content/en/release-notes/overview.md +++ b/content/en/release-notes/overview.md @@ -167,8 +167,7 @@ The Claude Platform release notes list changes to the Claude API, the client SDK ### August 27, 2026 * In Python SDK 1.2.0, TypeScript SDK 0.122.0, Go SDK 1.68.0, Java SDK 2.59.0, Ruby SDK 1.67.0, and C# SDK 12.44.0, `client.beta.files` and `client.beta.skills` no longer send the `files-api-2025-04-14` and `skills-2025-10-02` beta headers and return the same shapes as `client.files` and `client.skills`. With this change, `client.beta.skills.delete()` deletes a Skill together with all of its versions, and the beta Messages type `BetaSkill` (the container Skill reference) is renamed `BetaContainerSkill`. Requests that still send the beta headers keep receiving the beta shapes. See [Migrate from `files-api-2025-04-14`](https://platform.claude.com/docs/en/build-with-claude/files#migrate-from-files-api-2025-04-14) and [Migrate from `skills-2025-10-02`](https://platform.claude.com/docs/en/build-with-claude/skills-guide#migrate-from-skills-2025-10-02). - -- You can now create **personal keys** and **service account keys** in the Claude Console. They act as you or as a [service account](https://platform.claude.com/docs/en/manage-claude/workload-identity-federation#service-accounts), with the same permissions, and stop working when the linked account is removed from an organization. This lets organization admins more easily track usage for each account, and ensure key usage is legitimate. These API keys can be scoped to a specific workspace or [work on admin endpoints and across any workspace](https://platform.claude.com/docs/en/manage-claude/authentication#select-a-workspace) the account has access to. Workspace API keys remain supported as a legacy option. See [API keys in Authentication](https://platform.claude.com/docs/en/manage-claude/authentication#api-keys) for more information. +* You can now create **personal keys** and **service account keys** in the Claude Console. They act as you or as a [service account](https://platform.claude.com/docs/en/manage-claude/workload-identity-federation#service-accounts), with the same permissions, and stop working when the linked account is removed from an organization. This lets organization admins more easily track usage for each account, and ensure key usage is legitimate. These API keys can be scoped to a specific workspace or [work on admin endpoints and across any workspace](https://platform.claude.com/docs/en/manage-claude/authentication#select-a-workspace) the account has access to. Workspace API keys remain supported as a legacy option. See [API keys in Authentication](https://platform.claude.com/docs/en/manage-claude/authentication#api-keys) for more information. ### August 26, 2026 diff --git a/content/github/claude-cookbooks/CLAUDE.md b/content/github/claude-cookbooks/CLAUDE.md index 864ddd034d..03ccb7ee2b 100644 --- a/content/github/claude-cookbooks/CLAUDE.md +++ b/content/github/claude-cookbooks/CLAUDE.md @@ -99,7 +99,7 @@ skills/ # Advanced skill-based notebooks tool_use/ # Tool use and integration patterns multimodal/ # Vision and image processing misc/ # Batch processing, caching, utilities -third_party/ # Pinecone, Voyage, Wikipedia integrations +third_party/ # Pinecone, Voyage, LlamaIndex integrations extended_thinking/ # Extended reasoning patterns scripts/ # Validation scripts .claude/ # Claude Code commands and skills diff --git a/content/github/claude-cookbooks/README.md b/content/github/claude-cookbooks/README.md index b6c1dee32e..9db54e5c33 100644 --- a/content/github/claude-cookbooks/README.md +++ b/content/github/claude-cookbooks/README.md @@ -42,7 +42,6 @@ If you have ideas for new examples or guides, share them on the [issues page](ht ### Third-Party Integrations - [Retrieval augmented generation](https://github.com/anthropics/anthropic-cookbook/tree/main/third_party): Supplement Claude's knowledge with external data sources. - [Vector databases (Pinecone)](https://github.com/anthropics/anthropic-cookbook/blob/main/third_party/Pinecone/rag_using_pinecone.ipynb) - - [Wikipedia](https://github.com/anthropics/anthropic-cookbook/blob/main/third_party/Wikipedia/wikipedia-search-cookbook.ipynb/) - [Web pages](https://github.com/anthropics/anthropic-cookbook/blob/main/misc/read_web_pages_with_haiku.ipynb) - [Embeddings with Voyage AI](https://github.com/anthropics/anthropic-cookbook/blob/main/third_party/VoyageAI/how_to_create_embeddings.md) @@ -62,6 +61,7 @@ If you have ideas for new examples or guides, share them on the [issues page](ht - [Create a moderation filter](https://github.com/anthropics/anthropic-cookbook/blob/main/misc/building_moderation_filter.ipynb): Use Claude to create a content moderation filter for your application. - [Prompt caching](https://github.com/anthropics/anthropic-cookbook/blob/main/misc/prompt_caching.ipynb): Learn techniques for efficient prompt caching with Claude. - [Cost optimization](https://github.com/anthropics/anthropic-cookbook/blob/main/cost_optimization/cost_optimization.ipynb): Work through a cost optimization checklist on an agent, measuring pass rate and cost per task to find the Pareto-optimal configuration. +- [Latency optimization](https://github.com/anthropics/anthropic-cookbook/blob/main/latency_optimization/latency_optimization.ipynb): Work through the latency levers on an agent, measuring time to first token, task time, and accuracy to pick the fastest configuration that clears your quality bar. ## Additional Resources diff --git a/content/github/claude-cookbooks/capabilities/content_moderation/guide.ipynb b/content/github/claude-cookbooks/capabilities/content_moderation/guide.ipynb index 24b98f7398..51490aff91 100644 --- a/content/github/claude-cookbooks/capabilities/content_moderation/guide.ipynb +++ b/content/github/claude-cookbooks/capabilities/content_moderation/guide.ipynb @@ -76,7 +76,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "e8055976", "metadata": {}, "outputs": [ @@ -87,7 +87,7 @@ "" ] }, - "execution_count": null, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -121,13 +121,13 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "id": "1d5c52fd", "metadata": {}, "outputs": [], "source": [ "%%capture\n", - "%pip install -U \"anthropic>=0.109.0\" python-dotenv\n", + "%pip install -U \"anthropic>=2.0.0\" python-dotenv\n", "\n", "import json\n", "import pathlib\n", @@ -171,7 +171,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "id": "9539e698", "metadata": {}, "outputs": [ @@ -230,7 +230,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "id": "fe9a4b5b", "metadata": {}, "outputs": [ @@ -368,7 +368,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "id": "7030c9ce", "metadata": {}, "outputs": [ @@ -476,7 +476,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "id": "44a7dd15", "metadata": {}, "outputs": [ @@ -560,7 +560,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "id": "5633f0c7", "metadata": {}, "outputs": [ @@ -570,21 +570,21 @@ "text": [ "round 0: clean\n", "\n", - "22 rules · 7 derived fields · 1 uncompilable\n", + "22 rules · 6 derived fields · 2 uncompilable\n", "\n", - "rule ids: 1.1a_alcohol_targeting_21, 1.1b_alcohol_responsibility_message, 1.1c_alcohol_under_25_depiction, 1.2a_gambling_targeting_18, 1.2b_gambling_age_badge, 1.2c_gambling_responsibility_message, 1.2d_gambling_guaranteed_winnings, 1.3a_credit_offer_apr_required, 1.3b_guaranteed_approval, 1.4a_before_after_imagery, 1.4b_medical_claim, 1.4c_weight_loss_minor_targeting, 2.1_superlative_claims_review, 2.2_competitor_reference_legal_review, 3.1a_text_coverage_high, 3.1b_text_coverage_medium, 3.2_advertiser_identification, 4.1_restricted_category_no_min_age, 4.2_apparent_minor_restricted_categories, 5.1_nj_gambling_helpline, 5.2_email_alcohol_gambling_prohibited, 5.3_self_serve_financial_review\n", + "rule ids: 1.1a_alcohol_targeting_21, 1.1b_alcohol_responsible_message, 1.1c_alcohol_no_under_25, 1.2a_gambling_targeting_18, 1.2b_gambling_age_badge, 1.2c_gambling_responsible_message, 1.2d_gambling_no_guaranteed_or_risk_free, 1.3a_financial_apr_required, 1.3b_financial_no_guaranteed_approval, 1.4a_no_before_after_imagery, 1.4b_no_medical_claims, 1.4c_weight_loss_targeting_18, 2.1_superlatives_review, 2.2_competitor_reference_review, 3.1a_text_coverage_high, 3.1b_text_coverage_medium, 3.2_advertiser_identified, 4.1_restricted_unset_min_age, 4.2_no_minors_restricted_categories, 5.1_nj_gambling_helpline, 5.2_no_alcohol_gambling_email, 5.3_self_serve_financial_review\n", "\n", "derived fields:\n", - " responsible_drinking_message_present: Does the creative (image text, headline, or body copy) carry a responsible-drinking message such as 'Drink Res\n", - " depicts_person_apparently_under_25: Looking at the people shown in the creative, does anyone appear to be under 25 years old? Answer true if at le\n", - " responsible_gambling_message_present: Does the creative include a problem-gambling helpline (e.g. a helpline phone number or gambling-help website) \n", - " guaranteed_winnings_or_risk_free_claim: Does the ad claim guaranteed winnings, guaranteed wins/profits, 'can't lose', 'risk-free bet', 'free bet with \n", - " credit_offer_shown: Does the ad show an interest rate, a monthly payment amount, or a promotional credit/financing offer (e.g. '0%\n", - " guaranteed_approval_claim: Does the ad state or imply guaranteed approval for credit/financing — e.g. 'guaranteed approval', 'everyone ap\n", - " gambler_helpline_1800_shown: Does the creative image display the 1-800-GAMBLER helpline number (in any formatting, e.g. '1-800-GAMBLER' or \n", + " responsible_drinking_message_present: Look at the creative image, headline, and body copy. Answer true if any of them carries a responsible-drinking\n", + " depicted_person_apparent_under_25: If the creative shows one or more real-looking people, answer true if any of them appears to be under 25 years\n", + " responsible_gambling_message_present: Look at the creative image, headline, and body copy. Answer true if they include a problem-gambling helpline (\n", + " guaranteed_winnings_or_risk_free_bet_claim: Look at the headline, body copy, and image text. Answer true if the ad claims or implies guaranteed winnings, \n", + " credit_terms_shown: Look at the headline, body copy, and image text. Answer true if the ad shows any of the following: an interest\n", + " guaranteed_approval_claim: Look at the headline, body copy, and image text. Answer true if the ad states or implies that credit, loan, or\n", "\n", "uncompilable:\n", - " [1.2] Gambling advertisers must hold a valid gaming license in every state the campaig… → Requires an external lookup of state gaming-license registries per advertiser and per targeted state\n" + " [1.2] Gambling advertisers must hold a valid gaming license in every state the campaig… → Checking this requires an external lookup of the advertiser's gaming licenses against a state licens\n", + " [1.2] Must target 18+ (21+ preferred).… → The '21+ preferred' part is a stated preference, not a requirement, so there is no violation to chec\n" ] } ], @@ -620,7 +620,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "id": "e97c63b0", "metadata": {}, "outputs": [ @@ -686,7 +686,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "id": "bcd0a652", "metadata": {}, "outputs": [ @@ -757,7 +757,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "id": "7b0cd5af", "metadata": {}, "outputs": [ @@ -786,7 +786,7 @@ " \"disclaimer_present\": true,\n", " \"disclaimer_text\": \"Gamble Responsibly.\",\n", " \"age_gate_shown\": 21,\n", - " \"text_coverage\": \"medium\",\n", + " \"text_coverage\": \"low\",\n", " \"before_after_imagery\": false,\n", " \"superlative_claims\": [],\n", " \"health_claim_present\": false,\n", @@ -835,7 +835,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "id": "a1365eb2", "metadata": {}, "outputs": [ @@ -845,8 +845,6 @@ "text": [ "── New Jersey placement:\n", "DECISION: BLOCK\n", - " ✗ [flag] 3.1b_text_coverage_medium\n", - " T text_coverage eq 'medium' (actual: 'medium')\n", " ✗ [block] 5.1_nj_gambling_helpline\n", " scope:\n", " T all:\n", @@ -859,10 +857,9 @@ " – out of scope: 1.1a_alcohol_targeting_21, 1.1b_alcohol_responsible_message, 1.1c_alcohol_no_under_25, 1.3a_finance_apr_required, 1.3b_finance_no_guaranteed_approval, 1.4c_weight_loss_targeting_18, 5.2_no_alcohol_gambling_email, 5.3_self_serve_finance_review\n", "\n", "── Same fields, California placement — zero model calls:\n", - "DECISION: FLAG\n", - " ✗ [flag] 3.1b_text_coverage_medium\n", - " T text_coverage eq 'medium' (actual: 'medium')\n", - " – out of scope: 1.1a_alcohol_targeting_21, 1.1b_alcohol_responsible_message, 1.1c_alcohol_no_under_25, 1.3a_finance_apr_required, 1.3b_finance_no_guaranteed_approval, 1.4c_weight_loss_targeting_18, 5.1_nj_gambling_helpline, 5.2_no_alcohol_gambling_email, 5.3_self_serve_finance_review\n" + "DECISION: APPROVE\n", + " – out of scope: 1.1a_alcohol_targeting_21, 1.1b_alcohol_responsible_message, 1.1c_alcohol_no_under_25, 1.3a_finance_apr_required, 1.3b_finance_no_guaranteed_approval, 1.4c_weight_loss_targeting_18, 5.1_nj_gambling_helpline, 5.2_no_alcohol_gambling_email, 5.3_self_serve_finance_review\n", + " ✓ all 13 applicable rules clear\n" ] } ], @@ -904,7 +901,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "id": "53eec22b", "metadata": {}, "outputs": [ @@ -913,19 +910,9 @@ "output_type": "stream", "text": [ "{\n", - " \"derived_fields\": {\n", - " \"signup_bonus_over_1000\": {\n", - " \"type\": [\n", - " \"boolean\",\n", - " \"null\"\n", - " ],\n", - " \"judge\": \"Look at the headline, body copy, and any text in the creative image. Answer true if the ad promotes a sign-up / welcome / new-customer / registration bonus (cash, credit, bonus funds, free bets, match bonus, or equivalent) whose stated maximum value is greater than $1000 (e.g. 'Get up to $1,500 in bonus bets when you sign up'). Answer false if a sign-up bonus is offered but its stated value is $1000 or less, or if the ad promotes no sign-up bonus at all. Answer null if a sign-up bonus is clearly offered but its monetary value cannot be determined from the content (e.g. 'huge welcome bonus' with no amount, or amount given only in a non-monetary unit you cannot convert).\",\n", - " \"source_policy\": \"custom\"\n", - " }\n", - " },\n", " \"rules\": [\n", " {\n", - " \"id\": \"custom_signup_bonus_over_1000_flag\",\n", + " \"id\": \"custom_signup_bonus_over_1000_review\",\n", " \"policy_ref\": \"custom\",\n", " \"policy_text\": \"Sign-up bonus offers greater than $1000 must be flagged for review.\",\n", " \"action\": \"flag\",\n", @@ -946,7 +933,7 @@ " {\n", " \"id\": \"custom_signup_bonus_over_1000_nj_block\",\n", " \"policy_ref\": \"custom\",\n", - " \"policy_text\": \"In New Jersey, sign-up bonus offers greater than $1000 are blocked outright.\",\n", + " \"policy_text\": \"Sign-up bonus offers greater than $1000 are blocked outright in New Jersey.\",\n", " \"action\": \"block\",\n", " \"uses_llm_fields\": true,\n", " \"scope\": {\n", @@ -960,7 +947,17 @@ " \"value\": true\n", " }\n", " }\n", - " ]\n", + " ],\n", + " \"derived_fields\": {\n", + " \"signup_bonus_over_1000\": {\n", + " \"type\": [\n", + " \"boolean\",\n", + " \"null\"\n", + " ],\n", + " \"judge\": \"Look at the headline, body copy, and all text in the creative image. Answer true if the ad offers a sign-up, welcome, new-customer, new-account, or first-deposit bonus whose stated value is greater than $1000. Examples include '$1,500 welcome bonus', 'up to $2000 bonus', and 'bonus bets worth $1,001'. For 'up to' offers, use the maximum stated amount. Convert non-USD amounts at an approximate rate. Answer false if the ad has no sign-up or welcome bonus, or if the stated bonus value is $1000 or less. Answer null if a sign-up bonus is offered but its monetary value cannot be determined from the ad, for example 'huge welcome bonus' with no amount, or a match percentage with no cap.\",\n", + " \"source_policy\": \"custom\"\n", + " }\n", + " }\n", "}\n", "\n", "ruleset v2: 24 rules\n" @@ -999,7 +996,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "id": "4ad335b5", "metadata": {}, "outputs": [ @@ -1024,7 +1021,7 @@ " scope:\n", " T state eq 'NJ' (actual: 'NJ')\n", " T signup_bonus_over_1000 eq True (actual: True)\n", - " – out of scope: 1.1a_alcohol_targeting_21, 1.1b_alcohol_responsible_message, 1.1c_alcohol_no_under_25, 1.3a_finance_apr_required, 1.3b_finance_no_guaranteed_approval, 1.4c_weight_loss_targeting_18, 5.2_no_alcohol_gambling_email, 5.3_self_serve_finance_review, custom_signup_bonus_over_1000_flag\n" + " – out of scope: 1.1a_alcohol_targeting_21, 1.1b_alcohol_responsible_message, 1.1c_alcohol_no_under_25, 1.3a_finance_apr_required, 1.3b_finance_no_guaranteed_approval, 1.4c_weight_loss_targeting_18, 5.2_no_alcohol_gambling_email, 5.3_self_serve_finance_review, custom_signup_bonus_over_1000_review\n" ] } ], @@ -1061,7 +1058,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "id": "6f258167", "metadata": {}, "outputs": [ @@ -1071,12 +1068,13 @@ "text": [ "═══ product_listings: 9 rules · sample: Rolex at $89, 'authentic'\n", " DECISION: BLOCK\n", - " ✗ [block] 3.1b_luxury_cheap_authentic_claim\n", - " T all:\n", - " T luxury_brand_mentioned exists (actual: 'Rolex')\n", - " T price_usd lt 100 (actual: 89.0)\n", - " T claims_authentic eq True (actual: True)\n", - " – out of scope: 4.1a_age_restricted_new_seller, 4.1b_age_restricted_eu, 4.2_new_seller_expensive_electronics \n", + " ✗ [block] 3.1b_luxury_low_price_authentic_claim\n", + " scope:\n", + " T all:\n", + " T luxury_brand_mentioned exists (actual: 'Rolex')\n", + " T price_usd lt 100 (actual: 89.0)\n", + " T claims_authentic eq True (actual: True)\n", + " – out of scope: 4.1a_blades_new_seller, 4.1b_blades_eu, 4.2_new_seller_high_value_electronics \n", "\n" ] }, @@ -1086,7 +1084,7 @@ "text": [ "═══ ugc: 7 rules · sample: Personal attack on the author\n", " DECISION: BLOCK\n", - " ✗ [block] 1.1_personal_attack\n", + " ✗ [block] 1.1_personal_attacks\n", " T personal_attack eq True (actual: True)\n", " – out of scope: 1.2b_profanity_forum, 3.2_new_account_links, 4.1_undisclosed_incentive \n", "\n" @@ -1154,7 +1152,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "id": "db3acaa4", "metadata": {}, "outputs": [ @@ -1183,14 +1181,14 @@ "name": "stdout", "output_type": "stream", "text": [ - " ✓ Loan rate without APR — self-serve expected block got block fired: 1.3a_finance_apr_required, 3.1b_text_coverage_medium, 5.3_self_serve_finance_review\n" + " ✓ Loan rate without APR — self-serve expected block got block fired: 1.3a_finance_apr_required, 5.3_self_serve_finance_review\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - " ✓ Skincare before/after expected block got block fired: 1.4a_no_before_after, 3.1b_text_coverage_medium\n" + " ✓ Skincare before/after expected block got block fired: 1.4a_no_before_after\n" ] }, { @@ -1211,7 +1209,7 @@ "name": "stdout", "output_type": "stream", "text": [ - " ✓ Weight-loss ad targeting teens expected block got block fired: 1.4b_no_health_claims, 1.4c_weight_loss_targeting_18, 2.1_superlatives_review, 3.1b_text_coverage_medium\n" + " ✓ Weight-loss ad targeting teens expected block got block fired: 1.4c_weight_loss_targeting_18, 2.1_superlatives_review, 3.1b_text_coverage_medium\n" ] }, { @@ -1249,35 +1247,35 @@ "name": "stdout", "output_type": "stream", "text": [ - " ✓ Rolex at $89, 'authentic' expected block got block fired: 3.1b_luxury_cheap_authentic_claim\n" + " ✓ Rolex at $89, 'authentic' expected block got block fired: 3.1b_luxury_low_price_authentic_claim\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - " ✓ Supplement that 'cures' insomnia expected block got block fired: 1.1_medical_claim, 1.2_fda_claim\n" + " ✓ Supplement that 'cures' insomnia expected block got block fired: 1.1_no_medical_claims, 1.2_no_fda_claims\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - " ✓ Seller asking for Venmo expected block got block fired: 2.1_contact_info, 2.2_offplatform_payment\n" + " ✓ Seller asking for Venmo expected block got block fired: 2.1_no_contact_info, 2.2_no_offplatform_payment\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - " ✓ Chef's knife from a new seller expected block got block fired: 4.1a_age_restricted_new_seller\n" + " ✓ Chef's knife from a new seller expected block got block fired: 4.1a_blades_new_seller\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - " ✓ New seller, $899 camera expected flag got flag fired: 4.2_new_seller_expensive_electronics\n", + " ✓ New seller, $899 camera expected flag got flag fired: 4.2_new_seller_high_value_electronics\n", " → 6/6\n", "\n", "═══ ugc — 6 of 6 samples\n" @@ -1294,7 +1292,7 @@ "name": "stdout", "output_type": "stream", "text": [ - " ✓ Personal attack on the author expected block got block fired: 1.1_personal_attack\n" + " ✓ Personal attack on the author expected block got block fired: 1.1_personal_attacks\n" ] }, { @@ -1315,7 +1313,7 @@ "name": "stdout", "output_type": "stream", "text": [ - " ✓ Doxxing attempt expected block got block fired: 1.1_personal_attack, 2.1_pii_exposure\n" + " ✓ Doxxing attempt expected block got block fired: 1.1_personal_attacks, 2.1_personal_information\n" ] }, { @@ -1425,8 +1423,16 @@ "name": "python3" }, "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", "name": "python", - "version": "3.11" + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.14" } }, "nbformat": 4, diff --git a/content/github/claude-cookbooks/capabilities/contextual-embeddings/guide.ipynb b/content/github/claude-cookbooks/capabilities/contextual-embeddings/guide.ipynb index e613d8a500..8ae3e8166d 100644 --- a/content/github/claude-cookbooks/capabilities/contextual-embeddings/guide.ipynb +++ b/content/github/claude-cookbooks/capabilities/contextual-embeddings/guide.ipynb @@ -796,7 +796,6 @@ " ],\n", " },\n", " ],\n", - " extra_headers={\"anthropic-beta\": \"prompt-caching-2024-07-31\"},\n", " )\n", " text = \"\".join(b.text for b in response.content if b.type == \"text\")\n", " return text, response.usage\n", diff --git a/content/github/claude-cookbooks/capabilities/summarization/guide.ipynb b/content/github/claude-cookbooks/capabilities/summarization/guide.ipynb index 67eb6766ba..22bc0480fb 100644 --- a/content/github/claude-cookbooks/capabilities/summarization/guide.ipynb +++ b/content/github/claude-cookbooks/capabilities/summarization/guide.ipynb @@ -105,8 +105,15 @@ " \"\"\"Concatenate the text blocks of a response.\n", "\n", " Current models may return a leading thinking block, so don't index content[0].\n", + " Raises if there is no text at all (e.g. the whole max_tokens budget went to thinking).\n", " \"\"\"\n", - " return \"\".join(block.text for block in response.content if block.type == \"text\")\n", + " text_blocks = [block.text for block in response.content if block.type == \"text\"]\n", + " if not text_blocks:\n", + " raise ValueError(\n", + " f\"No text block in response (stop_reason={response.stop_reason}); \"\n", + " \"if stop_reason is 'max_tokens', raise max_tokens.\"\n", + " )\n", + " return \"\".join(text_blocks)\n", "\n", "\n", "print(\"Setup complete!\")" @@ -203,7 +210,7 @@ "metadata": {}, "outputs": [], "source": [ - "def basic_summarize(text, max_tokens=1000):\n", + "def basic_summarize(text, max_tokens=8192):\n", " # Prompt the model to summarize the text\n", " prompt = f\"\"\"Summarize the following text in bullet points. Focus on the main ideas and key details:\n", " {text}\n", @@ -264,7 +271,7 @@ } ], "source": [ - "basic_response = basic_summarize(text, max_tokens=1000)\n", + "basic_response = basic_summarize(text, max_tokens=8192)\n", "\n", "print(basic_response)" ] @@ -304,7 +311,7 @@ "from data.multiple_subleases import document1, document2, document3, sample1, sample2, sample3\n", "\n", "\n", - "def basic_summarize_multishot(text, max_tokens=1000):\n", + "def basic_summarize_multishot(text, max_tokens=8192):\n", " # Prompt the model to summarize the text\n", " prompt = f\"\"\"Summarize the following text in bullet points. Focus on the main ideas and key details:\n", " {text}\n", @@ -413,7 +420,7 @@ } ], "source": [ - "basic_multishot_response = basic_summarize_multishot(text, max_tokens=1000)\n", + "basic_multishot_response = basic_summarize_multishot(text, max_tokens=8192)\n", "\n", "print(basic_multishot_response)" ] @@ -444,7 +451,7 @@ "metadata": {}, "outputs": [], "source": [ - "def guided_legal_summary(text, max_tokens=1000):\n", + "def guided_legal_summary(text, max_tokens=8192):\n", " # Prompt the model to summarize the text\n", " prompt = f\"\"\"Summarize the following legal document. Focus on these key aspects:\n", "\n", @@ -553,7 +560,7 @@ "metadata": {}, "outputs": [], "source": [ - "def guided_sublease_summary(text, model=\"claude-sonnet-5-5\", max_tokens=1000):\n", + "def guided_sublease_summary(text, model=\"claude-sonnet-5-5\", max_tokens=8192):\n", " # Prompt the model to summarize the sublease agreement\n", " prompt = f\"\"\"Summarize the following sublease agreement. Focus on these key aspects:\n", "\n", @@ -773,7 +780,7 @@ " return [text[i : i + chunk_size] for i in range(0, len(text), chunk_size)]\n", "\n", "\n", - "def summarize_long_document(text, max_tokens=2000):\n", + "def summarize_long_document(text, max_tokens=8192):\n", " chunks = chunk_text(text)\n", "\n", " # Iterate over chunks and summarize each one\n", @@ -904,7 +911,7 @@ "\n", " response = client.messages.create(\n", " model=\"claude-sonnet-5-5\",\n", - " max_tokens=1500,\n", + " max_tokens=8192,\n", " messages=[{\"role\": \"user\", \"content\": prompt}],\n", " stop_sequences=[\"\"],\n", " )\n", @@ -951,7 +958,7 @@ "\n", " response = client.messages.create(\n", " model=\"claude-sonnet-5-5\",\n", - " max_tokens=1000,\n", + " max_tokens=8192,\n", " messages=[{\"role\": \"user\", \"content\": prompt}],\n", " )\n", "\n", @@ -1262,7 +1269,7 @@ "import seaborn as sns\n", "\n", "%matplotlib inline\n", - "plt.style.use(\"seaborn\")\n", + "plt.style.use(\"seaborn-v0_8\")\n", "\n", "# Load the data\n", "df = pd.read_csv(\"data/results.csv\")\n", diff --git a/content/github/claude-cookbooks/claude_agent_sdk/00_The_one_liner_research_agent.ipynb b/content/github/claude-cookbooks/claude_agent_sdk/00_The_one_liner_research_agent.ipynb index 09728bd026..1dbe1d97d6 100644 --- a/content/github/claude-cookbooks/claude_agent_sdk/00_The_one_liner_research_agent.ipynb +++ b/content/github/claude-cookbooks/claude_agent_sdk/00_The_one_liner_research_agent.ipynb @@ -137,7 +137,7 @@ "messages = []\n", "async for msg in query(\n", " prompt=\"Research the latest trends in AI agents and give me a brief summary and relevant citiations links.\",\n", - " options=ClaudeAgentOptions(model=MODEL, allowed_tools=[\"WebSearch\"]),\n", + " options=ClaudeAgentOptions(model=MODEL, allowed_tools=[\"WebSearch\"], setting_sources=[]),\n", "):\n", " print_activity(msg)\n", " messages.append(msg)" @@ -290,6 +290,7 @@ "\n", "- `query()` creates a single-turn agent interaction (no conversation memory)\n", "- `allowed_tools=[\"WebSearch\"]` gives Claude permission to search the web without asking for approval\n", + "- `setting_sources=[]` keeps the run self-contained: since claude-agent-sdk 0.2 the SDK otherwise loads your user and project Claude Code settings (CLAUDE.md, MCP servers, hooks), just like the interactive CLI\n", "- The agent autonomously decides when to search, what queries to run, and how to synthesize results\n", "\n", "**Visualization utilities from `utils.agent_visualizer`:**\n", @@ -552,6 +553,7 @@ " system_prompt=RESEARCH_SYSTEM_PROMPT,\n", " allowed_tools=[\"WebSearch\", \"Read\"],\n", " max_buffer_size=10 * 1024 * 1024, # Increase to 10MB for image handling\n", + " setting_sources=[],\n", " )\n", ") as research_agent:\n", " # First query: Analyze the chart image\n", diff --git a/content/github/claude-cookbooks/claude_agent_sdk/01_The_chief_of_staff_agent.ipynb b/content/github/claude-cookbooks/claude_agent_sdk/01_The_chief_of_staff_agent.ipynb index eaf1940cb0..b1d6fffdf0 100644 --- a/content/github/claude-cookbooks/claude_agent_sdk/01_The_chief_of_staff_agent.ipynb +++ b/content/github/claude-cookbooks/claude_agent_sdk/01_The_chief_of_staff_agent.ipynb @@ -397,6 +397,7 @@ " model=MODEL,\n", " allowed_tools=[\"Bash\", \"Read\"],\n", " cwd=\"chief_of_staff_agent\", # Points to subdirectory where our agent is defined\n", + " setting_sources=[\"project\"],\n", " )\n", ") as agent:\n", " await agent.query(\n", @@ -1021,6 +1022,7 @@ " model=MODEL,\n", " permission_mode=\"plan\",\n", " cwd=\"chief_of_staff_agent\",\n", + " setting_sources=[\"project\"],\n", " )\n", ") as agent:\n", " await agent.query(PLAN_PROMPT)\n", @@ -1545,7 +1547,7 @@ "- You can add parameters to your prompt using `$ARGUMENTS` (for full argument string) or `$1`, `$2`, etc. (for positional arguments)\n", "- The user uses the slash command in their prompt\n", "\n", - "> **CRITICAL SDK CONFIGURATION**: When using the SDK, you **must** set `setting_sources=[\"project\"]` in your `ClaudeAgentOptions` for slash commands to work. By default, the SDK operates in isolation mode and does NOT load filesystem settings (slash commands, CLAUDE.md, subagents, hooks, etc.). This is different from using Claude Code interactively where these are loaded automatically." + "> **CRITICAL SDK CONFIGURATION**: When using the SDK, set `setting_sources` explicitly in your `ClaudeAgentOptions` so you control which filesystem settings (slash commands, CLAUDE.md, subagents, hooks, etc.) are loaded. `setting_sources=[\"project\"]` loads only this project's `.claude/` directory. Since claude-agent-sdk 0.2, leaving it unset loads every source, including your personal `~/.claude` settings, just like interactive Claude Code; pass `setting_sources=[]` to run in isolation." ] }, { @@ -1934,9 +1936,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Feature 6: Subagents via Task Tool\n", + "### Feature 6: Subagents via the Agent Tool\n", "\n", - "**What**: The Task tool enables your agent to delegate specialized work to other subagents. These subagents each have their own instructions, tools, and expertise.\n", + "**What**: The Agent tool (named `Task` before claude-agent-sdk 0.2; the old name is still accepted) enables your agent to delegate specialized work to other subagents. These subagents each have their own instructions, tools, and expertise.\n", "\n", "**Why**: Adding subagents opens up a lot of possibilities:\n", "1. Specialization: each subagent is an expert in their domain\n", @@ -1944,7 +1946,7 @@ "3. Parallellization: multiple subagents can work simultaneously on different aspects.\n", "\n", "**How**:\n", - "- Add `\"Task\"` to allowed_tools\n", + "- Add `\"Agent\"` to allowed_tools\n", "- Use a system prompt to instruct your agent how to delegate tasks (you can also define this its CLAUDE.md more generally)\n", "- Create a markdown file for each agent in `.claude/agents/`. For example, check the one for `.claude/agents/financial-analyst.md` and notice how a (sub)agent can be defined with such an easy and intuitive markdown file: frontmatter with three fields (name, description, and tools) and its system prompt. The description is useful for the main chief of staff agent to know when to invoke each subagent.\n", "\n", @@ -2189,7 +2191,7 @@ "async with ClaudeSDKClient(\n", " options=ClaudeAgentOptions(\n", " model=MODEL,\n", - " allowed_tools=[\"Task\"], # this enables our Chief agent to invoke subagents\n", + " allowed_tools=[\"Agent\"], # this enables our Chief agent to invoke subagents\n", " system_prompt=\"Delegate financial questions to the financial-analyst subagent. Do not try to answer these questions yourself.\",\n", " cwd=\"chief_of_staff_agent\",\n", " setting_sources=[\"project\", \"local\"],\n", @@ -2419,7 +2421,7 @@ "metadata": {}, "source": [ "Here, when our main agent decides to use a subagent, it will:\n", - " 1. Call the Task tool with parameters like:\n", + " 1. Call the Agent tool with parameters like:\n", " ```json\n", " {\n", " \"description\": \"Analyze hiring impact\",\n", @@ -2427,7 +2429,7 @@ " \"subagent_type\": \"financial-analyst\"\n", " }\n", " ```\n", - " 2. The Task tool executes the subagent in a separate context\n", + " 2. The Agent tool executes the subagent in a separate context\n", " 3. Return results to main Chief of Staff agent to continue processing" ] }, diff --git a/content/github/claude-cookbooks/claude_agent_sdk/02_The_observability_agent.ipynb b/content/github/claude-cookbooks/claude_agent_sdk/02_The_observability_agent.ipynb index a5f75609ca..281fbc756a 100644 --- a/content/github/claude-cookbooks/claude_agent_sdk/02_The_observability_agent.ipynb +++ b/content/github/claude-cookbooks/claude_agent_sdk/02_The_observability_agent.ipynb @@ -118,9 +118,11 @@ " model=\"claude-opus-5-5\",\n", " mcp_servers=git_mcp,\n", " allowed_tools=[\"mcp__git\"],\n", - " # disallowed_tools ensures the agent ONLY uses MCP tools, not Bash with git commands\n", - " disallowed_tools=[\"Bash\", \"Task\", \"WebSearch\", \"WebFetch\"],\n", + " # disallowed_tools ensures the agent ONLY uses MCP tools, not Bash with git commands.\n", + " # \"Agent\" is the subagent tool (named \"Task\" before claude-agent-sdk 0.2).\n", + " disallowed_tools=[\"Bash\", \"Agent\", \"WebSearch\", \"WebFetch\"],\n", " permission_mode=\"acceptEdits\",\n", + " setting_sources=[], # only the MCP servers configured here; no user/project settings\n", " )\n", ") as agent:\n", " await agent.query(\n", @@ -278,8 +280,9 @@ " mcp_servers=github_mcp,\n", " allowed_tools=[\"mcp__github\"],\n", " # disallowed_tools ensures the agent ONLY uses MCP tools, not Bash with gh CLI\n", - " disallowed_tools=[\"Bash\", \"Task\", \"WebSearch\", \"WebFetch\"],\n", + " disallowed_tools=[\"Bash\", \"Agent\", \"WebSearch\", \"WebFetch\"],\n", " permission_mode=\"acceptEdits\",\n", + " setting_sources=[],\n", " )\n", ") as agent:\n", " await agent.query(\n", @@ -433,8 +436,9 @@ " # IMPORTANT: disallowed_tools is required to actually RESTRICT tool usage.\n", " # Without this, allowed_tools only controls permission prompting, not availability.\n", " # The agent would still have access to Bash (and could use `gh` CLI instead of MCP).\n", - " disallowed_tools=[\"Bash\", \"Task\", \"WebSearch\", \"WebFetch\"],\n", + " disallowed_tools=[\"Bash\", \"Agent\", \"WebSearch\", \"WebFetch\"],\n", " permission_mode=\"acceptEdits\",\n", + " setting_sources=[],\n", " )\n", ") as agent:\n", " await agent.query(prompt)\n", diff --git a/content/github/claude-cookbooks/claude_agent_sdk/03_The_site_reliability_agent.ipynb b/content/github/claude-cookbooks/claude_agent_sdk/03_The_site_reliability_agent.ipynb index c07a358cc5..4a7172b759 100644 --- a/content/github/claude-cookbooks/claude_agent_sdk/03_The_site_reliability_agent.ipynb +++ b/content/github/claude-cookbooks/claude_agent_sdk/03_The_site_reliability_agent.ipynb @@ -775,6 +775,8 @@ " },\n", " permission_mode=\"acceptEdits\",\n", " model=MODEL,\n", + " # Keep the run self-contained: don't load user/project Claude Code settings.\n", + " setting_sources=[],\n", ")" ] }, diff --git a/content/github/claude-cookbooks/claude_agent_sdk/04_migrating_from_openai_agents_sdk.ipynb b/content/github/claude-cookbooks/claude_agent_sdk/04_migrating_from_openai_agents_sdk.ipynb index d8c7376ba3..901a8f6754 100644 --- a/content/github/claude-cookbooks/claude_agent_sdk/04_migrating_from_openai_agents_sdk.ipynb +++ b/content/github/claude-cookbooks/claude_agent_sdk/04_migrating_from_openai_agents_sdk.ipynb @@ -240,6 +240,10 @@ " system_prompt=expense_system_prompt,\n", " mcp_servers={\"expense\": policy_server},\n", " allowed_tools=[\"mcp__expense__check_policy\"],\n", + " # Be explicit: since claude-agent-sdk 0.2, leaving these unset loads your user and\n", + " # project Claude Code settings and lets the CLI choose the permission mode.\n", + " setting_sources=[],\n", + " permission_mode=\"default\",\n", ")" ] }, @@ -331,6 +335,8 @@ " mcp_servers={\"expense\": policy_server},\n", " allowed_tools=[\"mcp__expense__check_policy\"],\n", " hooks={\"UserPromptSubmit\": [HookMatcher(hooks=[has_dollar_amount_hook])]},\n", + " setting_sources=[],\n", + " permission_mode=\"default\",\n", ")" ] }, @@ -827,6 +833,8 @@ " mcp_servers={\"expense\": policy_server},\n", " allowed_tools=[\"Agent\", \"mcp__expense__check_policy\"],\n", " agents={\"approver\": approver, \"escalator\": escalator},\n", + " setting_sources=[],\n", + " permission_mode=\"default\",\n", ")\n", "\n", "print(f\"Orchestrator configured with subagents: {list(triage_options.agents)}\")\n", diff --git a/content/github/claude-cookbooks/claude_agent_sdk/05_Building_a_session_browser.ipynb b/content/github/claude-cookbooks/claude_agent_sdk/05_Building_a_session_browser.ipynb index 684e1ab392..8726ec25a0 100644 --- a/content/github/claude-cookbooks/claude_agent_sdk/05_Building_a_session_browser.ipynb +++ b/content/github/claude-cookbooks/claude_agent_sdk/05_Building_a_session_browser.ipynb @@ -48,9 +48,16 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "9a63283cbaf04dbcab1f6479b197f3a8", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:50:46.349175Z", + "iopub.status.busy": "2026-10-21T16:50:46.349062Z", + "iopub.status.idle": "2026-10-21T16:50:46.516409Z", + "shell.execute_reply": "2026-10-21T16:50:46.515674Z" + } + }, "outputs": [], "source": [ "%%capture\n", @@ -67,10 +74,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "72eea5119410473aa328ad9291626812", - "metadata": {}, - "outputs": [], + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:50:46.518464Z", + "iopub.status.busy": "2026-10-21T16:50:46.518252Z", + "iopub.status.idle": "2026-10-21T16:50:46.524176Z", + "shell.execute_reply": "2026-10-21T16:50:46.523772Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Demo project dir: /path/to/claude-cookbooks/claude_agent_sdk/session_browser_demo\n" + ] + } + ], "source": [ "import os\n", "from pathlib import Path\n", @@ -106,9 +128,16 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "10185d26023b46108eb7d9f57d49d2b3", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:50:46.525393Z", + "iopub.status.busy": "2026-10-21T16:50:46.525205Z", + "iopub.status.idle": "2026-10-21T16:50:47.583607Z", + "shell.execute_reply": "2026-10-21T16:50:47.583005Z" + } + }, "outputs": [], "source": [ "from claude_agent_sdk import ClaudeAgentOptions, ResultMessage, query\n", @@ -121,6 +150,8 @@ " cwd=DEMO_DIR,\n", " max_turns=1,\n", " allowed_tools=[], # text-only, no tool loop\n", + " setting_sources=[], # self-contained: don't load user/project settings\n", + " permission_mode=\"default\",\n", " )\n", " session_id = None\n", " async for msg in query(prompt=prompt, options=opts):\n", @@ -143,10 +174,45 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "7623eae2785240b9bd12b16a66d81610", - "metadata": {}, - "outputs": [], + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:50:47.585545Z", + "iopub.status.busy": "2026-10-21T16:50:47.585400Z", + "iopub.status.idle": "2026-10-21T16:50:58.732607Z", + "shell.execute_reply": "2026-10-21T16:50:58.731953Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[54b0d2d8] Here are three name ideas for a git worktree management CLI tool:\n", + "\n", + "1. **Roots** ...\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[9bc70b72] A **mutex** (mutual exclusion lock) is a synchronization primitive that allows o...\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[7146a49b] Merge conflicts arise\n", + "Both versions now fight for truth\n", + "Rebase fixes all...\n", + "\n", + "Created 3 sessions.\n" + ] + } + ], "source": [ "prompts = [\n", " \"Give me three name ideas for a CLI tool that manages git worktrees.\",\n", @@ -178,10 +244,91 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "b118ea5561624da68c537baed56e602f", - "metadata": {}, - "outputs": [], + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:50:58.734477Z", + "iopub.status.busy": "2026-10-21T16:50:58.734262Z", + "iopub.status.idle": "2026-10-21T16:50:58.945979Z", + "shell.execute_reply": "2026-10-21T16:50:58.945614Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idsummarymodifiedbranchtag
07146a49bWrite a haiku about merge conflicts.16:50:58main-
19bc70b72Explain the difference between a mutex and a s...16:50:54main-
254b0d2d8Give me three name ideas for a CLI tool that m...16:50:52main-
\n", + "
" + ], + "text/plain": [ + " id summary modified \\\n", + "0 7146a49b Write a haiku about merge conflicts. 16:50:58 \n", + "1 9bc70b72 Explain the difference between a mutex and a s... 16:50:54 \n", + "2 54b0d2d8 Give me three name ideas for a CLI tool that m... 16:50:52 \n", + "\n", + " branch tag \n", + "0 main - \n", + "1 main - \n", + "2 main - " + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from datetime import datetime\n", "\n", @@ -223,10 +370,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "504fb2a444614c0babb325280ed9130a", - "metadata": {}, - "outputs": [], + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:50:58.948031Z", + "iopub.status.busy": "2026-10-21T16:50:58.947882Z", + "iopub.status.idle": "2026-10-21T16:50:58.951725Z", + "shell.execute_reply": "2026-10-21T16:50:58.951014Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Session: 54b0d2d8-2cdc-45f6-9888-8951545c93c2\n", + "Summary: Give me three name ideas for a CLI tool that manages git worktrees.\n", + "First prompt: Give me three name ideas for a CLI tool that manages git worktrees.\n", + "Created: 2026-10-21 16:50:47.943000\n", + "Size: 166,035 bytes\n" + ] + } + ], "source": [ "from claude_agent_sdk import get_session_info\n", "\n", @@ -253,10 +419,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "b43b363d81ae4b689946ece5c682cd59", - "metadata": {}, - "outputs": [], + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:50:58.953633Z", + "iopub.status.busy": "2026-10-21T16:50:58.953500Z", + "iopub.status.idle": "2026-10-21T16:50:58.958893Z", + "shell.execute_reply": "2026-10-21T16:50:58.958349Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[ user] \n", + "[assistant] \n", + "[assistant] Here are three name ideas for a git worktree management CLI tool:\n", + "\n", + "1. **Roots** — Simple, memorable,\n" + ] + } + ], "source": [ "from claude_agent_sdk import get_session_messages\n", "\n", @@ -298,10 +483,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "4dd4641cc4064e0191573fe9c69df29b", - "metadata": {}, - "outputs": [], + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:50:58.960569Z", + "iopub.status.busy": "2026-10-21T16:50:58.960451Z", + "iopub.status.idle": "2026-10-21T16:50:58.968657Z", + "shell.execute_reply": "2026-10-21T16:50:58.967921Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "54b0d2d8 custom_title='Worktree CLI naming brainstorm' summary='Worktree CLI naming brainstorm'\n", + "7146a49b custom_title='Haiku corner' summary='Haiku corner'\n", + "9bc70b72 custom_title='(auto)' summary='Explain the difference between a mutex a'\n" + ] + } + ], "source": [ "from claude_agent_sdk import rename_session\n", "\n", @@ -328,10 +530,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "3ed186c9a28b402fb0bc4494df01f08d", - "metadata": {}, - "outputs": [], + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:50:58.970038Z", + "iopub.status.busy": "2026-10-21T16:50:58.969912Z", + "iopub.status.idle": "2026-10-21T16:50:58.978505Z", + "shell.execute_reply": "2026-10-21T16:50:58.977728Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Visible favorites: 2\n", + " 54b0d2d8 [favorite] Worktree CLI naming brainstorm\n", + " 7146a49b [favorite] Haiku corner\n" + ] + } + ], "source": [ "from claude_agent_sdk import tag_session\n", "\n", @@ -383,10 +602,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "277c27b1587741f2af2001be3712ef0d", - "metadata": {}, - "outputs": [], + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:50:58.979854Z", + "iopub.status.busy": "2026-10-21T16:50:58.979734Z", + "iopub.status.idle": "2026-10-21T16:50:58.986563Z", + "shell.execute_reply": "2026-10-21T16:50:58.985748Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Source: 54b0d2d8-2cdc-45f6-9888-8951545c93c2\n", + "Fork: 21100fd5-9fad-4f9f-bd06-7c430084e1b3\n", + "Source has 3 messages, fork has 3\n" + ] + } + ], "source": [ "from claude_agent_sdk import fork_session\n", "\n", @@ -421,16 +657,42 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "916684f9a58a4a2aa5f864670399430d", - "metadata": {}, - "outputs": [], + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:50:58.987858Z", + "iopub.status.busy": "2026-10-21T16:50:58.987743Z", + "iopub.status.idle": "2026-10-21T16:51:09.971658Z", + "shell.execute_reply": "2026-10-21T16:51:09.970867Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[fork 21100fd5 resumed]\n", + "Here are three punnier names for a git worktree management CLI tool:\n", + "\n", + "1. **Root Beer** — A play on the beverage and managing multiple \"roots\" of worktrees. Catchy and memorable: `root-beer checkout`, `root-beer list`.\n", + "\n", + "2. **Rebase-ment** — A pun combining \"rebase\" (a git operation) with \"basement\" (a foundation/lower level). Perfect for a dev-audience that appreciates git puns: `rebase-ment add`, `rebase-ment clean`.\n", + "\n", + "3. **Leaf It** — A wordplay on \"leave it\" and \"leaf\" (tree part). Lighthearted and punny: `leaf-it create`, `leaf-it switch`. Bonus: the repo could have a leaf emoji in the docs.\n", + "\n", + "**My pick:** **Rebase-ment** — it's the cleverest for a developer audience, and it actually describes the tool's function (managing the base/foundation of your worktrees).\n" + ] + } + ], "source": [ "resume_opts = ClaudeAgentOptions(\n", " model=MODEL,\n", " cwd=DEMO_DIR,\n", " max_turns=1,\n", " allowed_tools=[],\n", + " setting_sources=[],\n", + " permission_mode=\"default\",\n", " resume=fork.session_id,\n", ")\n", "\n", @@ -453,10 +715,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "id": "33b0902fd34d4ace834912fa1002cf8e", - "metadata": {}, - "outputs": [], + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:51:09.973081Z", + "iopub.status.busy": "2026-10-21T16:51:09.972949Z", + "iopub.status.idle": "2026-10-21T16:51:09.981766Z", + "shell.execute_reply": "2026-10-21T16:51:09.981162Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(fork) 21100fd5 Worktree CLI names (round 2)\n", + " 54b0d2d8 Worktree CLI naming brainstorm\n", + " 9bc70b72 Explain the difference between a mutex and a semap\n", + " 7146a49b Haiku corner\n" + ] + } + ], "source": [ "for s in list_sessions(directory=DEMO_DIR):\n", " marker = \"(fork)\" if s.session_id == fork.session_id else \" \"\n", @@ -477,10 +757,30 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "id": "f5a1fa73e5044315a093ec459c9be902", - "metadata": {}, - "outputs": [], + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:51:09.982785Z", + "iopub.status.busy": "2026-10-21T16:51:09.982674Z", + "iopub.status.idle": "2026-10-21T16:51:09.994174Z", + "shell.execute_reply": "2026-10-21T16:51:09.993813Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Deleted 21100fd5\n", + "Deleted 54b0d2d8\n", + "Deleted 9bc70b72\n", + "Deleted 7146a49b\n", + "\n", + "0 session(s) remaining.\n" + ] + } + ], "source": [ "from claude_agent_sdk import delete_session\n", "\n", @@ -534,7 +834,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.9" + "version": "3.12.14" } }, "nbformat": 4, diff --git a/content/github/claude-cookbooks/claude_agent_sdk/06_The_vulnerability_detection_agent.ipynb b/content/github/claude-cookbooks/claude_agent_sdk/06_The_vulnerability_detection_agent.ipynb index 614d49b4d2..6eee79a6f3 100644 --- a/content/github/claude-cookbooks/claude_agent_sdk/06_The_vulnerability_detection_agent.ipynb +++ b/content/github/claude-cookbooks/claude_agent_sdk/06_The_vulnerability_detection_agent.ipynb @@ -407,6 +407,9 @@ " allowed_tools=[\"Read\", \"Write\", \"Edit\"],\n", " disallowed_tools=[\"Bash\"],\n", " permission_mode=\"acceptEdits\",\n", + " # Explicit isolation: since claude-agent-sdk 0.2, leaving setting_sources unset\n", + " # loads user and project Claude Code settings into the run.\n", + " setting_sources=[],\n", ")\n", "\n", "async with ClaudeSDKClient(options=tm_options) as tm_agent:\n", @@ -534,6 +537,8 @@ " system_prompt={\"type\": \"preset\", \"preset\": \"claude_code\", \"append\": ENGAGEMENT_CONTEXT},\n", " allowed_tools=[\"Read\", \"Grep\", \"Glob\"],\n", " disallowed_tools=[\"Bash\"],\n", + " permission_mode=\"default\",\n", + " setting_sources=[],\n", ")\n", "\n", "findings_text = await collect(query(prompt=FIND_PROMPT, options=find_options))\n", @@ -610,6 +615,8 @@ " system_prompt={\"type\": \"preset\", \"preset\": \"claude_code\", \"append\": ENGAGEMENT_CONTEXT},\n", " allowed_tools=[\"Read\", \"Grep\"],\n", " disallowed_tools=[\"Bash\"],\n", + " permission_mode=\"default\",\n", + " setting_sources=[],\n", ")\n", "\n", "triaged_text = await collect(query(prompt=TRIAGE_PROMPT, options=triage_options))\n", @@ -717,6 +724,8 @@ " model=MODEL_NAME,\n", " system_prompt={\"type\": \"preset\", \"preset\": \"claude_code\", \"append\": ENGAGEMENT_CONTEXT},\n", " allowed_tools=[],\n", + " permission_mode=\"default\",\n", + " setting_sources=[],\n", ")\n", "\n", "report_json = await collect(query(prompt=REPORT_PROMPT, options=report_options))\n", diff --git a/content/github/claude-cookbooks/claude_agent_sdk/07_Hosting_the_agent.ipynb b/content/github/claude-cookbooks/claude_agent_sdk/07_Hosting_the_agent.ipynb index c3fab77d12..48fd8afbae 100644 --- a/content/github/claude-cookbooks/claude_agent_sdk/07_Hosting_the_agent.ipynb +++ b/content/github/claude-cookbooks/claude_agent_sdk/07_Hosting_the_agent.ipynb @@ -47,7 +47,7 @@ "\n", "- A **process** is one running Python interpreter with the SDK loaded. It talks to the Anthropic API.\n", "- A **session** is one conversation: the prompt history, tool calls, and results that the SDK writes to disk so you can `resume=` it later.\n", - "- A **container** is a packaged process plus its filesystem: your agent code, the SDK, Node, and a place for sessions to live.\n", + "- A **container** is a packaged process plus its filesystem: your agent code, the SDK (which bundles the Claude Code CLI it drives), and a place for sessions to live.\n", "\n", "Unlike in-process SDKs (OpenAI Agents SDK, Google ADK) where an \"agent\" is an object you instantiate inside your web server, a Claude Agent SDK agent **is** a process. That makes isolation trivial (one container = one blast radius) but means hosting is a distributed-systems problem, not a `pip install` problem.\n", "\n", diff --git a/content/github/claude-cookbooks/claude_agent_sdk/08_Dynamic_workflows.ipynb b/content/github/claude-cookbooks/claude_agent_sdk/08_Dynamic_workflows.ipynb index c53a0d0603..4b08b1a2ed 100644 --- a/content/github/claude-cookbooks/claude_agent_sdk/08_Dynamic_workflows.ipynb +++ b/content/github/claude-cookbooks/claude_agent_sdk/08_Dynamic_workflows.ipynb @@ -64,7 +64,14 @@ "cell_type": "code", "execution_count": 1, "id": "62c1e950", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:51:57.141091Z", + "iopub.status.busy": "2026-10-21T16:51:57.140973Z", + "iopub.status.idle": "2026-10-21T16:51:57.297499Z", + "shell.execute_reply": "2026-10-21T16:51:57.296231Z" + } + }, "outputs": [], "source": [ "%%capture\n", @@ -75,13 +82,20 @@ "cell_type": "code", "execution_count": 2, "id": "aa22411a", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:51:57.299530Z", + "iopub.status.busy": "2026-10-21T16:51:57.299381Z", + "iopub.status.idle": "2026-10-21T16:51:58.356340Z", + "shell.execute_reply": "2026-10-21T16:51:58.355569Z" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "claude-agent-sdk 0.2.125\n" + "claude-agent-sdk 0.2.168\n" ] } ], @@ -144,7 +158,14 @@ "cell_type": "code", "execution_count": 3, "id": "64dcb526", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:51:58.358427Z", + "iopub.status.busy": "2026-10-21T16:51:58.358262Z", + "iopub.status.idle": "2026-10-21T16:51:58.363216Z", + "shell.execute_reply": "2026-10-21T16:51:58.362473Z" + } + }, "outputs": [ { "name": "stdout", @@ -292,7 +313,14 @@ "cell_type": "code", "execution_count": 4, "id": "8eb0fa67", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:51:58.364687Z", + "iopub.status.busy": "2026-10-21T16:51:58.364567Z", + "iopub.status.idle": "2026-10-21T16:51:58.371405Z", + "shell.execute_reply": "2026-10-21T16:51:58.370737Z" + } + }, "outputs": [], "source": [ "# The Workflow tool result mentions the persisted script path and task ID in plain\n", @@ -383,6 +411,7 @@ " allowed_tools=[\"Read\", \"Write\", \"Edit\", \"Glob\", \"Grep\", \"Workflow\"],\n", " permission_mode=\"acceptEdits\",\n", " max_turns=40,\n", + " setting_sources=[], # self-contained: don't load user/project Claude Code settings\n", " )" ] }, @@ -409,41 +438,20 @@ "cell_type": "code", "execution_count": 5, "id": "7c42e502", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:51:58.380286Z", + "iopub.status.busy": "2026-10-21T16:51:58.380118Z", + "iopub.status.idle": "2026-10-21T16:53:16.967083Z", + "shell.execute_reply": "2026-10-21T16:53:16.966566Z" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - " -> Bash\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " -> Read\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " -> Read\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " -> Read\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " -> Read\n" + " -> Skill\n" ] }, { @@ -451,8 +459,8 @@ "output_type": "stream", "text": [ "\n", - "[Workflow tool] Claude wrote a 152-line orchestration script\n", - "[Launched] Workflow running in the background (task wr1292rh8)\n" + "[Workflow tool] Claude wrote a 79-line orchestration script\n", + "[Launched] Workflow running in the background (task wl0y94urk)\n" ] }, { @@ -460,63 +468,56 @@ "output_type": "stream", "text": [ "\n", - "Claude: The fact-check workflow is running in the background (task `wr1292rh8`, run `wf_1072dc96-6a2`). It's fanning out: extract the 10 claims → verify each in parallel against `sources/` → adversarially re-check every \"confirmed\" verdict → compile the final markdown report. I'll let you know as soon as it completes.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ... 8 agent tool calls | 304,709 tokens | 13s\n" + "Claude: The fact-check workflow is running in the background (run ID `wf_1f07705a-65b`). It has four stages:\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - " ... 16 agent tool calls | 371,890 tokens | 13s\n" + " ... 9 agent tool calls | 38,330 tokens | 12s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - " ... 24 agent tool calls | 371,890 tokens | 14s\n" + " ... 17 agent tool calls | 65,728 tokens | 19s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - " ... 32 agent tool calls | 384,996 tokens | 17s\n" + " ... 25 agent tool calls | 93,097 tokens | 27s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - " ... 40 agent tool calls | 469,806 tokens | 23s\n" + " ... 33 agent tool calls | 132,471 tokens | 35s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - " ... 48 agent tool calls | 543,126 tokens | 30s\n" + " ... 41 agent tool calls | 171,435 tokens | 43s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - " ... 56 agent tool calls | 549,412 tokens | 42s\n" + " ... 50 agent tool calls | 198,723 tokens | 52s\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "[Completed] Dynamic workflow \"Fact-check the OrbitCart investor update against source documents\" completed\n" + "[Completed] Dynamic workflow \"Extract, verify, skeptic-check, and report on claims in investor_update.md\" completed\n" ] }, { @@ -524,15 +525,9 @@ "output_type": "stream", "text": [ "\n", - "Claude: The fact-check workflow finished. Here's the report:\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "Claude: The workflow finished. Of the ten claims, four are contradicted, two are unverifiable, and four are confirmed (some with wording caveats). The skeptic upheld all four confirmations, so none were flipped to contradicted.\n", "\n", - "=== Run complete in 2.5 min | $3.29 ===\n" + "=== Run complete in 1.3 min | $0.60 ===\n" ] } ], @@ -577,41 +572,48 @@ "cell_type": "code", "execution_count": 6, "id": "e491550e", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:53:16.968786Z", + "iopub.status.busy": "2026-10-21T16:53:16.968607Z", + "iopub.status.idle": "2026-10-21T16:53:16.973131Z", + "shell.execute_reply": "2026-10-21T16:53:16.972714Z" + } + }, "outputs": [ { "data": { "text/markdown": [ - "The fact-check workflow finished. Here's the report:\n", - "\n", - "# OrbitCart Q2 2026 Investor Update — Fact-Check Report\n", + "The workflow finished. Of the ten claims, four are contradicted, two are unverifiable, and four are confirmed (some with wording caveats). The skeptic upheld all four confirmations, so none were flipped to contradicted.\n", "\n", - "## Claim-by-Claim Verification\n", - "\n", - "| # | Claim | Verdict | Evidence |\n", + "| # | Claim | Verdict | Correct figure or issue |\n", "|---|---|---|---|\n", - "| 1 | Revenue $4.8M, up 42% from Q1 | ❌ Contradicted | `monthly_sales.csv`: Q2 = $1.48M+$1.52M+$1.61M = **$4.61M**; Q1 = $3.6M → growth ≈ **28%**, not 42% |\n", - "| 2 | Over 38,000 orders | ✅ Confirmed | `monthly_sales.csv`: 12,800+12,400+13,200 = **38,400 orders** |\n", - "| 3 | Active customers 12,400 | ✅ Confirmed | `customer_survey.txt`: \"Active customers at end of Q2: 12,400\" |\n", - "| 4 | NPS of 71 | ❌ Contradicted | `customer_survey.txt`: \"Net Promoter Score (NPS): **62** (Q1: 58)\" |\n", - "| 5 | 99.99% uptime | ❌ Contradicted | `uptime_report.txt`: \"Quarter average: **99.71%**\" (May was only 99.18%, with a 5h58m outage) |\n", - "| 6 | TechPedal: \"the fastest-growing cycling retailer in North America\" | ❌ Contradicted | `press_coverage.md` actual quote: \"**one of** the fastest-growing **online** cycling retailers in North America\" — misquoted, overstated |\n", - "| 7 | June flash sale = biggest sales day in company history | ⚠️ Unverifiable | No source has daily/flash-sale data |\n", - "| 8 | Support resolution under 4 hours | ⚠️ Unverifiable | No source mentions resolution time |\n", - "| 9 | 3 new product categories launched | ✅ Confirmed | `press_coverage.md`: bike maintenance tools, indoor training equipment, cycling apparel |\n", - "| 10 | \"Brief\" May interruption, zero data lost | ❌ Contradicted (framing) | `uptime_report.txt`: outage lasted **5h 58m** — not \"brief\"; the \"zero data lost\" part is accurate |\n", + "| 1 | Q2 revenue $4.8M, up 42% | Contradicted | $4.61M, up about 28% from Q1's $3.60M (`sources/monthly_sales.csv`) |\n", + "| 2 | Over 38,000 orders | Confirmed | 38,400 orders in Q2 |\n", + "| 3 | Active customers grew to 12,400 | Confirmed | 12,400 matches `sources/customer_survey.txt`, but no source gives a prior-period count, so \"grew\" isn't verified |\n", + "| 4 | NPS of 71 | Contradicted | NPS is 62, up from 58 in Q1 (`sources/customer_survey.txt`) |\n", + "| 5 | 99.99% uptime | Contradicted | Quarter average is 99.71% (`sources/uptime_report.txt`) |\n", + "| 6 | TechPedal called us \"the fastest-growing cycling retailer in North America\" | Contradicted | The source says \"one of the fastest-growing online cycling retailers in North America\" (`sources/press_coverage.md`) |\n", + "| 7 | June flash sale was the biggest sales day ever | Unverifiable | Only monthly totals exist, and no source mentions a flash sale |\n", + "| 8 | Support resolution time under 4 hours | Unverifiable | No source covers resolution time. The 4.4/5 CSAT score is a different metric |\n", + "| 9 | Launched 3 new product categories | Confirmed | The press article says \"recently expanded into\" three categories, not \"launched\" them, and gives no dates |\n", + "| 10 | Zero customer data lost in the brief May interruption | Confirmed | The source says checkout was degraded for 5h 58m on May 14 and no customer data was lost. \"Brief\" and \"service interruption\" overstate or misdescribe that |\n", "\n", - "## Summary — must fix before sending\n", + "**Must fix before sending**\n", + "- **Claim 1:** Change to $4.61M, up about 28%.\n", + "- **Claim 4:** Change to NPS 62, up from 58.\n", + "- **Claim 5:** Change to 99.71% average uptime, and consider disclosing the May 14 checkout degradation.\n", + "- **Claim 6:** Use the exact quote, \"one of the fastest-growing online cycling retailers in North America\".\n", "\n", - "- **#1 Revenue:** correct to **$4.61M, +28% QoQ** (not $4.8M/42%)\n", - "- **#4 NPS:** correct to **62** (not 71)\n", - "- **#5 Uptime:** correct to **99.71% average** (not 99.99%); consider disclosing the May 14 outage\n", - "- **#6 Press quote:** fix misquote — TechPedal said \"one of the fastest-growing **online** cycling retailers,\" not \"the fastest-growing cycling retailer\"\n", - "- **#10 Framing:** the outage was **~6 hours**, not \"brief\" — reword (data-loss claim itself is accurate)\n", - "- **#7 Flash sale:** no supporting source — provide data or remove/soften\n", - "- **#8 Support time:** no supporting source — provide data or remove/soften\n", + "**Wording tweaks**\n", + "- **Claim 3:** Drop \"grew\" or add a source for the prior customer count.\n", + "- **Claim 9:** Use \"expanded into\" rather than \"launched\".\n", + "- **Claim 10:** Say \"no customer data was lost during the May 14 checkout degradation\".\n", + "- **Claim 2:** Fine as written, though you could state 38,400.\n", "\n", - "**Safe as-is:** #2 (38,400 orders), #3 (12,400 customers), #9 (3 new categories)." + "**Needs a source or removal**\n", + "- **Claim 7:** Provide daily sales records or cut it.\n", + "- **Claim 8:** Provide helpdesk resolution-time data or cut it." ], "text/plain": [ "" @@ -660,165 +662,98 @@ "cell_type": "code", "execution_count": 7, "id": "9a8f8610", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:53:16.974539Z", + "iopub.status.busy": "2026-10-21T16:53:16.974427Z", + "iopub.status.idle": "2026-10-21T16:53:16.977178Z", + "shell.execute_reply": "2026-10-21T16:53:16.976832Z" + } + }, "outputs": [ { "data": { "text/markdown": [ "```javascript\n", "export const meta = {\n", - " name: 'orbitcart-fact-check',\n", - " description: 'Fact-check the OrbitCart investor update against source documents',\n", - " phases: [\n", - " { title: 'Extract' },\n", - " { title: 'Verify' },\n", - " { title: 'Skeptic' },\n", - " { title: 'Report' },\n", - " ],\n", + " name: 'factcheck-investor-update',\n", + " description: 'Extract, verify, skeptic-check, and report on claims in investor_update.md',\n", + " phases: [{ title: 'Extract' }, { title: 'Verify' }, { title: 'Skeptic' }, { title: 'Report' }],\n", "}\n", "\n", - "const EXTRACT_SCHEMA = {\n", + "const EXTRACT = {\n", " type: 'object',\n", " properties: {\n", " claims: {\n", " type: 'array',\n", " items: {\n", " type: 'object',\n", - " properties: {\n", - " number: { type: 'integer' },\n", - " text: { type: 'string' },\n", - " },\n", + " properties: { number: { type: 'integer' }, text: { type: 'string' } },\n", " required: ['number', 'text'],\n", " },\n", " },\n", " },\n", " required: ['claims'],\n", "}\n", - "\n", - "const VERIFY_SCHEMA = {\n", + "const VERDICT = {\n", " type: 'object',\n", " properties: {\n", - " number: { type: 'integer' },\n", - " text: { type: 'string' },\n", " verdict: { type: 'string', enum: ['confirmed', 'contradicted', 'unverifiable'] },\n", - " source_file: { type: 'string', description: 'relative path of the source file relied on, or empty string' },\n", - " quote: { type: 'string', description: 'exact quoted line(s) from the source relied on; empty string if unverifiable' },\n", - " correct_figure: { type: 'string', description: 'the correct figure/fact per the source, only if contradicted; else empty string' },\n", - " reasoning: { type: 'string' },\n", + " source_file: { type: 'string' },\n", + " quote: { type: 'string', description: 'Exact line(s) relied on' },\n", + " correct_figure: { type: 'string' },\n", + " explanation: { type: 'string' },\n", " },\n", - " required: ['number', 'text', 'verdict', 'source_file', 'quote', 'correct_figure', 'reasoning'],\n", + " required: ['verdict', 'explanation'],\n", "}\n", - "\n", - "const SKEPTIC_SCHEMA = {\n", + "const SKEPTIC = {\n", " type: 'object',\n", " properties: {\n", - " number: { type: 'integer' },\n", - " final_verdict: { type: 'string', enum: ['confirmed', 'contradicted'] },\n", - " source_file: { type: 'string' },\n", + " supported: { type: 'boolean' },\n", + " correct_figure: { type: 'string' },\n", " quote: { type: 'string' },\n", - " correct_figure: { type: 'string', description: 'only if downgraded to contradicted; else empty string' },\n", - " reasoning: { type: 'string' },\n", + " explanation: { type: 'string' },\n", " },\n", - " required: ['number', 'final_verdict', 'source_file', 'quote', 'correct_figure', 'reasoning'],\n", + " required: ['supported', 'explanation'],\n", "}\n", "\n", - "// 1. EXTRACT\n", "phase('Extract')\n", - "const extraction = await agent(\n", - " `Read the file investor_update.md in the current working directory. It is a draft investor update ` +\n", - " `containing a numbered list of ten highlights (1-10). Extract each numbered highlight as exactly one ` +\n", - " `claim, preserving the draft's own numbering 1-10. Treat each numbered item as exactly one claim even ` +\n", - " `when it bundles two figures together (e.g. an item that states both a dollar amount and a percentage ` +\n", - " `is still ONE claim, not two). Return the claim text verbatim as written in the draft (including bolded ` +\n", - " `figures), for all ten items.`,\n", - " { label: 'extract', schema: EXTRACT_SCHEMA }\n", + "const ex = await agent(\n", + " 'Read investor_update.md and extract its ten numbered highlights. Keep the draft\\'s own numbering 1-10. Each numbered highlight is exactly one claim, even if it bundles two figures. Return the claim number and the full claim text verbatim.',\n", + " { phase: 'Extract', label: 'extract', schema: EXTRACT },\n", ")\n", + "const claims = ex.claims\n", + "log(`Extracted ${claims.length} claims`)\n", "\n", - "const claims = extraction.claims.sort((a, b) => a.number - b.number)\n", - "log(`Extracted ${claims.length} claims from investor_update.md`)\n", - "\n", - "// 2. VERIFY (parallel, one per claim) then 3. SKEPTIC (only for confirmed verdicts)\n", "const results = await pipeline(\n", " claims,\n", - " (claim) => agent(\n", - " `You are fact-checking one highlight from OrbitCart's draft Q2 2026 investor update against source ` +\n", - " `documents. The source documents live in the sources/ directory of the current working directory: ` +\n", - " `sources/monthly_sales.csv, sources/customer_survey.txt, sources/press_coverage.md, and ` +\n", - " `sources/uptime_report.txt. Read all four files.\\n\\n` +\n", - " `Claim #${claim.number}: \"${claim.text}\"\\n\\n` +\n", - " `Determine a verdict:\\n` +\n", - " `- \"confirmed\" if a source directly supports the claim as written. Quote the exact supporting line(s).\\n` +\n", - " `- \"contradicted\" if a source conflicts with the claim (a different number, a different attribution, ` +\n", - " `a stat that doesn't match, etc). Quote the exact conflicting line(s) and state the correct figure/fact ` +\n", - " `per the source.\\n` +\n", - " `- \"unverifiable\" if no source covers this claim at all.\\n\\n` +\n", - " `Be precise and skeptical: pay close attention to subtle differences between what a source actually ` +\n", - " `says and what the draft claims it says (e.g. a claim may bundle a true figure with a false one, cite ` +\n", - " `the wrong quarter, misattribute a quote, round in a misleading way, or overstate what a source covers). ` +\n", - " `If the claim bundles two figures and only one is supported, that counts as \"contradicted\", not ` +\n", - " `\"confirmed\" — quote the source and explain exactly which part is wrong. Quote exact lines from the ` +\n", - " `source file(s), do not paraphrase the quote field.`,\n", - " { label: `verify-${claim.number}`, phase: 'Verify', schema: VERIFY_SCHEMA }\n", - " ),\n", - " (verifyResult, claim) => {\n", - " if (!verifyResult || verifyResult.verdict !== 'confirmed') {\n", - " return Promise.resolve(verifyResult ? { ...verifyResult, skeptic_reviewed: false } : null)\n", + " (c) => agent(\n", + " `Fact-check this claim from investor_update.md against the source documents in sources/ (list and read the files there).\\n\\nClaim ${c.number}: ${c.text}\\n\\nVerdict rules:\\n- \"confirmed\": a source directly supports the claim (quote the supporting line)\\n- \"contradicted\": a source conflicts (quote the conflicting line and state the correct figure)\\n- \"unverifiable\": no source covers it\\nQuote exact lines relied on and name the file. Pay close attention to subtle differences between what the source says and what the draft claims (time period, metric definition, units, rounding, scope, gross vs net, bundled figures - check BOTH figures if two are bundled).`,\n", + " { phase: 'Verify', label: `verify:${c.number}`, schema: VERDICT },\n", + " ).then((v) => ({ ...c, ...v })),\n", + " async (r, c) => {\n", + " if (!r || r.verdict !== 'confirmed') return r\n", + " phase('Skeptic')\n", + " const s = await agent(\n", + " `You are a skeptic. A verifier marked this claim from investor_update.md as CONFIRMED. Re-read the cited source and try to refute the confirmation.\\n\\nClaim ${r.number}: ${r.text}\\nCited file: ${r.source_file}\\nCited quote: ${r.quote}\\n\\nCheck that the quote really exists in that file, and that it supports EVERY part of the claim (period, metric definition, units, scope, all bundled figures). Also check other files in sources/ for conflicting figures. Set supported=false if the citation does not actually support the claim, and give the correct figure.`,\n", + " { phase: 'Skeptic', label: `skeptic:${r.number}`, schema: SKEPTIC },\n", + " )\n", + " if (s && !s.supported) {\n", + " return { ...r, verdict: 'contradicted', original_verdict: 'confirmed', correct_figure: s.correct_figure || r.correct_figure, quote: s.quote || r.quote, explanation: `Skeptic overturned: ${s.explanation}` }\n", " }\n", - " return agent(\n", - " `You are a skeptical fact-checking reviewer. Another verifier examined claim #${claim.number} from ` +\n", - " `OrbitCart's draft Q2 2026 investor update and marked it \"confirmed\", citing this evidence:\\n\\n` +\n", - " `Claim: \"${claim.text}\"\\n` +\n", - " `Cited source file: ${verifyResult.source_file}\\n` +\n", - " `Cited quote: \"${verifyResult.quote}\"\\n` +\n", - " `Verifier reasoning: ${verifyResult.reasoning}\\n\\n` +\n", - " `Re-read the cited source file (path relative to the current working directory, inside sources/) ` +\n", - " `yourself and try hard to REFUTE this confirmation. Look for: the quote being taken out of context, ` +\n", - " `the quote actually supporting a different number/fact than the claim states, the claim bundling a ` +\n", - " `second figure that the quote does NOT cover, misattribution, wrong time period, or rounding that ` +\n", - " `changes the meaning. If you find the citation does NOT actually fully support the claim, set ` +\n", - " `final_verdict to \"contradicted\", quote the real conflicting/limiting line, and state the correct ` +\n", - " `figure or fact. Only keep final_verdict \"confirmed\" if the citation genuinely and fully supports the ` +\n", - " `claim as written after your adversarial check.`,\n", - " { label: `skeptic-${claim.number}`, phase: 'Skeptic', schema: SKEPTIC_SCHEMA }\n", - " ).then((skepticResult) => {\n", - " if (!skepticResult) return { ...verifyResult, skeptic_reviewed: false }\n", - " if (skepticResult.final_verdict === 'contradicted') {\n", - " return {\n", - " ...verifyResult,\n", - " verdict: 'contradicted',\n", - " source_file: skepticResult.source_file || verifyResult.source_file,\n", - " quote: skepticResult.quote || verifyResult.quote,\n", - " correct_figure: skepticResult.correct_figure || verifyResult.correct_figure,\n", - " reasoning: `Skeptic overturned confirmation: ${skepticResult.reasoning}`,\n", - " skeptic_reviewed: true,\n", - " }\n", - " }\n", - " return { ...verifyResult, skeptic_reviewed: true, reasoning: `${verifyResult.reasoning} (skeptic upheld: ${skepticResult.reasoning})` }\n", - " })\n", - " }\n", + " return { ...r, skeptic: s ? 'upheld' : 'skeptic unavailable' }\n", + " },\n", ")\n", "\n", - "const finalResults = results.filter(Boolean).sort((a, b) => a.number - b.number)\n", - "log(`Verification complete for ${finalResults.length} claims`)\n", + "const final = results.filter(Boolean).sort((a, b) => a.number - b.number)\n", + "if (final.length !== claims.length) log(`Warning: ${claims.length - final.length} claims dropped due to agent failure`)\n", "\n", - "// 4. REPORT\n", "phase('Report')\n", "const report = await agent(\n", - " `Compile a markdown fact-check report for OrbitCart's draft Q2 2026 investor update ` +\n", - " `(investor_update.md), based on this verification data (JSON, one entry per numbered claim, already ` +\n", - " `including any skeptic-review overturns):\\n\\n${JSON.stringify(finalResults, null, 2)}\\n\\n` +\n", - " `Produce a markdown report with:\\n` +\n", - " `1. A table with columns: Claim #, Claim, Verdict, Evidence (the source file and quote, or \"no source ` +\n", - " `covers this\" for unverifiable claims, or the conflicting quote + correct figure for contradicted claims).\\n` +\n", - " `2. A \"Summary\" section listing exactly what must be fixed before the update can be sent — call out every ` +\n", - " `\"contradicted\" claim with the correct figure/fact to use instead, and every \"unverifiable\" claim that ` +\n", - " `needs a source or should be softened/removed. If everything is confirmed, say so plainly.\\n\\n` +\n", - " `Return only the finished markdown report as your final answer.`,\n", - " { label: 'report' }\n", + " `Compile a markdown fact-check report from this data (JSON). Include: (1) a table of every claim with columns: #, claim, verdict, evidence (quoted line + source file), correct figure where relevant; note any verdicts the skeptic overturned. (2) a summary of what must be fixed before the investor update can be sent (list each fix with the corrected wording/figure), and what is unverifiable and needs a source or removal. Return only the markdown.\\n\\n${JSON.stringify(final, null, 2)}`,\n", + " { phase: 'Report', label: 'report' },\n", ")\n", - "\n", "return report\n", - "\n", "```" ], "text/plain": [ @@ -895,7 +830,14 @@ "cell_type": "code", "execution_count": 8, "id": "0c633d6e", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:53:16.978472Z", + "iopub.status.busy": "2026-10-21T16:53:16.978357Z", + "iopub.status.idle": "2026-10-21T16:53:16.986293Z", + "shell.execute_reply": "2026-10-21T16:53:16.985471Z" + } + }, "outputs": [ { "name": "stdout", @@ -940,8 +882,16 @@ "name": "python3" }, "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", "name": "python", - "version": "3.11.0" + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.14" } }, "nbformat": 4, diff --git a/content/github/claude-cookbooks/claude_agent_sdk/scheduled_repository_reviewer/scheduled_repository_reviewer.ipynb b/content/github/claude-cookbooks/claude_agent_sdk/scheduled_repository_reviewer/scheduled_repository_reviewer.ipynb index 31ef671c8c..8d33a192aa 100644 --- a/content/github/claude-cookbooks/claude_agent_sdk/scheduled_repository_reviewer/scheduled_repository_reviewer.ipynb +++ b/content/github/claude-cookbooks/claude_agent_sdk/scheduled_repository_reviewer/scheduled_repository_reviewer.ipynb @@ -71,10 +71,10 @@ "id": "c2", "metadata": { "execution": { - "iopub.execute_input": "2026-08-28T21:43:30.452687Z", - "iopub.status.busy": "2026-08-28T21:43:30.452568Z", - "iopub.status.idle": "2026-08-28T21:43:30.457639Z", - "shell.execute_reply": "2026-08-28T21:43:30.457258Z" + "iopub.execute_input": "2026-10-21T16:51:24.765485Z", + "iopub.status.busy": "2026-10-21T16:51:24.765342Z", + "iopub.status.idle": "2026-10-21T16:51:24.920241Z", + "shell.execute_reply": "2026-10-21T16:51:24.919466Z" } }, "outputs": [], @@ -103,10 +103,10 @@ "id": "c4", "metadata": { "execution": { - "iopub.execute_input": "2026-08-28T21:43:30.458919Z", - "iopub.status.busy": "2026-08-28T21:43:30.458806Z", - "iopub.status.idle": "2026-08-28T21:43:30.466889Z", - "shell.execute_reply": "2026-08-28T21:43:30.466600Z" + "iopub.execute_input": "2026-10-21T16:51:24.922154Z", + "iopub.status.busy": "2026-10-21T16:51:24.922008Z", + "iopub.status.idle": "2026-10-21T16:51:24.928007Z", + "shell.execute_reply": "2026-10-21T16:51:24.927624Z" } }, "outputs": [], @@ -135,10 +135,10 @@ "id": "c6", "metadata": { "execution": { - "iopub.execute_input": "2026-08-28T21:43:30.467819Z", - "iopub.status.busy": "2026-08-28T21:43:30.467725Z", - "iopub.status.idle": "2026-08-28T21:43:30.471534Z", - "shell.execute_reply": "2026-08-28T21:43:30.471165Z" + "iopub.execute_input": "2026-10-21T16:51:24.929779Z", + "iopub.status.busy": "2026-10-21T16:51:24.929662Z", + "iopub.status.idle": "2026-10-21T16:51:24.934439Z", + "shell.execute_reply": "2026-10-21T16:51:24.933748Z" } }, "outputs": [ @@ -211,10 +211,10 @@ "id": "c8", "metadata": { "execution": { - "iopub.execute_input": "2026-08-28T21:43:30.472503Z", - "iopub.status.busy": "2026-08-28T21:43:30.472390Z", - "iopub.status.idle": "2026-08-28T21:43:30.475382Z", - "shell.execute_reply": "2026-08-28T21:43:30.475077Z" + "iopub.execute_input": "2026-10-21T16:51:24.935794Z", + "iopub.status.busy": "2026-10-21T16:51:24.935679Z", + "iopub.status.idle": "2026-10-21T16:51:24.939153Z", + "shell.execute_reply": "2026-10-21T16:51:24.938600Z" } }, "outputs": [], @@ -270,10 +270,10 @@ "id": "c10", "metadata": { "execution": { - "iopub.execute_input": "2026-08-28T21:43:30.476320Z", - "iopub.status.busy": "2026-08-28T21:43:30.476224Z", - "iopub.status.idle": "2026-08-28T21:43:30.478685Z", - "shell.execute_reply": "2026-08-28T21:43:30.478387Z" + "iopub.execute_input": "2026-10-21T16:51:24.942293Z", + "iopub.status.busy": "2026-10-21T16:51:24.942167Z", + "iopub.status.idle": "2026-10-21T16:51:24.945534Z", + "shell.execute_reply": "2026-10-21T16:51:24.944383Z" } }, "outputs": [ @@ -338,10 +338,10 @@ "id": "c12", "metadata": { "execution": { - "iopub.execute_input": "2026-08-28T21:43:30.479653Z", - "iopub.status.busy": "2026-08-28T21:43:30.479568Z", - "iopub.status.idle": "2026-08-28T21:43:30.737626Z", - "shell.execute_reply": "2026-08-28T21:43:30.737365Z" + "iopub.execute_input": "2026-10-21T16:51:24.946823Z", + "iopub.status.busy": "2026-10-21T16:51:24.946702Z", + "iopub.status.idle": "2026-10-21T16:51:26.014538Z", + "shell.execute_reply": "2026-10-21T16:51:26.014072Z" } }, "outputs": [], @@ -353,6 +353,7 @@ " ClaudeAgentOptions,\n", " HookContext,\n", " HookMatcher,\n", + " ProcessError,\n", " ResultError,\n", " ResultMessage,\n", " TextBlock,\n", @@ -493,10 +494,10 @@ "id": "c14", "metadata": { "execution": { - "iopub.execute_input": "2026-08-28T21:43:30.738447Z", - "iopub.status.busy": "2026-08-28T21:43:30.738343Z", - "iopub.status.idle": "2026-08-28T21:43:30.741560Z", - "shell.execute_reply": "2026-08-28T21:43:30.741289Z" + "iopub.execute_input": "2026-10-21T16:51:26.016545Z", + "iopub.status.busy": "2026-10-21T16:51:26.016326Z", + "iopub.status.idle": "2026-10-21T16:51:26.021227Z", + "shell.execute_reply": "2026-10-21T16:51:26.020599Z" } }, "outputs": [ @@ -509,7 +510,7 @@ } ], "source": [ - "from dataclasses import dataclass, field\n", + "from dataclasses import asdict, dataclass, field\n", "\n", "\n", "@dataclass\n", @@ -589,10 +590,10 @@ "id": "c16", "metadata": { "execution": { - "iopub.execute_input": "2026-08-28T21:43:30.742204Z", - "iopub.status.busy": "2026-08-28T21:43:30.742138Z", - "iopub.status.idle": "2026-08-28T21:43:30.745271Z", - "shell.execute_reply": "2026-08-28T21:43:30.745048Z" + "iopub.execute_input": "2026-10-21T16:51:26.022547Z", + "iopub.status.busy": "2026-10-21T16:51:26.022437Z", + "iopub.status.idle": "2026-10-21T16:51:26.027693Z", + "shell.execute_reply": "2026-10-21T16:51:26.027063Z" } }, "outputs": [], @@ -610,26 +611,42 @@ " \"\"\"Run one review pass and return its structured result.\"\"\"\n", " options = review_options(repo, schema, max_turns, resume_session_id, service_dir)\n", " outcome = RunOutcome()\n", - " async for message in query(prompt=prompt, options=options):\n", - " match message:\n", - " case AssistantMessage(content=blocks):\n", - " for block in blocks:\n", - " match block:\n", - " case TextBlock(text=text):\n", - " line = text.strip()\n", - " if line:\n", - " # Cap what a scheduled log absorbs per block.\n", - " print(f\"[{label}] {clip(line)}\")\n", - " case ToolUseBlock(name=tool_name):\n", - " outcome.tools_attempted.append(tool_name)\n", - " case ResultMessage() as result:\n", - " outcome.session_id = result.session_id\n", - " outcome.subtype = result.subtype\n", - " outcome.num_turns = result.num_turns\n", - " outcome.total_cost_usd = result.total_cost_usd\n", - " outcome.denials = len(result.permission_denials or [])\n", - " if isinstance(result.structured_output, dict):\n", - " outcome.payload = result.structured_output\n", + " # The raw payload of a terminal error result, kept so the except branch\n", + " # below can re-raise it typed.\n", + " error_result: dict[str, Any] | None = None\n", + " try:\n", + " async for message in query(prompt=prompt, options=options):\n", + " match message:\n", + " case AssistantMessage(content=blocks):\n", + " for block in blocks:\n", + " match block:\n", + " case TextBlock(text=text):\n", + " line = text.strip()\n", + " if line:\n", + " # Cap what a scheduled log absorbs per block.\n", + " print(f\"[{label}] {clip(line)}\")\n", + " case ToolUseBlock(name=tool_name):\n", + " outcome.tools_attempted.append(tool_name)\n", + " case ResultMessage() as result:\n", + " outcome.session_id = result.session_id\n", + " outcome.subtype = result.subtype\n", + " outcome.num_turns = result.num_turns\n", + " outcome.total_cost_usd = result.total_cost_usd\n", + " outcome.denials = len(result.permission_denials or [])\n", + " if isinstance(result.structured_output, dict):\n", + " outcome.payload = result.structured_output\n", + " error_result = asdict(result) if result.is_error else None\n", + " except ProcessError as exc:\n", + " # The SDK raises ResultError itself when the error result is the last\n", + " # frame the CLI emits. CLI 2.1.301 (bundled with claude-agent-sdk\n", + " # 0.2.168) sends a task_summary frame after it, and the SDK then falls\n", + " # back to a bare ProcessError; re-raise it typed from the result this\n", + " # loop already saw, so callers keep one narrow `except ResultError`.\n", + " if isinstance(exc, ResultError) or error_result is None:\n", + " raise\n", + " reason = \"; \".join(error_result.get(\"errors\") or []) or error_result.get(\"result\")\n", + " message = f\"Claude Code returned an error result: {reason or error_result.get('subtype')}\"\n", + " raise ResultError(message, data=error_result, exit_code=exc.exit_code) from exc\n", " return outcome\n", "\n", "\n", @@ -673,10 +690,10 @@ "id": "c18", "metadata": { "execution": { - "iopub.execute_input": "2026-08-28T21:43:30.745836Z", - "iopub.status.busy": "2026-08-28T21:43:30.745775Z", - "iopub.status.idle": "2026-08-28T21:43:45.085700Z", - "shell.execute_reply": "2026-08-28T21:43:45.085225Z" + "iopub.execute_input": "2026-10-21T16:51:26.029398Z", + "iopub.status.busy": "2026-10-21T16:51:26.029274Z", + "iopub.status.idle": "2026-10-21T16:51:31.211715Z", + "shell.execute_reply": "2026-10-21T16:51:31.211281Z" } }, "outputs": [ @@ -684,10 +701,10 @@ "name": "stdout", "output_type": "stream", "text": [ - "RUN-1 session=2d83a97b-27ff-403e-a067-2fb5b6474d9b subtype=success turns=10 denials=3 cost_usd=0.0278 tools_attempted=Glob,Read,StructuredOutput\n", + "RUN-1 session=f3f70d8c-2d10-46f4-9cd8-58528c10dd22 subtype=success turns=5 denials=0 cost_usd=0.0171 tools_attempted=Glob,Read,StructuredOutput\n", "VERDICT: concerns\n", - " F1 app/math_utils.py: divide() does not guard against denominator being zero, and average() calls divide(sum(values), len(values)) which raises ZeroDivisionError when values is an empty list.\n", - " F2 app/config.py: load_config() copies the entire process environment (os.environ) into the config dict and prints it via print(), which can leak secrets/credentials (API keys, tokens) into logs.\n" + " F1 app/config.py: load_config copies the whole os.environ into the config and then prints it, so secrets such as API keys and tokens end up in logs. Load only the specific variables needed and don't print them.\n", + " F2 app/math_utils.py: average() raises ZeroDivisionError for an empty list because it divides by len(values) with no check. divide() has the same problem when the denominator is 0. Handle empty input explicitly.\n" ] } ], @@ -747,10 +764,10 @@ "id": "c20", "metadata": { "execution": { - "iopub.execute_input": "2026-08-28T21:43:45.086969Z", - "iopub.status.busy": "2026-08-28T21:43:45.086855Z", - "iopub.status.idle": "2026-08-28T21:43:45.090933Z", - "shell.execute_reply": "2026-08-28T21:43:45.090551Z" + "iopub.execute_input": "2026-10-21T16:51:31.213254Z", + "iopub.status.busy": "2026-10-21T16:51:31.213055Z", + "iopub.status.idle": "2026-10-21T16:51:31.217270Z", + "shell.execute_reply": "2026-10-21T16:51:31.216578Z" } }, "outputs": [ @@ -821,10 +838,10 @@ "id": "c22", "metadata": { "execution": { - "iopub.execute_input": "2026-08-28T21:43:45.092085Z", - "iopub.status.busy": "2026-08-28T21:43:45.091984Z", - "iopub.status.idle": "2026-08-28T21:43:56.595562Z", - "shell.execute_reply": "2026-08-28T21:43:56.595128Z" + "iopub.execute_input": "2026-10-21T16:51:31.218537Z", + "iopub.status.busy": "2026-10-21T16:51:31.218417Z", + "iopub.status.idle": "2026-10-21T16:51:37.324630Z", + "shell.execute_reply": "2026-10-21T16:51:37.323676Z" } }, "outputs": [ @@ -832,12 +849,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "RUN-2 session=2d83a97b-27ff-403e-a067-2fb5b6474d9b subtype=success turns=7 denials=0 cost_usd=0.0339 tools_attempted=Glob,Read,StructuredOutput\n", + "RUN-2 session=f3f70d8c-2d10-46f4-9cd8-58528c10dd22 subtype=success turns=6 denials=0 cost_usd=0.0404 tools_attempted=Glob,Read,StructuredOutput\n", "VERDICT: concerns\n", - " F2 app/config.py: load_config() still copies the entire process environment (os.environ) into the config dict and prints it via print(), which can leak secrets/credentials into logs.\n", - " F3 app/retry.py: fetch_with_retry() retries in an unbounded infinite loop with a fixed 1-second sleep and no max attempt limit or exponential backoff, risking indefinite hangs/resource exhaustion if the underlying fetch keeps raising ConnectionError; other exceptions are also not handled.\n", - "RESUME-LINK run1_session=2d83a97b-27ff-403e-a067-2fb5b6474d9b run2_session=2d83a97b-27ff-403e-a067-2fb5b6474d9b same_session=True prior_review_id_echoed=True recalled_findings=2/2\n", - "resolved=['F1']\n", + " F1 app/config.py: load_config still copies all of os.environ into the config and prints it, which leaks secrets to logs.\n", + " F3 app/retry.py: fetch_with_retry loops forever on ConnectionError, with no attempt limit, no backoff and no timeout. A permanently unreachable service hangs the caller indefinitely.\n", + "RESUME-LINK run1_session=f3f70d8c-2d10-46f4-9cd8-58528c10dd22 run2_session=f3f70d8c-2d10-46f4-9cd8-58528c10dd22 same_session=True prior_review_id_echoed=True recalled_findings=2/2\n", + "resolved=['F2']\n", "REVIEW-CYCLE-COMPLETE runs=2 verdicts=concerns,concerns\n" ] } @@ -960,10 +977,10 @@ "id": "c25", "metadata": { "execution": { - "iopub.execute_input": "2026-08-28T21:43:56.597079Z", - "iopub.status.busy": "2026-08-28T21:43:56.596959Z", - "iopub.status.idle": "2026-08-28T21:44:00.554785Z", - "shell.execute_reply": "2026-08-28T21:44:00.554288Z" + "iopub.execute_input": "2026-10-21T16:51:37.326533Z", + "iopub.status.busy": "2026-10-21T16:51:37.326318Z", + "iopub.status.idle": "2026-10-21T16:51:39.078341Z", + "shell.execute_reply": "2026-10-21T16:51:39.077785Z" } }, "outputs": [ @@ -971,7 +988,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "REVIEW-CYCLE-INCOMPLETE stage=induced subtype=error_max_turns reason=max_turns cost_usd=0.0032\n" + "REVIEW-CYCLE-INCOMPLETE stage=induced subtype=error_max_turns reason=max_turns cost_usd=0.0009\n" ] } ], @@ -1140,10 +1157,10 @@ "id": "c29", "metadata": { "execution": { - "iopub.execute_input": "2026-08-28T21:44:00.556209Z", - "iopub.status.busy": "2026-08-28T21:44:00.556091Z", - "iopub.status.idle": "2026-08-28T21:44:00.559168Z", - "shell.execute_reply": "2026-08-28T21:44:00.558841Z" + "iopub.execute_input": "2026-10-21T16:51:39.079699Z", + "iopub.status.busy": "2026-10-21T16:51:39.079578Z", + "iopub.status.idle": "2026-10-21T16:51:39.085374Z", + "shell.execute_reply": "2026-10-21T16:51:39.084970Z" } }, "outputs": [ @@ -1203,7 +1220,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.0" + "version": "3.12.14" } }, "nbformat": 4, diff --git a/content/github/claude-cookbooks/cost_optimization/cost_optimization.ipynb b/content/github/claude-cookbooks/cost_optimization/cost_optimization.ipynb index c565244ff2..99e88b7c67 100644 --- a/content/github/claude-cookbooks/cost_optimization/cost_optimization.ipynb +++ b/content/github/claude-cookbooks/cost_optimization/cost_optimization.ipynb @@ -35,7 +35,7 @@ "source": [ "## Prerequisites\n", "\n", - "> **Note**: Running this cookbook top to bottom costs ~$40 in API credits. We recommend only running cells live when you want to experiment with the inputs.\n", + "> **Note**: Running this cookbook top to bottom costs ~\\$40 in API credits. We recommend only running cells live when you want to experiment with the inputs.\n", "\n", "To run this notebook, you will need:\n", "\n", @@ -794,9 +794,9 @@ "id": "7a9a7287", "metadata": {}, "source": [ - "Our baseline run lands at **10/10 correct** for **~$0.29/task**. At a million claims a year, every cent off cost per task will save us ~$10K in annual spend. But our quality bar is high – when it comes to insurance claims, mis-labels are more costly than inference savings, so we'll hold our quality bar at near-100% accuracy. That means that as we optimize, we'll look to achieve less than ~$0.29/task while getting all 10 eval cases correct.\n", + "Our baseline run lands at **10/10 correct** for ~**\\$0.29/task**. At a million claims a year, every cent off cost per task will save us ~\\$10K in annual spend. But our quality bar is high – when it comes to insurance claims, mis-labels are more costly than inference savings, so we'll hold our quality bar at near-100% accuracy. That means that as we optimize, we'll look to achieve less than ~**\\$0.29/task** while getting all 10 eval cases correct.\n", "\n", - ">**Note**: Model outputs are nondeterministic, so the same configuration can land at a different pass rate and cost per task from one run to the next. Your live eval runs in this notebook may return different results than what we've hardcoded in text. When conducting a cost optimization audit for your own agent, be sure to run many parallel trials so you're making decisions based on a representative distribution rather than a single sample." + "> **Note**: Model outputs are nondeterministic, so the same configuration can land at a different pass rate and cost per task from one run to the next. Your live eval runs in this notebook may return different results than what we've hardcoded in text. When conducting a cost optimization audit for your own agent, be sure to run many parallel trials so you're making decisions based on a representative distribution rather than a single sample." ] }, { @@ -1578,6 +1578,7 @@ "metadata": {}, "source": [ "Notice how the ledger stays in the context window, occupying significant space even though we've already pulled the necessary insights from it. Instead, we can employ [**context editing**](https://platform.claude.com/docs/en/build-with-claude/context-editing), which allows us to prune stale content (like the ledger) that otherwise lingers in the agent loop. Two edits do the clearing:\n", + "\n", "- `clear_tool_uses` removes older tool results and leaves a short placeholder so the model still knows the call happened. Set its `clear_tool_inputs` option to also drop the call's input parameters.\n", "- `clear_thinking` removes thinking blocks from prior turns\n", "\n", diff --git a/content/github/claude-cookbooks/latency_optimization/desk_agent/README.md b/content/github/claude-cookbooks/latency_optimization/desk_agent/README.md new file mode 100644 index 0000000000..211afe1892 --- /dev/null +++ b/content/github/claude-cookbooks/latency_optimization/desk_agent/README.md @@ -0,0 +1,29 @@ +# desk_agent + +The eval behind the latency cookbook: a desk assistant for auto claims at a made-up insurer, Acme Insurance. Every person, shop, claim, and policy in the data is invented, and any likeness to a real one is a coincidence. An adjuster hands the assistant one task about one claim, and the assistant follows a long policy manual in its system prompt, looks things up with tools, and finishes by calling the task's recorder tool. The package holds the tasks, the system prompt, the simulated tools, and the graders. It uses the standard library only and makes no API calls, so any agent loop can drive it. + +## How the tasks were made + +The 154 tasks in `data/final/` (50 letters, 54 quotes, and 50 pre-screens) were generated once from a fixed seed, recorded in `meta.json`. A solver that applies the manual's rules computes each answer key, so every key follows from the manual and the task's own material. The manual is the cost optimization cookbook's, with three parts added: a settlement procedure (Section 9), a parts catalogue (Appendix A), and the assistant's three tasks (Section 10). The letter templates and the catalogue rows are reached through `get_template` and `lookup_parts`, which keeps them out of the prompt. Each task's `level` grades the work it takes: letters run A1 to A2 (a payment or full denial, then a partial denial or total loss), quotes B0 to B8 by how many of the manual's rules apply, and pre-screens C0 to C4 by how many flagged prior claims the repair shop has in the ledger. The notebook's blended figures weight the three jobs a third each and the levels equally within a job, so re-weight the per-job results for your own traffic. Loading the tasks never generates anything. + +## How grading works + +`grade(item, recorded)` takes the first recorder call, `{"name": ..., "args": ...}` or `None`, and checks it against the task's key once harmless differences of form are removed. A letter needs the right template, the right "Pay After Acceptance" entry for the loss state, and the template's approved wording with the decision's figures filled in. A quote needs the right verdict and an amount within 50 cents. A pre-screen needs exactly the prior claims that count and the right score. It returns `correct` and diagnostic keys such as `ids_missed` and `amount_ok`, and a task with no recorder call or the wrong recorder is wrong. + +## Functions + +- `load_items("final")` returns the tasks as dicts. A loop may read `id`, `type`, `level`, `cluster`, `claim_id`, and `user_turn`, and only `user_turn` goes to the model. `cluster` is the unit to resample by: pre-screens at the same repair shop share one, and every other task is its own. `key` and fields starting with `_` belong to the tools and graders. +- `system_prompt(*, no_commentary=False)` returns the system prompt, with `NO_COMMENTARY` appended when asked. +- `tool_specs(*, big_pages=False)` returns five lookups and three recorders, ready to pass as `tools`. `RECORDERS` maps a task's type to its recorder, and `is_terminal(name)` is true for the recorders. +- `first_turn(item, *, prefetch=False, big_pages=False)` returns the first user message, which with `prefetch` also carries the claim record and, for a quote, page 1 of the estimate. +- `call_tool(item, name, args, *, big_pages=False)` returns a tool's result as a string, starting `"ERROR: "` on bad input. `big_pages` doubles the page sizes (estimate lines 15 to 30, ledger rows 10 to 20, catalogue numbers 20 to 40) and changes three tool descriptions, so pass the same value to `tool_specs`, `first_turn`, and `call_tool`. + +`_gen/` holds the manual's text, the parts catalogue, and each task type's grader. The notebook's one-off demos read the same manual from there. The generators and solvers don't ship. The package reads `items.json` and `ledgers.json` from `data/final/`. + +## Rules for the loop + +An attempt gets `TURN_CAP` (16) model calls, and `TURN_CAP_MESSAGE` goes on every tool result of the last turn before the cap. In a turn with a recorder call, the first recorder call is the answer. A turn with text and no tool call gets `NUDGE_MESSAGE` once, and a second such turn ends the attempt with no answer. The notebook also counts a reply cut off at `max_tokens` or refused as wrong. + +## Running a sweep and the logs + +No script here runs a full sweep. The notebook's `run_task()` follows the same rules as the loop we ran, except that it ends a task at `TIME_LIMIT`, which our loop didn't have. In each round we ran every task once per setting in a shuffled order, and `results/README.md` lists and counts the attempts we left out, such as those whose first call found the cache cold. In the sweep, each batch's system prompt began with a one-line session label, new in every round, so batches didn't share a cache, and the label also set each batch's shuffled order; `run_task()` doesn't add it. `results/sweep.jsonl` has one line per attempt that counts: the setting (`round`, the fields of the notebook's `Config`, and `caching`, which is `"on"` on every line), the task (`task`, `type`, `level`, `cluster`, `correct`), the task's token and seconds totals, and each model call's seconds, first-token seconds (`call_first_token_secs`, the time to the call's first token, thinking included), and output and thinking tokens. Seconds and first-token seconds are the service's own timing of each request, less the time that request waited on a step only our test harness adds, plus a fixed 0.13 seconds a call to stand for the network, so timings from your own client will differ by your network. `results/baseline.jsonl` has the baseline again, run without caching (`caching` is `"off"`), in the same fields, and `results/examples.jsonl` holds three of its tasks in the shape `baseline_task()` returns. `results/race.jsonl` holds the final run behind Putting it all together, under the same loop rules, but its seconds are timed by our client and include the network; `results/README.md` describes its extra fields. diff --git a/content/github/claude-cookbooks/latency_optimization/desk_agent/_gen/policy_manual.md b/content/github/claude-cookbooks/latency_optimization/desk_agent/_gen/policy_manual.md new file mode 100644 index 0000000000..d81dac7cc0 --- /dev/null +++ b/content/github/claude-cookbooks/latency_optimization/desk_agent/_gen/policy_manual.md @@ -0,0 +1,307 @@ +# Acme Insurance — Auto Claims Adjudication Manual (Internal) + +**Document ID:** CLM-ADJ-2024.3 +**Effective Date:** January 1, 2024 +**Classification:** Internal Use Only — Claims Operations +**Supersedes:** CLM-ADJ-2023.2 + +--- + +## Section 1: Coverage Types & Definitions + +### 1.1 Collision Coverage (COV-COLL) +Collision coverage indemnifies the insured for direct physical damage to the covered vehicle resulting from impact with another vehicle or object, or from upset (rollover). Collision applies regardless of fault. Payment is subject to the policy deductible and is capped at Actual Cash Value (ACV) of the vehicle immediately prior to loss. Collision does **not** cover mechanical failure, damage from animals, or damage from falling objects — these fall under Comprehensive. + +### 1.2 Comprehensive Coverage (COV-COMP) +Comprehensive (also "Other Than Collision") covers direct physical damage from causes other than collision, including: theft, vandalism, fire, flood, hail, windstorm, falling objects, contact with a bird or animal, and glass breakage. Comprehensive is subject to its own deductible (which may differ from the collision deductible). Glass-only claims may be handled under the separate Glass endorsement (see 1.7) if elected. + +### 1.3 Liability Coverage (COV-LIAB) +Liability coverage pays sums the insured becomes legally obligated to pay as damages because of bodily injury (BI) or property damage (PD) to third parties arising out of the ownership, maintenance, or use of the covered auto. Liability is written on a split-limit basis (e.g., 100/300/50 = $100k per person BI / $300k per accident BI / $50k per accident PD) or combined single limit (CSL). Liability does **not** cover damage to the insured's own vehicle or injuries to the named insured. + +### 1.4 Uninsured / Underinsured Motorist (COV-UM / COV-UIM) +UM coverage compensates the insured and resident family members for bodily injury caused by an at-fault driver who carries no liability insurance, or by a hit-and-run driver. UIM applies when the at-fault driver's liability limits are insufficient to cover the insured's damages. UM/UIM limits cannot exceed the policy's own BI liability limits. UMPD (property damage) is available in select states and carries a statutory deductible of $200–$300 depending on jurisdiction. + +### 1.5 Personal Injury Protection (COV-PIP) +PIP (no-fault coverage) pays first-party medical expenses, lost wages, and essential services regardless of fault, up to the elected limit. Standard PIP limits are $2,500 / $5,000 / $10,000 with state-mandated minimums in no-fault jurisdictions (e.g., FL $10,000, MI unlimited medical under legacy policies, NY $50,000). PIP wage loss is capped at 80% of gross weekly wages, subject to a per-week maximum of $500 unless higher limits are endorsed. + +### 1.6 Rental Reimbursement (COV-RENT) +Rental reimbursement pays for a substitute vehicle while the covered auto is being repaired for a covered loss. Standard limits are $30/day, $900 aggregate; enhanced limits of $50/day, $1,500 aggregate are available by endorsement. Rental begins the date the vehicle is delivered to the repair facility (or date of theft report for total theft) and ends the earlier of: repair completion, ACV settlement, or exhaustion of the aggregate limit. + +### 1.7 Full Glass Coverage (COV-GLASS) +The Full Glass endorsement waives the comprehensive deductible for glass-only damage (windshield, side windows, rear glass, sunroof). Repair (chip fill) is preferred over replacement when damage is smaller than a dollar bill and outside the driver's primary sight line. OEM glass is authorized only when the vehicle is under 2 model years old or when ADAS recalibration requires OEM per manufacturer spec. + +--- + +## Section 2: Claim Intake & Documentation Requirements + +### 2.1 Universal Intake Requirements (All Claim Types) +Every First Notice of Loss (FNOL) must capture: +- Policy number and named insured verification +- Date, time, and location of loss +- Description of loss facts in the insured's own words (recorded statement preferred for losses >$5,000) +- Police report number if law enforcement responded +- Names, contact information, and insurance information for all involved parties and witnesses +- Photos of damage (minimum 4 angles for vehicle damage; scene photos if available) +- Confirmation that coverage was in force on the date of loss (system-verified) + +### 2.2 Collision & Comprehensive — Additional Documentation +- Repair estimate from a licensed facility (Acme Direct Repair Program shop preferred) or independent appraisal +- Vehicle title or registration confirming ownership/insurable interest +- Lienholder information if financed +- Odometer reading and photo of odometer +- For theft: police report (mandatory), all keys/fobs, and completed Affidavit of Vehicle Theft (form CLM-118) +- For vandalism: police report if damage exceeds $1,000 +- For hail/weather: NOAA storm verification for the loss date and ZIP code + +### 2.3 Liability (Third-Party) — Additional Documentation +- Claimant's demand letter or itemized damages +- Claimant vehicle repair estimate and photos +- For BI: medical records, bills, and wage-loss documentation with signed HIPAA authorization (form CLM-204) +- Recorded statements from insured driver, claimant, and independent witnesses +- Scene diagram and police report +- ISO ClaimSearch run on all claimant parties + +### 2.4 UM/UIM — Additional Documentation +- Proof of the tortfeasor's uninsured or underinsured status (DMV FR letter, carrier denial, or declarations page showing limits) +- For hit-and-run: police report filed within 24 hours of loss (mandatory — no exceptions) +- Physical contact evidence for hit-and-run UMPD (where required by state) +- All BI documentation per Section 2.3 + +### 2.5 PIP — Additional Documentation +- Completed Application for Benefits (form CLM-PIP-01) within 30 days of loss +- Attending physician's report and treatment plan +- Itemized medical bills with CPT/ICD-10 coding +- Employer wage verification (form CLM-PIP-02) for lost-wage claims +- Independent Medical Examination (IME) may be required after $5,000 in billed medical or 90 days of treatment + +### 2.6 Rental & Glass — Additional Documentation +- Rental: rental agreement and final invoice; proof of covered primary loss +- Glass: photo of damage, VIN photo, invoice from glass vendor showing NAGS part numbers + +### 2.7 Recorded Statement Standards +Recorded statements are taken by the assigned adjuster, not intake staff, and must follow the approved question outline (CLM-RS-OUTLINE-v6). Begin every recording with date, time, parties present, and confirmation that the party consents to recording. Do not ask leading questions on liability facts. For any loss with SIU indicators (Section 5) or estimated indemnity >$25,000, statements must be taken from the insured driver, all claimant drivers, and at least one independent witness where available. Transcripts are ordered when the file is in litigation, referred to SIU, or the statement contains a material admission. If a party refuses to give a recorded statement, document the refusal verbatim, send the Cooperation Clause reminder letter (CORR-COOP-02), and diary 10 days; a second refusal on a first-party claim supports reservation of rights under the Duties After Loss condition. + +### 2.8 Proof of Loss +A sworn Proof of Loss (form CLM-POL-9) is required on: all first-party claims >$10,000, all theft claims regardless of amount, and any claim where SIU has been consulted. The insured has 60 days from written request to return the executed form. Failure to return a demanded Proof of Loss is a defense to payment but does **not** support outright denial without a second written demand and Claims Legal review. + +--- + +## Section 3: Payout Calculation Rules + +### 3.1 Deductible Application +The deductible is subtracted from the gross covered loss **before** payment. Deductibles apply per occurrence, not per vehicle part. If a single occurrence damages two covered vehicles on the same policy, one deductible applies per vehicle. Deductible is waived when: +- Subrogation recovery is 100% and includes the deductible +- Full Glass endorsement applies to a glass-only loss +- The insured is 0% at fault and the at-fault carrier accepts 100% liability (deductible advanced pending subro) + +### 3.2 Actual Cash Value (ACV) Determination +ACV = Replacement Cost − Depreciation. For vehicles, ACV is established using the CCC ONE or Mitchell valuation platform, drawing on a minimum of three comparable vehicles within a 75-mile radius (150 miles for rural ZIPs). Condition adjustments must be supported by inspection photos. Add: prior aftermarket equipment with receipts (capped at $1,000 unless scheduled). Subtract: prior unrepaired damage at 50% of estimated repair cost. + +### 3.3 Depreciation Schedules — Parts +When paying on a repair basis, betterment/depreciation is applied to the following wear items: + +| Part Category | Depreciation Method | Maximum Depreciation | +|---|---|---| +| Tires | Pro-rata by tread depth (2/32" = 100% worn) | 100% | +| Batteries | 20% per year of age | 80% | +| Exhaust systems | 10% per year after year 3 | 50% | +| Paint (full panel refinish) | 5% per year after year 5 | 40% | +| Convertible tops / upholstery | 10% per year | 70% | +| Suspension wear components | 8% per year after year 4 | 50% | + +No depreciation is taken on sheet metal, structural components, glass, airbags, or safety restraint systems. + +### 3.4 Labor Rate Caps by Region +Labor is reimbursed at the prevailing rate for the repair market, not to exceed the following caps without supervisor override: + +| Region | Body Labor | Refinish Labor | Mechanical Labor | Frame Labor | +|---|---|---|---|---| +| Region 1 (CA, NY, MA, WA, NJ) | $78/hr | $78/hr | $145/hr | $95/hr | +| Region 2 (TX, FL, IL, CO, AZ, GA) | $62/hr | $62/hr | $125/hr | $80/hr | +| Region 3 (all other states) | $54/hr | $54/hr | $110/hr | $72/hr | + +Paint & materials are calculated using the Mitchell refinish materials formula; manual P&M entries above $450 require itemized invoice. + +### 3.5 Total Loss Threshold +A vehicle is deemed a total loss when the cost to repair (including supplement reserve of 10%) plus projected rental plus salvage handling exceeds the **Total Loss Formula (TLF)** threshold: + +- **Standard TLF:** Repair cost ≥ 75% of ACV → total loss +- **Statutory states:** Use state-mandated threshold where higher (e.g., FL 80%, TX 100%, OK 60%, NC 75%) +- **Obvious total:** Burned, submerged above dash, or frame kinked beyond section limits → total regardless of formula + +Upon total loss determination, settlement = ACV + applicable taxes and title fees − deductible − prior damage deduction. Salvage is retained by Acme unless owner-retained salvage is elected (deduct salvage bid from settlement; issue salvage title per state law). + +### 3.6 Replacement Cost vs. ACV +Replacement Cost coverage (endorsement COV-RCV, available only on vehicles ≤3 model years old) pays the cost of a new vehicle of same make/model without depreciation, capped at 110% of MSRP. RCV applies only to total loss; partial losses settle on repair-cost basis. + +### 3.7 Supplement Handling +Supplements (additional damage discovered after teardown) are approved only after re-inspection or receipt of photos clearly showing hidden damage adjacent to the original impact zone. Supplements exceeding 25% of the original estimate require a desk re-review; supplements exceeding 50% trigger a mandatory field re-inspection and total-loss re-evaluation under Section 3.5. All supplements must be requested by the shop **before** the supplemental repair is performed — after-the-fact supplements for work already completed are capped at $500 absent supervisor approval. Document every supplement with a revised estimate version in the estimating platform; do not overwrite the original. + +### 3.8 Subrogation & Recovery +When the insured is 50% or less at fault, open a subrogation feature at FNOL and place the adverse carrier on notice within 5 business days. Minimum economic threshold for pursuit is $500 net of deductible. Send the subrogation demand package (estimate, photos, police report, payment ledger) within 15 days of final payment. If the adverse carrier disputes liability, refer to Intercompany Arbitration (Arbitration Forums) when both carriers are signatories; file within the 1-year contractual limitation. Recovered funds are applied first to reimburse the insured's deductible pro-rata to the recovery percentage, then to indemnity. Do not release the adverse party or sign a property damage release without confirming all first-party payments (including rental and towing) are included in the demand. + +### 3.9 Salvage & Towing +Towing from the scene is covered under collision/comprehensive up to $250 without endorsement; amounts above require the Towing & Labor endorsement (COV-TOW). Storage charges are covered only from date of loss to the date Acme makes the vehicle available for pickup or issues a total-loss offer plus 3 business days — advise the insured in writing (CORR-STOR-01) that storage beyond that date is their responsibility. Salvage vehicles are assigned to the contracted salvage vendor (Copart primary, IAA secondary) within 2 business days of settlement; adjusters must clear personal property release with the insured before assignment. + +### 3.10 Diminished Value +First-party diminished value is **not** covered under collision or comprehensive. Third-party diminished value claims are evaluated only in states recognizing the cause of action (GA, NC, and by case law in others). Use the 17c formula as a starting point: Base Loss of Value = 10% × NADA retail; apply damage modifier (0.00–1.00) and mileage modifier (0.00–1.00). + +--- + +## Section 4: Exclusions & Denial Codes + +All denials must cite the applicable exclusion code and quote the controlling policy language in the denial letter. The following are the standard exclusion codes: + +| Code | Exclusion | Policy Form Ref. | Notes | +|---|---|---|---| +| **EXCL-01** | Intentional acts | PP-00-01 §A.8 | Damage intentionally caused by or at the direction of the insured. Requires SIU concurrence before denial. | +| **EXCL-02** | Racing / speed contest | PP-00-01 §A.12 | Any prearranged or organized racing, speed, demolition, or stunt activity. Track-day events are excluded even if "non-competitive." | +| **EXCL-03** | Unlicensed / excluded driver | PP-00-01 §A.3 | Operator had no valid license, a suspended license, or is a named excluded driver on the policy. Verify DMV status on date of loss. | +| **EXCL-04** | Wear, tear, mechanical breakdown | PP-00-01 §B.2 | Gradual deterioration, rust, corrosion, freezing, or mechanical/electrical failure not resulting from a covered peril. | +| **EXCL-05** | Commercial use on personal policy | PP-00-01 §A.6 | Vehicle used to carry persons or property for compensation (rideshare, delivery, courier) without commercial-use endorsement END-CU-22. | +| **EXCL-06** | DUI / controlled substance | PP-00-01 §A.9 | Operator under the influence per statutory definition. Applies to first-party physical damage only; liability may still owe to third parties per state law. | +| **EXCL-07** | No coverage in force / lapsed policy | Declarations | Premium unpaid beyond grace period, policy cancelled or expired prior to date of loss. Verify with Underwriting before issuing. A lapsed policy reinstated by payment before the date of loss is in force from the reinstatement date forward; losses occurring inside the lapse gap remain excluded. | +| **EXCL-08** | Non-permissive use | PP-00-01 §A.4 | Vehicle operated without a reasonable belief of the owner's permission. Does not apply to resident family members. | +| **EXCL-09** | Nuclear, war, government seizure | PP-00-01 §B.7 | Standard catastrophic exclusions. | +| **EXCL-10** | Custom equipment not scheduled | PP-00-01 §B.4 | Aftermarket equipment beyond $1,000 aggregate not declared on the policy. | +| **EXCL-11** | Diminution in value (first-party) | PP-00-01 §B.9 | First-party DV is not a covered loss. | +| **EXCL-12** | Misrepresentation / fraud | PP-00-01 Conditions §3 | Material misrepresentation in the application or in the presentation of a claim. Voids coverage ab initio for the claim. Requires SIU and Claims Legal sign-off. | + +### 4.1 Denial Procedure +Before issuing any denial: (1) confirm the facts supporting the exclusion are documented in the file with source (statement, police report, DMV record, inspection); (2) confirm the cited policy form and edition match the insured's declarations page; (3) run the denial past the authority matrix in Section 6.2; (4) generate the denial letter from the template library — free-typed denial letters are prohibited. Denials citing EXCL-03, EXCL-06, or EXCL-08 must attach the underlying evidence (MVR printout, toxicology summary, or theft report) to the file before the letter is released. Denials must be sent by first-class mail and, where the insured has opted in, by email; certified mail is required for EXCL-07 and EXCL-12. + +### 4.2 Appeals & Reconsideration +The insured or claimant may appeal any denial in writing within 60 days of the denial letter date. Appeals are logged under file activity code `APPEAL` and routed to a Senior Adjuster who did not handle the original decision. The reviewer must issue a written appeal decision within 21 days, either affirming the denial (with additional explanation addressing each point raised) or reversing and authorizing payment. A second-level appeal goes to the Claims Manager and is the final internal step; the response must include the state DOI contact information regardless of outcome. + +**Partial denials:** When only a portion of the claim is excluded (e.g., mechanical failure caused a collision — collision damage covered, engine repair excluded under EXCL-04), issue a partial denial letter itemizing covered vs. excluded amounts. + +--- + +## Section 5: Fraud Indicators & SIU Escalation + +### 5.1 Fraud Indicator Scoring Rubric +Score each claim at FNOL and again at estimate review. Assign points per indicator present; a cumulative score of **6 or higher** requires mandatory SIU referral via form SIU-REF-1. Scores of 3–5 require supervisor review before payment. + +| Indicator | Points | +|---|---| +| Loss reported >30 days after occurrence without documented reason | 2 | +| Policy incepted or coverage increased ≤30 days before loss | 3 | +| Prior claims frequency: ≥3 claims in 36 months on same policy or insured | 2 | +| Damage inconsistent with described facts (e.g., rear damage in claimed frontal collision) | 3 | +| No police report on theft, vandalism, or hit-and-run | 2 | +| Insured pushes for quick cash settlement, refuses inspection | 2 | +| Vehicle purchased ≤60 days before total-loss theft or fire | 3 | +| All damage is pre-existing per CARFAX/prior photos | 4 | +| Claimant/insured is evasive, contradictory, or coached in recorded statement | 2 | +| Medical treatment grossly disproportionate to impact severity (MIST claim) | 2 | +| Same body shop, clinic, or attorney appears in ≥3 flagged claims in 12 months | 3 | +| Receipts, title, or documents show signs of alteration | 4 | +| Insured has financial distress indicators (bankruptcy, repossession notice on file) | 1 | +| VIN inconsistencies between title, dash plate, and door jamb | 4 | + +### 5.2 Mandatory SIU Referral Triggers (regardless of score) +- Any theft or fire total loss with vehicle value >$25,000 +- Any claim where EXCL-01 (intentional) or EXCL-12 (fraud) denial is contemplated +- Staged-accident pattern match from ISO ClaimSearch or NICB alert +- Owner-give-up indicators: vehicle recovered stripped in <72 hours, keys in ignition, insured behind on payments +- Any claim where an involved party is on the internal Watch List + +### 5.3 SIU Handling Rules +Once referred, the field adjuster **must not** issue payment, take a final recorded statement, or send a denial without SIU written concurrence. SIU has 14 calendar days to accept or return the referral. If SIU accepts, the claim is placed in status `HOLD-SIU` and regulatory-clock extensions must be requested per Section 8. + +### 5.4 Examination Under Oath (EUO) +An EUO is a formal, sworn examination of the insured conducted by Claims Legal or retained counsel, authorized under the policy's Duties After Loss condition. Request an EUO when: SIU score ≥8; documentary evidence is materially inconsistent; or the loss exceeds $40,000 with any single 3-point indicator present. The EUO demand letter (CORR-EUO-01) must give at least 14 days' notice, offer at least two date options, and list the documents the insured must bring (title, finance contract, phone records, bank statements for 90 days pre-loss, all keys). An insured's unexcused failure to appear after two properly noticed EUO dates is a breach of policy conditions and supports denial — but only with Claims Legal written concurrence. EUO transcripts are privileged work product; do not share with claimants or third parties. + +### 5.5 NICB & Law Enforcement Coordination +SIU is the sole point of contact with the National Insurance Crime Bureau and law enforcement. Field adjusters do not contact police detectives directly regarding fraud suspicion. When SIU confirms probable fraud, SIU files the state fraud bureau referral (mandatory in CA, FL, NJ, NY, MA within 60 days of determination) and NICB questionable-claim submission. A fraud denial under EXCL-12 may be issued before criminal resolution, but any reference to criminal proceedings in customer correspondence must be pre-approved by Claims Legal. + +--- + +## Section 6: Authority Limits & Approval Matrix + +### 6.1 Payment Authority +Authority is measured against **gross indemnity** on the claim (all features combined), not net of deductible. + +| Role | Indemnity Authority | Reserve Authority | Expense Authority | +|---|---|---|---| +| Adjuster I | $7,500 | $15,000 | $1,000 | +| Adjuster II | $15,000 | $30,000 | $2,500 | +| Senior Adjuster | $50,000 | $100,000 | $5,000 | +| Claims Supervisor | $100,000 | $200,000 | $10,000 | +| Claims Manager | $150,000 | $300,000 | $25,000 | +| Regional Claims Director | $500,000 | $1,000,000 | $75,000 | +| Large Loss Committee | Unlimited | Unlimited | Unlimited | + +### 6.2 Escalation Rules +- Any single payment exceeding role authority requires **written approval** from the next level up in ClaimCenter before check issuance. +- The Large Loss Committee (Claims VP, Claims Legal, Actuarial, Regional Director) must review any claim reserved >$500,000, any claim with extra-contractual (bad faith) exposure, and any fatality. +- Authority is **reduced by 50%** for any claim with an SIU score ≥3 until SIU clears the file. +- Coverage denials (full denial of a claim feature) require Senior Adjuster or above, plus a Coverage Opinion memo on file for denials citing EXCL-01, EXCL-06, EXCL-07, or EXCL-12. + +### 6.3 Reserve Adequacy +Reserves must reflect probable ultimate exposure, not best-case. Reserves are reviewed at 30/60/90 days and at any adverse development. Stair-stepping (repeated small reserve increases to avoid authority triggers) is prohibited and audited monthly. + +--- + +## Section 7: Customer Communication Templates + +Use the following approved language blocks. Do not alter bracketed regulatory text. Full templates are in the Correspondence Library (CORR-LIB-24). + +### 7.1 Acknowledgment of Claim (Template ACK-01) +> "We have received your claim reported on [DATE OF FNOL] regarding a loss occurring on [DATE OF LOSS]. Your claim number is [CLAIM #]. Your adjuster is [NAME], who can be reached at [PHONE/EMAIL]. We will complete our investigation and advise you of our coverage decision within the timeframe required by your state." + +### 7.2 Request for Information (Template RFI-03) +> "To continue our evaluation of your claim, we need the following documents: [LIST]. Please provide these within 15 days of this letter. Failure to provide requested documentation may delay resolution and, where permitted by your policy, may affect coverage. [Insert state-specific cooperation clause language.]" + +### 7.3 Payment / Approval (Template PAY-02) +> "We have completed our review and have approved payment in the amount of $[AMOUNT], representing [DESCRIPTION: e.g., cost of repair less your $500 collision deductible]. Payment has been issued to [PAYEE] on [DATE]. If you or your repair facility identify additional damage related to this loss, please contact your adjuster before repairs are performed." + +### 7.4 Partial Denial (Template DEN-PART-01) +> "We have approved $[COVERED AMOUNT] for the covered portion of your loss. However, we are unable to pay $[EXCLUDED AMOUNT] for [ITEM], because [plain-language reason]. This determination is based on the following policy provision: '[QUOTE POLICY LANGUAGE]' (Exclusion [EXCL-CODE]). You have the right to appeal this decision as described below." + +### 7.5 Full Denial (Template DEN-FULL-01) +> "After careful review, we must respectfully deny coverage for this claim. Our investigation determined that [factual basis]. Your policy excludes coverage for this loss under [EXCL-CODE]: '[QUOTE POLICY LANGUAGE].' [Insert state-mandated appeal rights and DOI contact paragraph — CORR-LIB-24 Appendix B.] This denial does not waive any other policy terms, conditions, or defenses." + +### 7.6 Total Loss Settlement Offer (Template TL-04) +> "We have determined your vehicle to be a total loss. Based on market valuation of comparable vehicles in your area, the Actual Cash Value of your [YEAR MAKE MODEL] is $[ACV]. Adding sales tax of $[TAX] and title/registration fees of $[FEES], and subtracting your deductible of $[DED], our settlement offer is $[NET]. A copy of the valuation report is enclosed. Please sign and return the enclosed Power of Attorney and title documents." + +### 7.7 Reservation of Rights (Template ROR-01) +> "We are investigating this claim under a reservation of rights. This means we have identified a question as to whether coverage applies, specifically regarding [ISSUE]. We will continue to investigate and defend as appropriate, but we reserve the right to deny coverage, withdraw from defense, or seek reimbursement if it is determined that coverage does not apply. This letter is not a denial." + +--- + +## Section 8: Regulatory & Timeline Requirements + +### 8.1 Unfair Claims Practices — General Standards +All handling must comply with the NAIC Unfair Claims Settlement Practices Model Act as adopted in each state. Core obligations: acknowledge claims promptly, investigate promptly and fairly, affirm or deny coverage within a reasonable time, offer fair settlement when liability is reasonably clear, and provide a written explanation for any denial citing specific policy language. + +### 8.2 State Timeline Matrix +The table below reflects the strictest deadlines for high-volume states. Where the insured's state is not listed, apply the **default row**. All days are calendar days from receipt unless noted. + +| State | Acknowledge FNOL | Begin Investigation | Accept/Deny Decision | Pay After Acceptance | Status Letter Interval | +|---|---|---|---|---|---| +| CA | 15 days | 15 days | 40 days from proof of claim | 30 days | Every 30 days | +| TX | 15 days | 15 days | 15 business days from all docs | 5 business days | n/a (statutory) | +| FL | 14 days | Upon receipt | 90 days | 20 days | Every 30 days | +| NY | 15 business days | 15 business days | 15 business days from proof | 5 business days | Every 90 days | +| IL | 15 days | 30 days | 60 days | 30 days | Every 60 days | +| GA | Prompt | Prompt | 60 days from proof | 10 days | Every 60 days | +| PA | 10 days | 30 days | 15 days from proof | Prompt | Every 45 days | +| MI | Prompt | Prompt | 60 days (PIP: 30 days) | 30 days | Every 30 days | +| **Default** | 15 days | 15 days | 30 days from proof | 10 days | Every 30 days | + +### 8.3 Clock Management Rules +- The "proof of claim" clock starts when **all** documentation reasonably necessary to decide the claim has been received — not at FNOL. Document each RFI and each receipt in the file notes to establish the clock. +- If unable to accept or deny within the statutory window, send a written status/delay letter citing the specific reason and the additional time needed, and diary the file for the next interval. +- SIU referral does **not** automatically toll the statutory clock. Request an extension in writing and, where required (CA, NY), notify the insured that the claim is under investigation. +- Interest penalties accrue on late payments in TX (18% annual), FL (statutory rate), NY (2%/month on PIP), and MI (12% on PIP). Late-payment interest is coded to expense, not indemnity, and is reportable on the adjuster's quality scorecard. + +### 8.4 Record Retention +All claim files, including photos, estimates, correspondence, and recorded statements, are retained for 7 years after closure (10 years for BI claims involving a minor, measured from the minor's 18th birthday). Litigation-hold notices override standard retention and suspend all destruction. + +### 8.5 Complaint Handling +Any written complaint from an insured, claimant, attorney, or Department of Insurance must be logged in the Complaint Register within 24 hours and escalated to the Claims Supervisor. DOI complaints require a written response within the timeframe stated in the DOI letter (typically 15–21 days) and must be reviewed by Claims Compliance before sending. + +--- + +*End of Manual — Revision 2024.3. Direct questions to Claims Technical Unit, ext. 4400.* diff --git a/content/github/claude-cookbooks/latency_optimization/desk_agent/_gen/section9_desk_settlement.md b/content/github/claude-cookbooks/latency_optimization/desk_agent/_gen/section9_desk_settlement.md new file mode 100644 index 0000000000..0238dea094 --- /dev/null +++ b/content/github/claude-cookbooks/latency_optimization/desk_agent/_gen/section9_desk_settlement.md @@ -0,0 +1,74 @@ + +--- + +## Section 9: Desk Settlement Procedure (Live Calls) + +Use this procedure when an adjuster asks for a settlement figure on a first-party physical damage claim while the customer is on the line. Work the steps in order, using only facts in the claim file. Sections 1 to 6 supply the tables and definitions; where they leave room for interpretation, this section controls. Documentation, correspondence, sign-off and regulatory steps (Sections 2, 7 and 8, and 4.1, 4.2, 5.3 to 5.5, 6.2 and 6.3) happen after the call and never change the verdict or the amount. + +### 9.1 Coverage in force +An endorsement counts only if its effective date is on or before the date of loss. This applies everywhere an endorsement matters below. +The date of loss must fall on or after policy inception. If the policy lapsed, a loss on or after the lapse date and before the reinstatement date is excluded (EXCL-07). A loss on or after the reinstatement date is covered. Not in force: verdict DENY. + +### 9.2 Exclusions +Apply the Section 4 table, including the limits written into each row. In particular: EXCL-08 never applies to a family member who lives in the insured's household (same address as the named insured); it does apply to family members who live elsewhere and to people who are not family; a named excluded driver is EXCL-03 whatever their relationship or permission; EXCL-05 does not apply when END-CU-22 is on the policy. An exclusion that reaches the whole loss: verdict DENY. A denial is reported as DENY whichever role has to sign it. EXCL-04 and EXCL-10 only remove or limit individual estimate lines (9.4). + +### 9.3 Which coverage responds +Classify the cause of loss under 1.1 or 1.2. A parked vehicle struck by another vehicle is Collision. If the policy does not carry the coverage that responds: verdict DENY. The deductible used in 9.6 is the deductible of the coverage that responds. + +### 9.4 Adjusted repair cost +Re-price every estimate line against Appendix A; the shop's billed figures are never used as is. +1. Area: a catalogue line whose Appendix A area is not among the areas the appraiser confirmed is not loss-related and is removed in full (EXCL-04). Use the Area column exactly as printed; LH or RH in a part name does not change the area. Lines without a catalogue number (refinish, paint and materials, sublet, aftermarket) have no area and are never removed under this item. +2. Duplicates: a catalogue number is paid once per claim. Later lines with the same number are removed. +3. Part price: the lower of the billed price and the Appendix A list price. +4. Labor: the lower of the billed hours and the Appendix A book hours, x the lower of the shop's rate and the 3.4 cap for the shop's state and that labor type. + Included operations: where a line that survives items 1 and 2 has entries in the Appendix A column "Book hours include the labor for", no labor is paid on those catalogue numbers anywhere on the estimate. Their parts are still paid. This holds for ordinary and supplement lines alike, and even when the including line's own labor is not paid. +5. Wear items (Appendix A wear category, 3.3 schedule): part age = whole years from the date the part was last replaced per the service history, or from the vehicle's first in-service date if it never was, to the date of loss. Depreciation percent = yearly rate x (age - the years stated after "after year", if any), never below 0% and never above the stated maximum. It reduces the payable part price only, not the labor. +6. Refinish labor: payable hours = the lower of the billed hours and the refinish allowance, which is 1.5 hours for each Appendix A refinish panel that survives items 1 and 2 (ordinary and supplement lines alike), plus 1.0 hour for blending, which is allowed even when no refinish panel survives. The rate cap applies. No depreciation is taken on refinish labor or on paint and materials. + Paint and materials: the lower of the billed amount and $40 x the payable refinish hours. If the result is above $450 it is paid at $450 unless an itemized paint and materials invoice is on file. + Sublet lines with an invoice on file are paid as billed. +7. Aftermarket (custom) equipment lines are paid up to $1,000 in total across all such lines, unless a custom equipment schedule is in effect, in which case they are paid in full (EXCL-10). +8. Supplement lines sent after the work was already finished, with no supervisor approval on file, are re-priced under items 1 to 5 and then paid up to $500 in total (3.7). Supplements requested before the work and approved are ordinary lines. The 25% and 50% review thresholds in 3.7 are handled after the call. +The adjusted repair cost is the sum of what remains. + +### 9.5 Total loss test +ACV = market valuation + unscheduled aftermarket equipment with receipts (at most $1,000) - 50% of the estimated cost of prior unrepaired damage (3.2). The vehicle is a total loss when adjusted repair cost x 1.10 (the supplement reserve) is at or above the threshold percentage of ACV. The threshold is 75%, or the 3.5 figure for the state where the vehicle is garaged (the policy address) where that is higher. Leave rental and salvage handling out of the desk test. +- Total loss: vehicle amount = ACV + sales tax on the ACV at the rate shown in the file + the title fee. +- Otherwise: vehicle amount = adjusted repair cost. +Prior damage is already inside ACV; do not subtract it again. + +### 9.6 Deductible +Subtract the deductible from the vehicle amount, not below zero, unless 3.1 waives it. The fault-based waiver needs both conditions: the insured is 0% at fault and the other carrier has accepted 100% liability. + +### 9.7 Towing and rental +Towing per 3.9. Rental per 1.6, only if a rental endorsement is on the policy: payable days = calendar days from the later of rental pickup and delivery to the shop, to the earlier of rental return and repair completion or settlement (May 3 to May 10 is 7 days); daily rate = the lower of the billed rate and the daily limit; the result is capped at the aggregate limit. The deductible does not apply to towing or rental. + +### 9.8 Amounts +Gross indemnity = vehicle amount before the deductible + payable towing + payable rental. +Amount payable = vehicle amount after the deductible + payable towing + payable rental. + +### 9.9 Fraud score +Score the claim with the 5.1 table, counting only indicators the file supports. +- Day counts are calendar days between the two dates (June 1 to July 1 is 30 days). +- A window of N months ending on the date of loss runs from the same calendar day N months earlier up to the day before the date of loss. +- Only the policy inception date and "limits increased" entries in the change log count for the 30-day indicator, each counted from the date printed. A reinstatement does not. +- Prior claim frequency counts this policyholder's ledger rows with status "paid" and a loss date in the 36 months ending on this date of loss. Claims closed without payment and the current claim are not counted. +- The repair shop indicator counts ledger rows, for any policyholder, at the shop on this estimate, with SIU flag Y and a loss date in the 12 months ending on this date of loss. The full shop name must match; shops with similar names are different businesses. +- "Damage inconsistent with described facts" is scored only when the appraiser says so in the file notes, or when two or more estimate lines were removed under 9.4 item 1. Do not score it on your own view of the estimate. +- The police report indicator applies only to theft, vandalism and hit-and-run losses. +- Financial distress is scored only on what the 5.1 row names. A lapse for non-payment is not a financial distress indicator. +Also check the 5.2 mandatory triggers. Only two can be decided from a desk file: the Watch List trigger, and the theft or fire total loss trigger (any theft or fire loss that 9.5 tests as a total loss, with the 9.5 ACV above $25,000). The owner-give-up trigger applies only to a stolen vehicle that has been recovered; a repossession notice on its own is the 1-point financial distress indicator, not a trigger. + +### 9.10 Verdict +Take the first row that applies. An amount payable of $0 is still APPROVE or SUPERVISOR, not DENY. + +| Condition | Verdict | Amount to report | +|---|---|---| +| 9.1, 9.2 or 9.3 ends the claim | DENY | 0 | +| Score of 6 or more, or any 5.2 trigger | FRAUD (SIU referral; no payment, 5.3) | 0 | +| Score of 3 to 5 | SUPERVISOR | amount payable | +| Gross indemnity above the handling adjuster's indemnity authority (6.1) | SUPERVISOR | amount payable | +| Otherwise | APPROVE | amount payable | + +### Appendix A: Parts and Labor Catalogue + +CATALOGUE_TABLE diff --git a/content/github/claude-cookbooks/latency_optimization/latency_optimization.ipynb b/content/github/claude-cookbooks/latency_optimization/latency_optimization.ipynb new file mode 100644 index 0000000000..cdf4bdb51f --- /dev/null +++ b/content/github/claude-cookbooks/latency_optimization/latency_optimization.ipynb @@ -0,0 +1,2793 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0110-title", + "metadata": {}, + "source": [ + "# Latency Optimization on the Claude API" + ] + }, + { + "cell_type": "markdown", + "id": "0120-intro", + "metadata": {}, + "source": [ + "Optimizing LLM workloads is a balancing act between quality, cost, and latency. Most of our cookbooks cover output quality, and the [cost optimization cookbook](https://platform.claude.com/cookbook/cost-optimization-cost-optimization) covers spend. This one is about making your Claude-powered experience as fast as possible.\n", + "\n", + "You might need lower latency to deliver a real-time product experience, like a call center voice agent. You might have time-sensitive dependencies, like a fraud check that has to be cleared before payment authorization times out. Or the result might lose value the longer it takes, such as in summarizing an earnings call for traders before the market reacts.\n", + "\n", + "Whatever the use case may be, we measure latency in three ways. Time to first token (TTFT) is how long it takes to see *any* response from the model. Time to last token (TTLT) is how long it takes to get the entire final response. Output tokens per second (OTPS) is the rate at which the response is generated between the two. This cookbook covers how to improve all three through the following levers:\n", + "\n", + "1. **[Input token management](#input-token-management)**: send fewer tokens on each call, then stop reprocessing the same prefix with [prompt caching](#prompt-caching), pre-warm the cache, and avoid resending the conversation with message threads\n", + "2. **[Agent loop efficiency](#agent-loop-efficiency)**: compact in the background so no turn waits on it, hand independent work to subagents, and make fewer round trips\n", + "3. **[Output token management](#output-token-management)**: prompt for shorter answers or use structured outputs\n", + "4. **[Model, effort, and thinking](#model-effort-and-thinking)**: speed up output with fast mode, tune effort per request or per turn, or choose a different model and whether it thinks\n", + "5. **[Limiting the longest task](#limiting-the-longest-task)**: bound the slowest tasks with limits enforced by your code or the API\n", + "6. **[User experience design](#user-experience-design)**: stream outputs and show loading states to minimize perceived wait time while the model is working\n", + "\n", + "It's relatively easy to make a fast agent, but harder to make a fast agent that maintains your desired behavior. So first we'll cover how to build an eval that measures latency and establishes a quality bar to hillclimb against." + ] + }, + { + "cell_type": "markdown", + "id": "0200-prerequisites", + "metadata": {}, + "source": [ + "\n", + "## Prerequisites\n", + "\n", + "> **Note**: Running this cookbook top to bottom costs ~$20 in API credits. We recommend only running cells live when you want to experiment with the inputs. Latency changes with service conditions, so results may not replicate from run to run. Additional variables that impact latency beyond API levers are enumerated in [§Limitations](#limitations).\n", + "\n", + "To run this notebook, you will need:\n", + "\n", + "- **Anthropic API key** to call the Claude API ([get your API key](https://platform.claude.com/settings/keys))\n", + "- **Python 3.11 or later** with the `anthropic` (2.2.0 or later), `matplotlib`, `numpy`, and `python-dotenv` packages\n", + "- **This cookbook's folder** from the [cookbooks repo](https://github.com/anthropics/claude-cookbooks): `desk_agent/` (tasks, simulated tools, and graders), `results/` (the logged runs), `latency_stats.py` (statistics, tables, and charts), and `assets/` (the mock data)" + ] + }, + { + "cell_type": "markdown", + "id": "0205-setup", + "metadata": {}, + "source": [ + "\n", + "## Setup\n", + "\n", + "Start the notebook from this cookbook's folder, `latency_optimization/`, because it reads `assets/`, `results/`, and `desk_agent/` by relative path. Create a `.env` file in this directory containing `ANTHROPIC_API_KEY=your-anthropic-api-key`, then install and import the dependencies." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "0210-pip", + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "%pip install --upgrade \"anthropic>=2.2.0\" matplotlib numpy python-dotenv" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "0220-imports", + "metadata": {}, + "outputs": [], + "source": [ + "import base64\n", + "import csv\n", + "import io\n", + "import json\n", + "import random\n", + "import statistics\n", + "import threading\n", + "import time\n", + "from concurrent.futures import ThreadPoolExecutor\n", + "from dataclasses import dataclass, replace\n", + "from pathlib import Path\n", + "\n", + "import anthropic\n", + "import desk_agent # the tasks, simulated tools, and graders, in the folder beside this notebook\n", + "import httpx2 # the SDK's HTTP library\n", + "import matplotlib.pyplot as plt\n", + "from dotenv import load_dotenv\n", + "from IPython.display import display\n", + "from latency_stats import (\n", + " Sweep,\n", + " curve_chart,\n", + " frontier_chart,\n", + " in_words,\n", + " rank_row,\n", + " show,\n", + " show_task,\n", + " speed_chart,\n", + " table,\n", + ")\n", + "\n", + "load_dotenv()\n", + "# Retries are off so that timed_stream() can retry outside the timing.\n", + "client = anthropic.Anthropic(max_retries=0)" + ] + }, + { + "cell_type": "markdown", + "id": "0230-config", + "metadata": {}, + "source": [ + "Now define the base models and pricing schemas. The pricing table below defines cache rates and fast mode [list prices](https://platform.claude.com/docs/en/about-claude/pricing) at the time of writing (October 16, 2026). `BASE` is our baseline: Opus 5.5 at its default `medium` effort. We start from Opus 5.5 because it gets most tasks right, and there's no point speeding up a configuration that can't do the work in the first place. The other levers we work through then focus on bringing its latency down." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "0240-config", + "metadata": {}, + "outputs": [], + "source": [ + "OPUS, SONNET, HAIKU = \"claude-opus-5-5\", \"claude-sonnet-5-5\", \"claude-haiku-5-5\"\n", + "MODELS = (OPUS, SONNET, HAIKU)\n", + "NAME = {OPUS: \"Opus 5.5\", SONNET: \"Sonnet 5.5\", HAIKU: \"Haiku 5.5\"}\n", + "\n", + "# $ per million tokens on October 16, 2026, from https://platform.claude.com/docs/en/about-claude/pricing\n", + "PRICE = {\n", + " OPUS: {\"input_tokens\": 4.00, \"cache_write\": 5.00, \"cache_read\": 0.20, \"output_tokens\": 20.00},\n", + " SONNET: {\"input_tokens\": 2.00, \"cache_write\": 2.50, \"cache_read\": 0.10, \"output_tokens\": 10.00},\n", + " HAIKU: {\"input_tokens\": 0.10, \"cache_write\": 0.125, \"cache_read\": 0.01, \"output_tokens\": 0.50},\n", + "}\n", + "FAST_PRICE = 2.0 # fast mode multiplies every rate by this\n", + "EFFORTS = (\"low\", \"medium\", \"high\")\n", + "JOBS = {\"letter\": \"letter\", \"quote\": \"quote\", \"prescreen\": \"pre-screen\"}\n", + "PLAIN = {\"loop\": \"plain\", \"commentary\": \"free\"}\n", + "LOOPS = {\n", + " \"baseline loop\": PLAIN,\n", + " \"prefetch\": PLAIN | {\"loop\": \"prefetch\"},\n", + " \"bigger pages\": PLAIN | {\"loop\": \"big_pages\"},\n", + " \"no commentary\": PLAIN | {\"commentary\": \"none\"},\n", + " \"prefetch + bigger pages\": PLAIN | {\"loop\": \"prefetch+big_pages\"},\n", + "}\n", + "\n", + "\n", + "@dataclass(frozen=True)\n", + "class Config:\n", + " \"\"\"One setting: what the request asks for, and what the agent loop does around it\"\"\"\n", + "\n", + " model: str = OPUS\n", + " effort: str = \"medium\"\n", + " thinking: str = \"adaptive\" # or \"disabled\" (Haiku 5.5) or \"between_tools\" (Sonnet 5.5)\n", + " speed: str = \"standard\" # or \"fast\", on Opus 5.5 only\n", + " loop: str = \"plain\" # or \"prefetch\", \"big_pages\", \"prefetch+big_pages\"\n", + " commentary: str = \"free\" # or \"none\": the system prompt asks for no text around tool calls\n", + "\n", + " def kwargs(self):\n", + " \"\"\"The request parameters this setting fixes\"\"\"\n", + " thinking = {\"type\": self.thinking}\n", + " if self.thinking == \"adaptive\":\n", + " thinking[\"display\"] = \"omitted\"\n", + " kw = {\"model\": self.model, \"thinking\": thinking, \"output_config\": {\"effort\": self.effort}}\n", + " if self.speed == \"fast\":\n", + " kw |= {\"speed\": \"fast\", \"betas\": [\"fast-mode-2026-02-01\"]}\n", + " return kw\n", + "\n", + " def dollars(self, tokens):\n", + " \"\"\"tokens: the four counts in PRICE, for one call or summed over a task\"\"\"\n", + " usd = sum(tokens[kind] * rate for kind, rate in PRICE[self.model].items()) / 1e6\n", + " return usd * (FAST_PRICE if self.speed == \"fast\" else 1)\n", + "\n", + " def with_loop(self, name):\n", + " \"\"\"A copy of this setting with the loop and commentary of LOOPS[name]\"\"\"\n", + " return replace(self, **LOOPS[name])\n", + "\n", + " @property\n", + " def loop_name(self):\n", + " return next(name for name in LOOPS if self == self.with_loop(name))\n", + "\n", + " @property\n", + " def name(self):\n", + " name = f\"{NAME[self.model]} · {self.effort}\"\n", + " name += \" · thinking off\" if self.thinking == \"disabled\" else \"\"\n", + " name += \" · between tools\" if self.thinking == \"between_tools\" else \"\"\n", + " name += \" · fast mode\" if self.speed == \"fast\" else \"\"\n", + " return name + (f\" + {self.loop_name}\" if self.loop_name != \"baseline loop\" else \"\")\n", + "\n", + " @property\n", + " def order(self):\n", + " \"\"\"The key that tables sort settings by: the largest model and the highest effort first\"\"\"\n", + " model, effort = MODELS.index(self.model), -EFFORTS.index(self.effort)\n", + " loop = list(LOOPS).index(self.loop_name)\n", + " return (model, self.thinking != \"adaptive\", self.speed == \"fast\", effort, loop)\n", + "\n", + "\n", + "BASE = Config() # the baseline: Opus 5.5 at medium, its default effort, on the baseline loop" + ] + }, + { + "cell_type": "markdown", + "id": "0250-measuring", + "metadata": {}, + "source": [ + "\n", + "## Measuring latency\n", + "\n", + "We use the following equation to calculate how long a task takes and where that time is being spent:\n", + "\n", + "> TTLT ≈ calls × TTFT + output tokens ÷ OTPS + additional client- or server-side latency\n", + "\n", + "In other words, it's the wait before each model call starts responding (multiplied by the number of calls), plus the time it takes to write out every output token, plus any time spent outside the model, such as tool lookups or network hops. The sum is TTLT, or seconds per task, and we lower it by manipulating each variable:\n", + "\n", + "- **Calls**: each request to the model pays its own TTFT, and we make fewer of them in [§Agent loop efficiency](#agent-loop-efficiency).\n", + "- **TTFT**: every call has a floor that depends on the model, plus the time to read whatever part of the prompt isn't cached, which we shorten in [§Input token management](#input-token-management) by sending fewer tokens and caching what repeats from call to call.\n", + "- **Output tokens**: these include thinking tokens. We reduce them in [§Output token management](#output-token-management), and by lowering effort in [§Model, effort, and thinking](#model-effort-and-thinking).\n", + "- **OTPS**: this depends on the model, and fast mode raises it, as we show in [§Model, effort, and thinking](#model-effort-and-thinking).\n", + "- **Additional latency**: this covers time spent waiting on tools, the network, queues, and compaction. [§Agent loop efficiency](#agent-loop-efficiency) takes on the wait for compaction, and the full loop in [§Putting it all together](#putting-it-all-together) runs a turn's lookups side by side.\n", + "\n", + "**Percentiles:** The median (p50) is the time that half of all tasks finish within, and p90 is the time that 90% of tasks finish within. We're going to track both so we know what latency looks like for the typical and slow user experiences. When a lever moves one more than the other, it's important to prioritize the one your users feel more. A person on a call notices the long silences, while someone waiting on a finished result feels the typical wait. For rarer stalls, put [a limit on the longest task](#limiting-the-longest-task).\n", + "\n", + "**Timing:** We record latency using `timed_stream()`, as seen in the next cell. It starts a clock just before sending the request and records three moments as the reply streams in: the first thinking text, the first answer text (TTFT), and the end of the reply (TTLT). OTPS is estimated separately, by fitting the equation above to the recorded sweep, in [§Model, effort, and thinking](#model-effort-and-thinking)." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "0260-timing", + "metadata": {}, + "outputs": [], + "source": [ + "MAX_TOKENS = 16_000 # per model call: thinking, text, and tool calls\n", + "TIME_LIMIT = 60 # seconds for a whole task in run_task(), which stops it there\n", + "\n", + "\n", + "def timed_stream(deadline=None, **request):\n", + " \"\"\"One streamed request. Returns (message, marks): the seconds until the first thinking text (\"thinking\")\n", + " and the first answer text (\"text\"), each left out if none came, and until the end of the reply (\"done\").\n", + " deadline: a time.perf_counter() reading. At the deadline the reply is cut off and TimeoutError raised, with no\n", + " retry. A connection that goes completely silent can run past it: it ends once no data has arrived for as long as\n", + " was left when the request was sent\"\"\"\n", + " api = client.beta.messages if \"betas\" in request else client.messages\n", + " for tries_left in (2, 1, 0):\n", + " marks = {}\n", + " start = time.perf_counter()\n", + " if deadline is not None:\n", + " if start >= deadline:\n", + " raise TimeoutError\n", + " request[\"timeout\"] = deadline - start\n", + " try:\n", + " with api.stream(**request) as stream:\n", + " # At the deadline the watchdog closes the connection, which stops the loop below with an error\n", + " watchdog = None\n", + " if deadline is not None:\n", + " left = max(0.0, deadline - time.perf_counter())\n", + " watchdog = threading.Timer(left, stream.close)\n", + " watchdog.start()\n", + " try:\n", + " for event in stream:\n", + " if event.type == \"content_block_delta\":\n", + " kind = event.delta.type.removesuffix(\"_delta\")\n", + " if kind == \"text\" or (kind == \"thinking\" and event.delta.thinking):\n", + " marks.setdefault(kind, time.perf_counter() - start)\n", + " message = stream.get_final_message()\n", + " finally:\n", + " if watchdog:\n", + " watchdog.cancel()\n", + " if deadline is not None and time.perf_counter() >= deadline:\n", + " raise TimeoutError # the watchdog may have cut the reply short\n", + " return message, {**marks, \"done\": time.perf_counter() - start}\n", + " except Exception as e:\n", + " timed_out = isinstance(e, (anthropic.APITimeoutError, httpx2.TimeoutException))\n", + " if deadline is not None and (timed_out or time.perf_counter() >= deadline):\n", + " raise TimeoutError from None\n", + " retry = (anthropic.APIStatusError, anthropic.APIConnectionError, httpx2.TransportError)\n", + " if not isinstance(e, retry):\n", + " raise\n", + " # Retry everything except a request the API rejects (400 to 428)\n", + " if not tries_left or 400 <= getattr(e, \"status_code\", 500) < 429:\n", + " raise\n", + " if deadline is not None and time.perf_counter() + 10 >= deadline:\n", + " raise TimeoutError from None # no time left to wait and try again\n", + " time.sleep(10)\n", + "\n", + "\n", + "def token_counts(usage):\n", + " \"\"\"A reply's token counts, under the names the price table and the sweep's log use\"\"\"\n", + " details = getattr(usage, \"output_tokens_details\", None)\n", + " return {\n", + " \"input_tokens\": usage.input_tokens,\n", + " \"cache_write\": usage.cache_creation_input_tokens or 0,\n", + " \"cache_read\": usage.cache_read_input_tokens or 0,\n", + " \"output_tokens\": usage.output_tokens,\n", + " \"thinking_tokens\": details.thinking_tokens if details else 0,\n", + " }\n", + "\n", + "\n", + "def cached(block):\n", + " \"\"\"A copy of a content block with a cache breakpoint on it\"\"\"\n", + " return {**block, \"cache_control\": {\"type\": \"ephemeral\"}}\n", + "\n", + "\n", + "def single_request(content, cfg=BASE, *, system, cache=False, max_tokens=MAX_TOKENS, **more):\n", + " \"\"\"A request with one user message. cache=True puts a cache breakpoint at the end of the system prompt\"\"\"\n", + " system = [cached({\"type\": \"text\", \"text\": system})] if cache else system\n", + " messages = [{\"role\": \"user\", \"content\": content}]\n", + " return cfg.kwargs() | {\"max_tokens\": max_tokens, \"system\": system, \"messages\": messages} | more\n", + "\n", + "\n", + "def timed(request):\n", + " \"\"\"Sends one request. Returns its seconds and token counts, under the headings the demos' tables print\"\"\"\n", + " message, marks = timed_stream(**request)\n", + " counts = token_counts(message.usage)\n", + " return {\n", + " # the first thinking or answer text to arrive\n", + " \"first thing on screen, s\": min(marks.values()),\n", + " \"first answer text, s\": marks.get(\"text\", marks[\"done\"]),\n", + " \"done, s\": marks[\"done\"], # TTLT\n", + " \"cache read, tokens\": counts[\"cache_read\"],\n", + " \"cache write, tokens\": counts[\"cache_write\"],\n", + " \"output tokens\": counts[\"output_tokens\"],\n", + " \"of which thinking\": counts[\"thinking_tokens\"],\n", + " }\n", + "\n", + "\n", + "def compare(variants, repeats=3):\n", + " \"\"\"variants: {label: a function with no arguments that returns a dict of numbers, such as timed()'s}.\n", + " Calls each one `repeats` times. Returns {label: the median of each number}\"\"\"\n", + " runs = {label: [] for label in variants}\n", + " for _ in range(repeats): # alternating, so a change in load hits every variant\n", + " for label, run in variants.items():\n", + " runs[label].append(run())\n", + " return {\n", + " label: {k: statistics.median(r[k] for r in got) for k in got[0]}\n", + " for label, got in runs.items()\n", + " }\n", + "\n", + "\n", + "def show_medians(found, *columns):\n", + " \"\"\"Prints what compare() returns, one row for each variant\"\"\"\n", + " show({\"\": label} | {k: medians[k] for k in columns} for label, medians in found.items())" + ] + }, + { + "cell_type": "markdown", + "id": "0300-usecase", + "metadata": {}, + "source": [ + "\n", + "## Our example use case\n", + "\n", + "For this cookbook, the running example is a desk agent at Acme Insurance, a fictional insurer. The agent takes a claim, looks up what it needs with tools, and records its answer. Acme runs the agent in two products:\n", + "\n", + "- **The phone line** is a voice agent that people call. It's conversational, and until the agent responds the caller sits in silence, so it needs near-real-time latency. Here Acme optimizes for TTFT.\n", + "- **The chat agent** answers in a chat window. The app can show that the agent is working while it thinks, and the user expects a full result, so a slightly longer wait is acceptable. Here Acme optimizes for TTLT.\n", + "\n", + "Both run the same agent on a 154-task set in `desk_agent/`. We measure the effect of each lever with live demo cells you can rerun and with a recorded sweep, which runs those tasks under 33 different configurations of Claude Opus 5.5, Claude Sonnet 5.5, and Claude Haiku 5.5. The next cell loads the mock data and the pieces the demos share." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "0310-data", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10 claims · manual 29,526 characters · ledger 5,050 rows\n" + ] + } + ], + "source": [ + "POLICY_MANUAL = Path(\"desk_agent/_gen/policy_manual.md\").read_text() # the cost cookbook's manual\n", + "LEDGER_ROWS = Path(\"assets/claims_ledger.csv\").read_text().splitlines()\n", + "with open(\"assets/claims.csv\") as f:\n", + " CLAIMS = {r[\"id\"]: r for r in csv.DictReader(f)}\n", + "with open(\"assets/prior_claims.csv\") as f:\n", + " PRIORS = list(csv.DictReader(f))\n", + "MANUAL = \"=== UNDERWRITING MANUAL ===\\n\" + POLICY_MANUAL + \"\\n=== END MANUAL ===\"\n", + "MEMO_SYSTEM = (\n", + " \"You are a licensed auto-insurance claims adjuster. The file has already been reviewed. \"\n", + " f\"Write from the facts given and the manual below.\\n\\n{MANUAL}\"\n", + ")\n", + "QUESTION = \"Which section covers rental reimbursement?\"\n", + "TWO_LINES = \"DECISION: \\nWHY: \"\n", + "\n", + "\n", + "def ledger_system(tag, ledger_rows=None):\n", + " \"\"\"A tag, MEMO_SYSTEM, then the first ledger_rows lines of the paid-claims ledger (all of it by default).\n", + " A tag nobody has sent before makes a prefix the cache has never seen\"\"\"\n", + " paid = \"\\n\".join(LEDGER_ROWS[:ledger_rows])\n", + " return f\"({tag})\\n\\n{MEMO_SYSTEM}\\n\\n=== PAID CLAIMS ===\\n{paid}\"\n", + "\n", + "\n", + "def claim_record(cid):\n", + " \"\"\"What is on file for one claim: the record, the shop's estimate, and the policyholder's prior claims\"\"\"\n", + " claim, estimate = CLAIMS[cid], Path(f\"assets/estimates/{cid}.txt\").read_text()\n", + " priors = [json.dumps(p) for p in PRIORS if p[\"policyholder_id\"] == claim[\"policyholder_id\"]]\n", + " return (\n", + " f\"CLAIM RECORD\\n{json.dumps(claim, indent=1)}\\n\\nESTIMATE\\n{estimate}\\n\"\n", + " \"PRIOR CLAIMS\\n\" + (\"\\n\".join(priors) or \"none\")\n", + " )\n", + "\n", + "\n", + "print(\n", + " f\"{len(CLAIMS)} claims · manual {len(POLICY_MANUAL):,} characters · ledger {len(LEDGER_ROWS) - 1:,} rows\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "0310-jobs", + "metadata": {}, + "source": [ + "The agent starts with an underwriting manual in its system prompt and a one-line request, and every task offers it the same eight simulated tools. Five look things up and three record an answer, which is the output we grade.\n", + "\n", + "Each task is one of three jobs. A **letter** fills the right customer-letter template from the decision on file: one or two lookups, then visible output. A **quote** works a claim through the manual's settlement worksheet and records the verdict and amount, which takes paging through an estimate, pricing parts, and reasoning over rules. A **pre-screen** finds the prior claims that count under the fraud rubric and scores the claim, searching a ledger page by page.\n", + "\n", + "Within each job, tasks are sorted into difficulty levels by how much work they take, from easiest to hardest. [§Putting it all together](#putting-it-all-together) uses them to show accuracy on each job's hardest tasks." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "0320-tasks", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "154 tasks\n", + "tools: get_claim, get_estimate, lookup_parts, search_ledger, get_template, submit_quote, submit_prescreen, submit_letter\n" + ] + } + ], + "source": [ + "TASKS = desk_agent.load_items(\"final\")\n", + "print(f\"{len(TASKS)} tasks\")\n", + "print(\"tools: \" + \", \".join(t[\"name\"] for t in desk_agent.tool_specs()))" + ] + }, + { + "cell_type": "markdown", + "id": "0400-before", + "metadata": {}, + "source": [ + "\n", + "## Before you start\n", + "\n", + "Before we dive into the latency optimization methods, we need to make sure we have a robust eval that shows how each lever changes overall performance, since several levers below trade capability or cost for speed. Our eval scores the 154 tasks above on accuracy, TTFT, TTLT, and cost per task.\n", + "\n", + "The winning configuration has to be both accurate and fast, so we need to know what \"good enough\" looks like. Acme will tolerate one wrong answer in twenty, meaning at least 95% of tasks must be right. However, each product has different latency requirements: the phone line can't tolerate long silences at all (p90 TTFT), while the chat agent will accept longer sessions for hard cases (p50 TTLT). These targets are Acme's, so your goal configuration will depend on your own product, users, and tolerance for errors.\n", + "\n", + "We'll start from a simple agent loop with no latency levers. The next cell defines `baseline_task()`, which sends the conversation to the model, runs the lookups it asks for one after another, and sends the results back, until the model records an answer. A task is correct when every field it records matches the answer key." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "0444-bare-loop", + "metadata": {}, + "outputs": [], + "source": [ + "def baseline_task(task, cfg):\n", + " \"\"\"Runs one task until it records an answer or gives up, with no latency lever applied. cfg sets the\n", + " model, effort, and thinking. Returns its id, type, grade, and a row per model call\"\"\"\n", + " prompt = desk_agent.system_prompt()\n", + " tools = desk_agent.tool_specs()\n", + " first = desk_agent.first_turn(task)\n", + " history = [{\"role\": \"user\", \"content\": [{\"type\": \"text\", \"text\": first}]}]\n", + " calls, recorder, nudged = [], None, False\n", + " while True: # no cap on calls yet\n", + " start = time.perf_counter()\n", + " m = client.messages.create(\n", + " **cfg.kwargs(), max_tokens=MAX_TOKENS, system=prompt, tools=tools, messages=history\n", + " )\n", + " marks = {\"done\": time.perf_counter() - start}\n", + " history.append({\"role\": \"assistant\", \"content\": m.content}) # thinking blocks included\n", + " uses = [b for b in m.content if b.type == \"tool_use\"]\n", + " calls.append(\n", + " {\"secs\": marks[\"done\"], \"tools\": [b.name for b in uses], **token_counts(m.usage)}\n", + " )\n", + " if m.stop_reason in (\"max_tokens\", \"refusal\"): # counts as wrong\n", + " break\n", + " recorder = next((b for b in uses if desk_agent.is_terminal(b.name)), None)\n", + " if recorder or (nudged and not uses):\n", + " break\n", + " if not uses: # one reminder, then the task ends with nothing recorded\n", + " nudged = True\n", + " reminder = {\"type\": \"text\", \"text\": desk_agent.NUDGE_MESSAGE}\n", + " history.append({\"role\": \"user\", \"content\": [reminder]})\n", + " continue\n", + " results = [desk_agent.call_tool(task, b.name, b.input) for b in uses] # one after another\n", + " blocks = [\n", + " {\"type\": \"tool_result\", \"tool_use_id\": b.id, \"content\": r}\n", + " | ({\"is_error\": True} if r.startswith(\"ERROR: \") else {})\n", + " for b, r in zip(uses, results, strict=True)\n", + " ]\n", + " history.append({\"role\": \"user\", \"content\": blocks}) # one message, in call order\n", + " recorded = {\"name\": recorder.name, \"args\": recorder.input} if recorder else None\n", + " correct = bool(desk_agent.grade(task, recorded)[\"correct\"])\n", + " return {\"task\": task[\"id\"], \"type\": task[\"type\"], \"correct\": correct, \"calls\": calls}" + ] + }, + { + "cell_type": "markdown", + "id": "0444-measured", + "metadata": {}, + "source": [ + "We'll run the baseline on all 154 tasks using Opus 5.5 at `medium`, its default effort, and do it three times to minimize nondeterministic variance. The tools are simulated and every call gets the same fixed network time, so our timings isolate the model. Your backend services and network will add latency of their own, which is out of scope here and covered in [§Limitations](#limitations). A task's seconds are the sum of its calls' TTLTs. For the first visible token, we take the time the task's first call returned its first token, where a thinking token counts, and add the time that call spent thinking, estimated as its thinking tokens divided by its output speed.\n", + "\n", + "The next cell shows how time and tokens accumulate in one example task from our eval set." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "0446-tasks", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
callwaittools calledinput tokensoutput tokensof which thinking
Q1-002, call 11.0sget_claim, get_estimate15,8721080
Q1-002, call 21.5slookup_parts, search_ledger, search_ledger16,7121940
Q1-002, call 32.6ssubmit_quote17,152335254
" + ], + "text/plain": [ + "call wait tools called input tokens output tokens of which thinking\n", + "Q1-002, call 1 1.0s get_claim, get_estimate 15,872 108 0\n", + "Q1-002, call 2 1.5s lookup_parts, search_ledger, search_ledger 16,712 194 0\n", + "Q1-002, call 3 2.6s submit_quote 17,152 335 254" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "→ correct, 5.1s waiting on the model, $0.212\n", + "\n" + ] + } + ], + "source": [ + "# One task from the baseline's run, a quote.\n", + "# To run one live: show_task(baseline_task(TASKS[0], BASE), BASE)\n", + "examples = [json.loads(line) for line in open(\"results/examples.jsonl\")]\n", + "show_task(next(row for row in examples if row[\"type\"] == \"quote\"), BASE)" + ] + }, + { + "cell_type": "markdown", + "id": "0490-baseline", + "metadata": {}, + "source": [ + "Now we'll do that for the full eval suite by loading in results from `results/baseline.jsonl`. The output shows average latency, cost, and accuracy across three trials." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "0492-results-table", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
settingcorrectp50p90calls / taskoutput tokens / task$ / task
Opus 5.5 · medium99.0%6.1s11.3s3.5861$0.2512
" + ], + "text/plain": [ + "setting correct p50 p90 calls / task output tokens / task $ / task\n", + "Opus 5.5 · medium 99.0% 6.1s 11.3s 3.5 861 $0.2512" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "p50 is the average of the three rounds: 6.0s, 5.9s, 6.4s\n", + "p90 is the average of the three rounds: 10.6s, 11.2s, 12.2s\n" + ] + } + ], + "source": [ + "BASELINE = Sweep(\"results/baseline.jsonl\", Config)\n", + "display(BASELINE.results_table([BASE]))\n", + "for metric in (\"p50\", \"p90\"):\n", + " each = \", \".join(f\"{seconds:.1f}s\" for seconds in BASELINE.stat(BASE, metric)[:, 0])\n", + " print(f\"{metric} is the average of the three rounds: {each}\")" + ] + }, + { + "cell_type": "markdown", + "id": "0492-to-beat", + "metadata": {}, + "source": [ + "And these are the resulting p50 and p90 waits that Acme's products have to beat." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "0493-to-beat", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
productwaitp50p90optimizes for
Phone lineseconds to the first visible token0.56s0.70sp90
Chat agentseconds per task6.1s11.3sp50
" + ], + "text/plain": [ + "product wait p50 p90 optimizes for\n", + "Phone line seconds to the first visible token 0.56s 0.70s p90\n", + "Chat agent seconds per task 6.1s 11.3s p50" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from latency_stats import to_beat\n", + "\n", + "MEASURES = {\"Phone line\": \"first token p90\", \"Chat agent\": \"p50\"}\n", + "display(to_beat(BASELINE, BASE, MEASURES))" + ] + }, + { + "cell_type": "markdown", + "id": "0495-baseline-after", + "metadata": {}, + "source": [ + "So every latency optimization we make from here on has to keep accuracy at 95% or better while beating the phone line's p90 TTFT and the chat agent's p50 TTLT. Latency is noisy (the baseline's p90 TTLT alone varied by 1.6 seconds between rounds), so we'll only call a change significant when a bootstrap test puts it at *p* < 0.05. With our objectives defined, let's start hillclimbing." + ] + }, + { + "cell_type": "markdown", + "id": "0700-input", + "metadata": {}, + "source": [ + "\n", + "## Input token management\n", + "\n", + "The latency equation is a function of how many tokens the model has to process, so one simple lever is to send fewer tokens. When all of your input tokens are necessary, the next best option is to store them server-side with [prompt caching](#prompt-caching) or [message threads](#message-threads), such that they aren't reprocessed or resent on every call.\n", + "\n", + "\n", + "### Sending fewer tokens\n", + "\n", + "To see how much time a longer prompt adds, the cell below asks each model for a one-token reply to prompts of about 17,000 tokens (the size of our tasks' prompts), 100,000 tokens, and 200,000 tokens. Each prompt is new and nothing is cached. We'll run each prompt three times and plot the fastest, which leaves out moments when the service was busy." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "0710-prefill", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "model prompt tokens s\n", + "Opus 5.5 17,066 0.52\n", + "Opus 5.5 100,002 0.74\n", + "Opus 5.5 199,994 0.96\n", + "Sonnet 5.5 17,066 0.44\n", + "Sonnet 5.5 100,002 0.74\n", + "Sonnet 5.5 199,994 0.94\n", + "Haiku 5.5 17,066 0.50\n", + "Haiku 5.5 100,002 0.76\n", + "Haiku 5.5 199,994 1.02\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAmYAAAFoCAYAAAD9zjdnAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjIsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvgI3uAAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAjlNJREFUeJzs3XV8FNfawPHfSjauxN0hSHAvNRzaUofqrd63t+7uRt3djbob0hYqSHGHQJS4EZfN2rx/bLLJkgTCsiEJeb6fTy83M2dmzpzYkzPPPEdlMhkVhBBCCCFEj1P3dAeEEEIIIYSVBGZCCCGEEL2EBGZCCCGEEL2EBGZCCCGEEL2EBGZCCCGEEL2EBGZCCCGEEL2EBGZCCCGEEL2EBGZCCCGEEL1Evw7MmpqaMJlMPd2NfqGpqQmz2dzT3RAHYbFY0Ov1Pd2NDvXmvgkhhDP168Bs0KAU7r333iM6h16vx2KxOKlHx66wsHA+//zznu5Gv/t8HU5A8+uvvxISEkpdXV0396pznfX3q6++IiQktAd6JIQQR1e/DsycISQklK+++qqnu9Hrubm5odFoerob/e7z9eOPPxESEtpnZpv6Wn+FEMLZJDA7iKamJvR6PU1NTZ3uBzAajej1evR6PYrSfunRzmZoHJm9ObB9Z48IzWbzQX+5He5xHd3X4cjOzuKcc86xfdzVe2/b7mB96GjsTSYTBoPB9nFXP1+OXLttu7bXhM4//wfODnV0jc6ue+CxHV3DYrFgMhmB1q/lA/t2ODq7xqHu4WDnaft1eDj9PdKvRyGE6K0kMDuI8eMnEB0dQ1RUNJGRUZxyyqls2bLFtj8uLh6AG2+8iejoGKKjY8jLywOgurqaG2+8ifj4BAICBpCaOpwvvvjCdqxeryckJJSnnnqKefNOJzraeo0rrriS2tpau35UVVVx0003k5iYRGBgEJMmTWLx4sUAnH/+BZx//vnt+n7DDTdy0kknd3pv55xzLhdffHG77bfccitTphwPWH/5PfHEE6SkDCYwMIhhw1J56qmnHPrl3vZRZlfvvaXdwoULmTNnDlFR0YSFhXPNNdfS0NBga1dQUEBISCj//vuv3TVvvfU2zjjjDNvHB/t8Hair125p9+STTzJ79mxCQkI5/fTTAVi2bBlTphxPYGAQwcEhnH32OWRkZNiObXk899ZbbzF27DiCgoIZOHAQ7733Phs3bmLGjJkEBQUTHR3Dfffdb9e/lmM//vhjRo8eQ3BwCCkpg/nggw9tbZYuXcpVV/0PgKSkZKKjYzjllFMP/clqY/PmLcybdzrBwSEEBQUzd+5c9uzZ064fX3zxBePHTyA4OIRBg1J466232p3rq6++YtiwVAICBpCUlMyrr77KkCFDefPNN7vc365cRwgh+jIJzA5iy5bNlJaWUFpawrZt20hNHcY555xLdXU1AIWFBQC8+uortnbR0dGYzWbOOONMVqxYwRdffE5JSTEPPfQQ1113PX///bfdNd54402uv/56MjMzWbZsKX///TdPP/2Mbb/JZOK00+bx77//8vnnn1FcXMQ777zDzz//DMCVV17BsmW/kZubazumurqab775hssuu6zTe7voogtZunQZZWVltm2NjY18++03XHTRRQB8++13vPzyK3zwwfuUlZWyZMliLBaLXXB6JA517y1efPElrrjiSjIzM/j555/5668/ueOOOw/7ep19vg6mq9d+7bXXufHGGykoyOfXX39lx44dLFhwHjNnziAnJ5stWzY3f12cQWNjo92xP/30M9988zWFhQWcffbZ3HLLLVx22WXcf/99FBcX8eGHH/LKK6/w008/tbvuK6+8yieffExeXi633347N954I7///gcAs2fP5p133gEgN3cfpaUlLFu2tMvjtXv3bubMmYOfnx/btm0lKyuT5OSBnHHGme1mVT/66CM+++wziooKufvuu7jtttvZuHGTbf/GjRu58sr/8n//918KCwv47bdlfP/9D3Zff13p76GuI4QQfZ0EZl3k6enBvffeS11dHatXrz5o28WLF7Nx40aef/55xo4di6urK2eccToLFixoF3hce+21TJ16Mi4uLgwePJgzzjidNWvW2Pb//PMvbN26lXfffYcxY8ag0+kYPHgwr776KgAzZswgKirKbqbks88+Q61WM3/+uZ328dRTT8XDw8NuFu+nn36ivr6BBQvmA5Cfn09AQACjR49GrVYTERHBnXfeybhx47o+cAdxqHtvcd5553HmmWfg6urK6NGjuPfee1m0aJHdL/Xu0tVrX3HFFcycORMXFxcAnn/+BQYPHsy9996Lj48P4eHhvP76axQWFvH551/YHfv8888RHR2NTqfj6qv/h8Vi4bLLLuO4445Dq9Vy0kknkpqa2uHX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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def read_prompt(model, ledger_rows):\n", + " \"\"\"A one-token reply to a prompt nobody has sent before, with no caching, so its seconds go to reading the\n", + " prompt, plus a fixed overhead. Returns the prompt's tokens and the seconds\"\"\"\n", + " paid = \"\\n\".join((LEDGER_ROWS * 2)[:ledger_rows])\n", + " system = f\"(length {time.time_ns()})\\n\\n{MEMO_SYSTEM}\\n\\n=== PAID CLAIMS ===\\n{paid}\"\n", + " request = single_request(QUESTION, Config(model, \"low\"), system=system, max_tokens=1)\n", + " message, marks = timed_stream(**request)\n", + " return message.usage.input_tokens, marks[\"done\"]\n", + "\n", + "\n", + "# Ledger rows for about 17,000 prompt tokens (our tasks' size), 100,000, and 200,000\n", + "LENGTHS = (220, 3318, 7057)\n", + "runs = {(model, rows): [] for model in MODELS for rows in LENGTHS}\n", + "for repeat in range(3):\n", + " order = list(runs)\n", + " random.Random(repeat).shuffle(order)\n", + " for model, rows in order:\n", + " runs[model, rows].append(read_prompt(model, rows))\n", + "\n", + "# Each point is its fastest run\n", + "CURVE = [\n", + " {\"model\": NAME[model], \"prompt tokens\": got[0][0], \"s\": min(s for _, s in got)}\n", + " for (model, rows), got in runs.items()\n", + "]\n", + "show(CURVE, places=2)\n", + "curve_chart(CURVE)" + ] + }, + { + "cell_type": "markdown", + "id": "0712-length-after", + "metadata": {}, + "source": [ + "Going from the Desk Agent's 17,000 token input prompt to 200,000 tokens added about half a second on every model, which means roughly a quarter of a second per 100,000 tokens. That's a large share of the phone line's 0.70-second p90 TTFT, but a small part of the chat agent's 6.1-second p50, where most of the time goes to writing output. So for a near-real-time product, trimming the prompt can be a significant latency lever.\n", + "\n", + "There are three approaches to sending fewer tokens:\n", + "\n", + "- **Trim it.** Remove the parts of the prompt the task doesn't use. For images, [resize them](https://platform.claude.com/docs/en/build-with-claude/vision#evaluate-image-size) to the resolution the task needs, because a larger image costs more tokens and takes longer to process. In a long conversation, [context editing](https://platform.claude.com/docs/en/build-with-claude/context-editing) clears old tool results or thinking blocks the model no longer needs, and on the 5.5 models it [leaves earlier thinking valid](https://platform.claude.com/docs/en/build-with-claude/context-editing#context-editing-happens-server-side). If you use [prompt caching](#prompt-caching), each clear restarts the cache at that point, so the next call reads everything after it cold.\n", + "- **Defer it.** Keep context out of the prompt until the model needs it, also known as progressive disclosure. With [tool search](https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-search-tool), tools marked `defer_loading` stay out of the prompt until the model's search loads the ones it needs, which tends to pay off once tool definitions run past about 10,000 tokens. Skills do the same for instructions, where parts of a system prompt move behind a skill and load only when a task calls for them.\n", + "- **Make access efficient.** Give the model a narrower way to reach large context. A tool that returns the pages or fields a task needs keeps the rest of a long document out of the context. For tabular data, a CSV mounted into the [code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool) lets the model query it in a sandbox, so only the code and its output reach the context.\n", + "\n", + "Each of these can add an extra call or more tokens downstream, so let your eval decide what your input shape should be." + ] + }, + { + "cell_type": "markdown", + "id": "0500-caching", + "metadata": {}, + "source": [ + "\n", + "### Prompt caching\n", + "\n", + "Our agent resends the same tools, system prompt, and conversation history on every call, and the model has to reprocess all of that content before it can start outputting tokens. [Prompt caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching) stores the content that the model has already seen so later calls don't need to reprocess it, which makes caching a great lever for cutting TTFT. The prefix is the part at the start of the prompt that repeats from call to call, including the tools, system prompt, and prior messages, and it ends at a cache breakpoint, the marker for how much of the prompt to cache. The simplest way to start is with [automatic caching](https://platform.claude.com/docs/en/build-with-claude/prompt-caching#automatic-caching): add a single top-level `cache_control` to your request, which places the breakpoint for you.\n", + "\n", + "To add caching to the baseline, we use [explicit cache breakpoints](https://platform.claude.com/docs/en/build-with-claude/prompt-caching#explicit-cache-breakpoints) instead. This lets you place up to four breakpoints yourself, where each marks the end of a prefix that can be cached. Using more than one lets you match the parts of your prompt that change at different rates, so if a later part changes, the calls can still read the earlier ones from the cache. We'll use three of them here, with a `cache_control` marker on the system prompt, the first user turn, and the newest user turn. These are the lines that do it:\n", + "\n", + "```python\n", + "system = [{\"type\": \"text\", \"text\": prompt, \"cache_control\": {\"type\": \"ephemeral\"}}]\n", + "...\n", + " messages = list(history)\n", + " for k in {0, len(messages) - 1}:\n", + " *before, last = messages[k][\"content\"]\n", + " messages[k] = {\"role\": \"user\", \"content\": [*before, {**last, \"cache_control\": {\"type\": \"ephemeral\"}}]}\n", + "```\n", + "\n", + "Each request then sends `system` and `messages` instead of `prompt` and `history`. The next cell runs our eval with and without caching on all 154 tasks." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "0502-caching-sweep", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
settingcorrectcorrect vs first row, pointsfirst token p90first token p90 vs first rowp50p50 vs first rowcalls / taskoutput tokens / task$ / task
Opus 5.5 · medium · no caching99.0%0.70s6.1s3.5861$0.2512
Opus 5.5 · medium · caching98.4%-0.6 (-1.6 to +0.4)0.69s×0.98 (0.94 to 1.01)6.2s×1.01 (0.96 to 1.06)3.5856$0.0377
" + ], + "text/plain": [ + "setting correct correct vs first row, points first token p90 first token p90 vs first row p50 p50 vs first row calls / task output tokens / task $ / task\n", + "Opus 5.5 · medium · no caching 99.0% 0.70s 6.1s 3.5 861 $0.2512\n", + "Opus 5.5 · medium · caching 98.4% -0.6 (-1.6 to +0.4) 0.69s ×0.98 (0.94 to 1.01) 6.2s ×1.01 (0.96 to 1.06) 3.5 856 $0.0377" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "@dataclass(frozen=True)\n", + "class CachingConfig(Config):\n", + " \"\"\"A Config that also says whether the requests were cached, to tell the two baselines apart\"\"\"\n", + "\n", + " caching: str = \"on\" # or \"off\"\n", + "\n", + " @property\n", + " def name(self):\n", + " return super().name + (\" · caching\" if self.caching == \"on\" else \" · no caching\")\n", + "\n", + "\n", + "BOTH = Sweep([\"results/baseline.jsonl\", \"results/sweep.jsonl\"], CachingConfig)\n", + "no_caching = CachingConfig(caching=\"off\")\n", + "display(BOTH.results_table([CachingConfig()], base=no_caching, waits=tuple(MEASURES.values())))\n", + "\n", + "# The baseline caches from here on. Every setting in the sweep ran with caching on\n", + "SWEEP = Sweep(\"results/sweep.jsonl\", Config)" + ] + }, + { + "cell_type": "markdown", + "id": "0503-caching-sweep-after", + "metadata": {}, + "source": [ + "Caching cut the cost per task by 85% and didn't significantly change either product's wait or accuracy. The phone line's p90 TTFT went from 0.70 to 0.69 seconds and the chat agent's p50 TTLT from 6.1 to 6.2 seconds, both within run-to-run noise. Even if that small rise in p50 were real, we'd accept it to bring the cost per task from $0.25 down to $0.04, so caching stays on from here as the new baseline to beat. Our tasks are short and average 3.5 calls on prompts of about 17,000 tokens, so there's little prefix for a cache read to skip. \n", + "\n", + "The TTFT savings grow with the size of the prefix and the number of calls that reuse it, so on longer-horizon tasks with more turns they add up. The cell below times a two-turn conversation on a new system prompt of about 146,000 tokens, with no caching and then with the top-level `cache_control` added. The second turn resends the whole prompt and the first turn, which is where caching offers bigger latency wins. On that turn, `usage.cache_read_input_tokens` shows whether the cache was read. We run it on Haiku 5.5 at `low` effort, which keeps a prompt this long cheap to rerun, and report the median of five runs." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "0505-caching-demo", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " turn 1 turn 2 cache write, tokens cache read, tokens\n", + "BEFORE: no caching 1.6s 1.7s 0 0\n", + "AFTER: caching 1.2s 0.5s 146,605 146,312\n", + "\n", + "→ 1.2s faster with 146,312 tokens read from cache\n" + ] + } + ], + "source": [ + "TURNS = (QUESTION, \"What are its standard daily and aggregate limits?\")\n", + "\n", + "\n", + "def long_system():\n", + " \"\"\"A system prompt of about 146,000 tokens that the cache has never seen\"\"\"\n", + " return ledger_system(f\"caching demo {time.time_ns()}\")\n", + "\n", + "\n", + "def run_turns(system, cfg, cache):\n", + " \"\"\"Asks TURNS in one conversation. cache: turn on automatic caching. Returns the seconds until each\n", + " answer began, and the tokens written to the cache and read from it\"\"\"\n", + " history, calls = [], []\n", + " for turn in TURNS:\n", + " history.append({\"role\": \"user\", \"content\": turn})\n", + " request = cfg.kwargs() | {\"max_tokens\": MAX_TOKENS, \"system\": system, \"messages\": history}\n", + " if cache:\n", + " request[\"cache_control\"] = {\"type\": \"ephemeral\"} # the one line that turns caching on\n", + " m, marks = timed_stream(**request)\n", + " history.append({\"role\": \"assistant\", \"content\": m.content}) # thinking blocks included\n", + " calls.append(marks | token_counts(m.usage))\n", + " waits = {f\"turn {n}, s\": c.get(\"text\", c[\"done\"]) for n, c in enumerate(calls, 1)}\n", + " return waits | {\n", + " \"cache write, tokens\": sum(c[\"cache_write\"] for c in calls),\n", + " \"cache read, tokens\": sum(c[\"cache_read\"] for c in calls),\n", + " }\n", + "\n", + "\n", + "cfg = Config(HAIKU, \"low\")\n", + "found = compare(\n", + " {\n", + " \"BEFORE: no caching\": lambda: run_turns(long_system(), cfg, cache=False),\n", + " \"AFTER: caching\": lambda: run_turns(long_system(), cfg, cache=True),\n", + " },\n", + " repeats=5,\n", + ")\n", + "before, after = found.values()\n", + "show_medians(found, *before)\n", + "saved = before[\"turn 2, s\"] - after[\"turn 2, s\"]\n", + "print(f\"\\n→ {saved:.1f}s faster with {after['cache read, tokens']:,} tokens read from cache\")" + ] + }, + { + "cell_type": "markdown", + "id": "0510-caching-after", + "metadata": {}, + "source": [ + "Note that these savings last only while the prefix stays identical. A dynamic field at the top of the system prompt, such as a timestamp or a request ID, changes the prefix on every request and no longer matches what's been written to cache. Put [static content first](https://platform.claude.com/docs/en/build-with-claude/prompt-caching#structuring-your-prompt), mark its end with an explicit breakpoint, and put whatever varies after it in the newest user turn. Automatic caching alone won't do when requests share only that static part because it puts its breakpoint on the last block.\n", + "\n", + "The same goes for the conversation. Editing an earlier turn restarts the cache from that point, and on recent models that support [preserved thinking](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking) it can also get the request rejected. Changing the tools, thinking, effort, or model invalidates some or all of the cache too ([which parts](https://platform.claude.com/docs/en/build-with-claude/prompt-caching#what-invalidates-the-cache)). So only add to the end of `messages`, as a [mid-conversation system message](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages) if you need one, and keep the model and its settings fixed. If cache reads drop to zero and you can't see why, [cache diagnostics](https://platform.claude.com/docs/en/build-with-claude/cache-diagnostics) shows what changed." + ] + }, + { + "cell_type": "markdown", + "id": "0520-prewarm", + "metadata": {}, + "source": [ + "\n", + "#### Pre-warming\n", + "\n", + "A cache entry lives five minutes by default and is refreshed each time it's read, so the first request after more than five minutes of downtime pays for a cold prefix. [Pre-warming](https://platform.claude.com/docs/en/build-with-claude/prompt-caching#pre-warming-the-cache) moves that cost off the user's path. At startup, or on a timer inside the cache's lifetime, you send the shared prefix with an explicit breakpoint on its last block and `max_tokens: 0` so the model writes nothing. Use the same model, thinking configuration, and effort as the traffic that follows.\n", + "\n", + "In the caching example above, the first turn is still slow because it reads all 146,000 tokens of the prompt cold. The cell below reruns that conversation with caching on, once as is and once after a pre-warm." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "0540-prewarm", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " turn 1 turn 2 cache write, tokens cache read, tokens\n", + "BEFORE: no pre-warm 1.0s 0.5s 146,615 146,312\n", + "AFTER: pre-warmed 0.8s 0.6s 308 292,609\n", + "\n", + "→ 0.2s faster with 146,297 more tokens read from cache\n" + ] + } + ], + "source": [ + "def prewarm(system, cfg):\n", + " \"\"\"Writes system into the cache ahead of real traffic, and returns it. cfg: that traffic's setting.\n", + " max_tokens=0 generates nothing and can't stream\"\"\"\n", + " request = single_request(\"warmup\", cfg, system=system, cache=True, max_tokens=0)\n", + " client.with_options(max_retries=2).messages.create(**request)\n", + " return system\n", + "\n", + "\n", + "found = compare(\n", + " {\n", + " \"BEFORE: no pre-warm\": lambda: run_turns(long_system(), cfg, cache=True),\n", + " \"AFTER: pre-warmed\": lambda: run_turns(prewarm(long_system(), cfg), cfg, cache=True),\n", + " },\n", + " repeats=5,\n", + ")\n", + "before, after = found.values()\n", + "show_medians(found, *before)\n", + "saved = before[\"turn 1, s\"] - after[\"turn 1, s\"]\n", + "more = after[\"cache read, tokens\"] - before[\"cache read, tokens\"]\n", + "print(f\"\\n→ {saved:.1f}s faster with {more:,} more tokens read from cache\")" + ] + }, + { + "cell_type": "markdown", + "id": "0550-prewarm-after", + "metadata": {}, + "source": [ + "Pre-warming cut the first answer's wait from 1.0 to 0.8 seconds on this 146,000-token prompt. The saving grows with prompt length, because a cold read takes longer the more tokens it has to process, as we measured in [§Sending fewer tokens](#sending-fewer-tokens). We'd pre-warm when the prefix is long and traffic comes in bursts, with quiet spells longer than the cache lives. For those spells a [one-hour cache](https://platform.claude.com/docs/en/build-with-claude/prompt-caching#1-hour-cache-duration) is the alternative to a timer, and where steady traffic already keeps the cache warm, a pre-warm only adds a billed request." + ] + }, + { + "cell_type": "markdown", + "id": "0560-threads", + "metadata": {}, + "source": [ + "\n", + "### Message threads\n", + "\n", + "Prompt caching saves the model from reprocessing the prefix, but every call still uploads the whole conversation for the API to validate and tokenize again. [Message threads](https://platform.claude.com/docs/en/build-with-claude/message-threads) keep the conversation on the server so you don't have to resend it. The first call sends everything as usual and creates the thread. Each later call sends its new messages with the ID of the previous response and leaves out the system prompt, tools, and earlier turns. Here's how you'd implement it:\n", + "\n", + "```python\n", + "first = {\"system\": system, \"messages\": history, \"thread\": {\"type\": \"create\"}}\n", + "...\n", + "later = {\"messages\": [new_message], \"thread\": {\"type\": \"continue\", \"previous_message_id\": previous.id}}\n", + "```\n", + "\n", + "A thread saves you from resending the conversation, which matters more as it fills up with images, documents, or hundreds of tool results. The cell below opens a conversation with scanned pages of Acme's claims ledger and asks a few questions about them, with and without a thread. The first call on a thread uploads the full conversation, so we'll report the median TTFT of the later calls. And we'll keep `cache_control` on every request because threads don't cache the prompt for us." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "0570-threads", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " pages prompt tokens TTFT request\n", + "BEFORE: caching 4 30,165 0.61s 5.6 MB\n", + "AFTER: caching + thread 4 30,165 0.40s 0.3 KB\n", + "BEFORE: caching 8 49,209 0.82s 11.2 MB\n", + "AFTER: caching + thread 8 49,209 0.48s 0.3 KB\n", + "BEFORE: caching 16 87,297 1.27s 22.3 MB\n", + "AFTER: caching + thread 16 87,297 0.63s 0.3 KB\n" + ] + } + ], + "source": [ + "THREADS = \"message-threads-2026-08-12\"\n", + "LOST = (\"thread_not_found\", \"thread_already_continued\", \"thread_continue_in_flight\")\n", + "PAGES = (4, 8, 16)\n", + "cfg = Config(HAIKU, \"low\", thinking=\"disabled\")\n", + "\n", + "\n", + "def scan(rows):\n", + " \"\"\"An image block of one page of the paid claims ledger, as a 300 dpi scan of about 1 MB\"\"\"\n", + " page = plt.figure(figsize=(8.5, 11))\n", + " page.text(0.05, 0.96, \"\\n\".join(rows), family=\"monospace\", size=7, va=\"top\", parse_math=False)\n", + " jpeg = io.BytesIO()\n", + " page.savefig(jpeg, format=\"jpg\", dpi=300, pil_kwargs={\"quality\": 90})\n", + " plt.close(page)\n", + " data = base64.b64encode(jpeg.getvalue()).decode()\n", + " return {\"type\": \"image\", \"source\": {\"type\": \"base64\", \"media_type\": \"image/jpeg\", \"data\": data}}\n", + "\n", + "\n", + "SCANS = [scan(LEDGER_ROWS[80 * n : 80 * (n + 1)]) for n in range(max(PAGES))]\n", + "PAID_CLAIMS = [row.split(\",\")[0] for row in LEDGER_ROWS[10:290:40]]\n", + "TOKENS = {\n", + " pages: client.messages.count_tokens(\n", + " model=cfg.model, system=MEMO_SYSTEM, messages=[{\"role\": \"user\", \"content\": SCANS[:pages]}]\n", + " ).input_tokens\n", + " for pages in PAGES\n", + "}\n", + "\n", + "\n", + "def run_claims(pages, thread):\n", + " \"\"\"Opens a conversation with that many scanned pages, then asks about each of PAID_CLAIMS, with caching on. thread: create a\n", + " thread on the first call and send each later call only its new message. Returns, over the calls after the first,\n", + " the median seconds until the answer began and the median size of the request's JSON\"\"\"\n", + " system = f\"(threads {time.time_ns()})\\n\\n{MEMO_SYSTEM}\"\n", + " fixed = cfg.kwargs() | {\"max_tokens\": MAX_TOKENS, \"cache_control\": {\"type\": \"ephemeral\"}}\n", + " history = [\n", + " {\"role\": \"user\", \"content\": SCANS[:pages]},\n", + " {\"role\": \"assistant\", \"content\": \"I have the pages.\"},\n", + " ]\n", + " previous, calls = None, []\n", + " for claim in PAID_CLAIMS:\n", + " history.append({\"role\": \"user\", \"content\": f\"What was paid on {claim}?\"})\n", + " whole = fixed | {\"system\": system, \"messages\": history}\n", + " if thread:\n", + " whole[\"thread\"] = {\"type\": \"create\"}\n", + " request = whole\n", + " if thread and previous: # the thread holds the system prompt and the earlier messages\n", + " request = fixed | {\"messages\": history[-1:]}\n", + " request[\"thread\"] = {\"type\": \"continue\", \"previous_message_id\": previous}\n", + " start, lost = time.perf_counter(), 0.0\n", + " try:\n", + " m, marks = timed_stream(betas=[THREADS], **request)\n", + " except (anthropic.NotFoundError, anthropic.BadRequestError) as e:\n", + " details = e.body.get(\"error\", {}).get(\"details\") if isinstance(e.body, dict) else None\n", + " if (details or {}).get(\"error_code\") not in LOST:\n", + " raise\n", + " # The thread can't be continued, so resend the conversation on a new one. The failed call's time counts\n", + " request, lost = whole, time.perf_counter() - start\n", + " m, marks = timed_stream(betas=[THREADS], **request)\n", + " calls.append(\n", + " {\n", + " \"TTFT, s\": lost + marks.get(\"text\", marks[\"done\"]),\n", + " \"bytes\": len(json.dumps(request, default=lambda block: block.to_dict())),\n", + " }\n", + " )\n", + " history.append({\"role\": \"assistant\", \"content\": m.content})\n", + " previous = m.id\n", + " ttft, size = (statistics.median(c[k] for c in calls[1:]) for k in (\"TTFT, s\", \"bytes\"))\n", + " return {\n", + " \"TTFT, s\": ttft,\n", + " \"request\": f\"{size / 1e6:.1f} MB\" if size >= 1e6 else f\"{size / 1e3:.1f} KB\",\n", + " }\n", + "\n", + "\n", + "runs = {(pages, thread): [] for pages in PAGES for thread in (False, True)}\n", + "for repeat in range(3):\n", + " order = list(runs)\n", + " random.Random(repeat).shuffle(order)\n", + " for pages, thread in order:\n", + " runs[pages, thread].append(run_claims(pages, thread))\n", + "\n", + "show(\n", + " [\n", + " {\"\": \"AFTER: caching + thread\" if thread else \"BEFORE: caching\", \"pages\": pages}\n", + " | {\"prompt tokens\": TOKENS[pages]}\n", + " | min(repeats, key=lambda run: run[\"TTFT, s\"])\n", + " for (pages, thread), repeats in runs.items()\n", + " ],\n", + " places=2,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "0580-threads-after", + "metadata": {}, + "source": [ + "With 16 pages, the thread halved TTFT by cutting each request from 22 MB to 0.3 KB, and those savings grew with the number of pages. Notice how the thread saves upload time as opposed to tokens. Claude still reads the full conversation on every call, so our cost is the same with and without threads. We'd use a thread on any long or heavy multi-turn conversation, but our desk agent's typical tasks are a few calls of plain text, so there's little payload for a thread to save." + ] + }, + { + "cell_type": "markdown", + "id": "0800-agent-loop", + "metadata": {}, + "source": [ + "\n", + "## Agent loop efficiency\n", + "\n", + "Latency also depends on how many times an agent calls the model. This is the calls × TTFT term in our equation: an agent that takes five calls to answer pays five TTFTs, plus the tool waits in between. The levers in this section aim to make fewer calls and parallelize the calls that need to stay." + ] + }, + { + "cell_type": "markdown", + "id": "0810-compaction", + "metadata": {}, + "source": [ + "\n", + "### Background compaction\n", + "\n", + "On long multi-turn tasks, the conversation can eventually outgrow the model's context window. To keep going, the earlier turns have to be condensed into a summary that takes their place. The API's [compaction](https://platform.claude.com/docs/en/build-with-claude/compaction) writes that summary for you. Writing it takes time, and the ways to trigger it differ in whether a user has to wait for it. [At a token threshold](https://platform.claude.com/docs/en/build-with-claude/compaction-threshold), the request that crosses it writes the summary first, which adds that wait to the turn. [On demand](https://platform.claude.com/docs/en/build-with-claude/compaction-on-demand), a separate request returns the summary, and if you send that request [in the background](https://platform.claude.com/docs/en/build-with-claude/compaction-background), no turn waits for it at all.\n", + "\n", + "Our desk agent's tasks never get long enough to reach a threshold, so we'll use a separate chat example with ten claims, each pasting in about 8K tokens. We'll run it three ways: with no compaction, with compaction at a 50K-token threshold (the lowest the API accepts), and with background compaction once the prompt passes 50K tokens." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "0820-compaction", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " median wait longest wait largest prompt, tokens\n", + "no compaction 3.3s 5.4s 95,881\n", + "BEFORE: at a threshold 4.1s 21.4s 55,674\n", + "AFTER: in the background 3.3s 4.9s 69,755\n", + "\n", + "→ longest wait: 21.4s compacting at a threshold, 4.9s in the background\n" + ] + } + ], + "source": [ + "# Helpers shared by this demo and the per-turn effort demo in Model, effort, and thinking\n", + "SESSION_SYSTEM = (\n", + " \"You are a Senior Adjuster in Acme Insurance's auto claims unit, working a queue of claims \"\n", + " \"in one session. Apply the underwriting manual below. For each claim reply in exactly two \"\n", + " f\"lines and nothing else:\\n{TWO_LINES}\\n\\n{MANUAL}\"\n", + ")\n", + "\n", + "\n", + "def new_session():\n", + " \"\"\"A system prompt that no earlier session has cached, and an empty history\"\"\"\n", + " return f\"(session {time.time_ns()})\\n\\n\" + SESSION_SYSTEM, []\n", + "\n", + "\n", + "def claim_file(i):\n", + " cid = list(CLAIMS)[i]\n", + " comparables = \"\\n\".join([LEDGER_ROWS[0], *LEDGER_ROWS[1 + i * 270 : 1 + (i + 1) * 270]])\n", + " return f\"{claim_record(cid)}\\n\\nCOMPARABLE PAID CLAIMS\\n{comparables}\\n\\nDecide claim {cid}.\"\n", + "\n", + "\n", + "def session_request(system, messages, **more):\n", + " \"\"\"What every request on a conversation shares. Two cache breakpoints: one at the end of the system prompt,\n", + " and one the API places at the end of the history, asked for by the top-level cache_control\"\"\"\n", + " return BASE.kwargs() | {\n", + " \"max_tokens\": MAX_TOKENS,\n", + " \"system\": [cached({\"type\": \"text\", \"text\": system})],\n", + " \"messages\": messages,\n", + " \"cache_control\": {\"type\": \"ephemeral\"},\n", + " **more,\n", + " }\n", + "\n", + "\n", + "def send_turn(label, system, history, **more):\n", + " \"\"\"Sends the conversation's next request and appends the reply to history as returned, thinking included.\n", + " Returns its row of the session's table\"\"\"\n", + " m, marks = timed_stream(**session_request(system, history, **more))\n", + " history.append({\"role\": \"assistant\", \"content\": m.content})\n", + " # A request that compacts before it answers makes two passes, and usage.iterations lists each\n", + " parts = [token_counts(u) for u in getattr(m.usage, \"iterations\", None) or [m.usage]]\n", + " sizes = [t[\"input_tokens\"] + t[\"cache_read\"] + t[\"cache_write\"] for t in parts]\n", + " return {\n", + " \"\": label,\n", + " \"wait s\": marks[\"done\"],\n", + " \"prompt tokens\": max(sizes),\n", + " \"cache read, tokens\": parts[-1][\"cache_read\"],\n", + " \"cache write, tokens\": parts[-1][\"cache_write\"],\n", + " \"output tokens\": m.usage.output_tokens,\n", + " }\n", + "\n", + "\n", + "# The compaction demo: one conversation of ten claims, run three ways\n", + "COMPACT_BETA = \"compact-2026-09-04\" # compaction on demand\n", + "THRESHOLD_BETA = \"compact-2026-01-12\" # compaction at a token threshold\n", + "COMPACT_AT = 50_000 # prompt tokens. Also the lowest threshold the API accepts\n", + "PAUSE = 4.0 # seconds between turns, standing in for the person reading. Not counted as waiting\n", + "\n", + "\n", + "def summarize(system, messages):\n", + " \"\"\"Compaction on demand. Model, system, thinking, effort, and cache_control match the conversation's,\n", + " so the request reads the conversation's cached prefix\"\"\"\n", + " extra = {\"betas\": [COMPACT_BETA], \"compaction\": {\"type\": \"summarize\"}}\n", + " request = session_request(system, messages, **extra)\n", + " return client.with_options(max_retries=2).beta.messages.create(**request)\n", + "\n", + "\n", + "def run_session(mode):\n", + " \"\"\"Ten claims in one conversation. mode: \"none\", \"threshold\" (compact inside the request that crosses it),\n", + " or \"background\" (ask for a summary between turns, swap it in when ready). Returns one row for each turn\"\"\"\n", + " system, history = new_session()\n", + " extra = {}\n", + " if mode == \"threshold\":\n", + " trigger = {\"type\": \"input_tokens\", \"value\": COMPACT_AT}\n", + " edits = [{\"type\": \"compact_20260112\", \"trigger\": trigger}]\n", + " extra = {\"betas\": [THRESHOLD_BETA], \"context_management\": {\"edits\": edits}}\n", + " if mode == \"background\":\n", + " extra = {\"betas\": [COMPACT_BETA]} # needed once the history holds a summary\n", + " rows = []\n", + " pending, held = None, 0 # the summary on its way, and how many messages it covers\n", + " with ThreadPoolExecutor(max_workers=1) as pool:\n", + " for i in range(len(CLAIMS)):\n", + " if pending and pending.done():\n", + " summary, pending = pending.result(), None\n", + " if summary.stop_reason == \"compaction\":\n", + " # Replace exactly the messages the summary covers. Later turns stay after it\n", + " history[:held] = [{\"role\": \"assistant\", \"content\": summary.content}]\n", + " history.append({\"role\": \"user\", \"content\": claim_file(i)})\n", + " row = send_turn(f\"turn {i + 1}\", system, history, **extra)\n", + " rows.append(row)\n", + " last = i + 1 == len(CLAIMS)\n", + " if mode == \"background\" and not (pending or last) and row[\"prompt tokens\"] > COMPACT_AT:\n", + " pending, held = pool.submit(summarize, system, list(history)), len(history)\n", + " time.sleep(0 if last else PAUSE)\n", + " return rows\n", + "\n", + "\n", + "SESSIONS = {\n", + " \"no compaction\": run_session(\"none\"),\n", + " \"BEFORE: at a threshold\": run_session(\"threshold\"),\n", + " \"AFTER: in the background\": run_session(\"background\"),\n", + "}\n", + "summary = [\n", + " {\n", + " \"\": label,\n", + " \"median wait s\": statistics.median(r[\"wait s\"] for r in rows),\n", + " \"longest wait s\": max(r[\"wait s\"] for r in rows),\n", + " \"largest prompt, tokens\": max(r[\"prompt tokens\"] for r in rows),\n", + " }\n", + " for label, rows in SESSIONS.items()\n", + "]\n", + "show(summary)\n", + "_, before, after = (row[\"longest wait s\"] for row in summary)\n", + "print(f\"\\n→ longest wait: {before:.1f}s compacting at a threshold, {after:.1f}s in the background\")" + ] + }, + { + "cell_type": "markdown", + "id": "0830-compaction-after", + "metadata": {}, + "source": [ + "Compacting at a threshold left one turn waiting 21.4 seconds while the summary was written. In the background, the longest wait was 4.9 seconds, in line with the 5.4 seconds with no compaction. The tradeoff is a bigger prompt, about 70,000 tokens at its peak against 56,000 at a threshold, because the turns sent while the summary was being written still carried the full history. If your conversations run long enough to compact and someone waits on every turn, we'd compact in the background and ask for the summary early enough that those turns still fit in the context window." + ] + }, + { + "cell_type": "markdown", + "id": "0838-subagents", + "metadata": {}, + "source": [ + "\n", + "### Subagents\n", + "\n", + "When a task splits into independent pieces, each piece can go to a subagent. With the Messages API, a subagent is just another request with its own `messages` array. It sees the context you give it and returns its answer to the main agent. Sent together, the pieces run in parallel and the task waits for the slowest one. If you're building on the [Agent SDK](https://code.claude.com/docs/en/agent-sdk/subagents) or [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration), both have their own subagent support. \n", + "\n", + "In the cell below, Opus 5.5 is the main agent deciding a claim, and it needs three facts from the claim record first. In the first run it looks them up itself, one turn at a time in its own conversation. In the second it hands them to three faster, cheaper Haiku 5.5 subagents and decides from their answers. Only Opus gets the underwriting manual, since the subagents just look up facts. Every request runs at `low` effort, and we'll check their answers to ensure accuracy doesn't degrade." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "0880-subagents", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " answers decision total decisions right\n", + "BEFORE: Opus 5.5 answers in turn 6.8s 3.1s 9.5s 5/5\n", + "AFTER: Haiku 5.5 subagents side by side 1.5s 4.2s 5.7s 5/5\n", + "\n", + "→ with subagents the task waits ×0.60 as long\n" + ] + } + ], + "source": [ + "# Three facts the manual's fraud score (§5.1) turns on. Each is a lookup in the claim record\n", + "QUESTIONS = [\n", + " \"How many days passed between the loss and the report, and is a reason for the delay on file?\",\n", + " \"How many prior claims fell in the 36 months before the loss date?\",\n", + " \"Was a police report filed?\",\n", + "]\n", + "CLAIM = claim_record(\"CLM-008\")\n", + "ONE_LINE = \"Answer in one terse line.\"\n", + "DECIDE = f\"Decide the claim from these findings. Reply in exactly two lines:\\n{TWO_LINES}\"\n", + "ANSWER = \"SUPERVISOR\" # the manual's fraud score comes to 4, and 3 to 5 means supervisor review\n", + "ORCHESTRATOR, SUBAGENT = Config(OPUS, \"low\"), Config(HAIKU, \"low\")\n", + "BEFORE, AFTER = \"BEFORE: Opus 5.5 answers in turn\", \"AFTER: Haiku 5.5 subagents side by side\"\n", + "GRADES = {BEFORE: [], AFTER: []} # whether each decision matched ANSWER\n", + "\n", + "\n", + "def reply(cfg, system, messages):\n", + " \"\"\"Sends one conversation and adds the reply to it. Returns the seconds\"\"\"\n", + " message, marks = timed_stream(**cfg.kwargs(), max_tokens=8192, system=system, messages=messages)\n", + " messages.append({\"role\": \"assistant\", \"content\": message.content})\n", + " return marks[\"done\"]\n", + "\n", + "\n", + "def text(messages):\n", + " \"\"\"The text of the conversation's last reply\"\"\"\n", + " return \"\".join(b.text for b in messages[-1][\"content\"] if b.type == \"text\")\n", + "\n", + "\n", + "def decide(messages, label):\n", + " \"\"\"The orchestrator, which has the manual, decides from the conversation so far. Returns the seconds\"\"\"\n", + " messages.append({\"role\": \"user\", \"content\": DECIDE})\n", + " secs = reply(ORCHESTRATOR, MEMO_SYSTEM, messages)\n", + " GRADES[label].append(f\"DECISION: {ANSWER}\" in text(messages))\n", + " return secs\n", + "\n", + "\n", + "def one_agent():\n", + " \"\"\"The orchestrator answers each question in turn in its own conversation, then decides. Returns the\n", + " seconds\"\"\"\n", + " messages, secs = [], 0.0\n", + " for i, question in enumerate(QUESTIONS):\n", + " ask = f\"{question} {ONE_LINE}\"\n", + " messages.append({\"role\": \"user\", \"content\": f\"{CLAIM}\\n\\n{ask}\" if i == 0 else ask})\n", + " secs += reply(ORCHESTRATOR, MEMO_SYSTEM, messages)\n", + " decision = decide(messages, BEFORE)\n", + " return {\"answers, s\": secs, \"decision, s\": decision, \"total, s\": secs + decision}\n", + "\n", + "\n", + "def subagent(question):\n", + " \"\"\"One subagent: a request with its own messages array and no manual. Returns its seconds and answer\"\"\"\n", + " messages = [{\"role\": \"user\", \"content\": f\"{CLAIM}\\n\\n{question} {ONE_LINE}\"}]\n", + " return reply(SUBAGENT, \"You are a claims assistant.\", messages), text(messages)\n", + "\n", + "\n", + "def with_subagents():\n", + " \"\"\"Subagents answer the questions side by side, then the orchestrator decides from their answers. Returns\n", + " the seconds\"\"\"\n", + " with ThreadPoolExecutor(max_workers=len(QUESTIONS)) as pool:\n", + " found = list(pool.map(subagent, QUESTIONS))\n", + " findings = \"\\n\".join(f\"{q}\\n{answer}\" for q, (_, answer) in zip(QUESTIONS, found, strict=True))\n", + " messages = [{\"role\": \"user\", \"content\": f\"{CLAIM}\\n\\nSubagents' findings:\\n{findings}\"}]\n", + " secs = max(s for s, _ in found)\n", + " decision = decide(messages, AFTER)\n", + " return {\"answers, s\": secs, \"decision, s\": decision, \"total, s\": secs + decision}\n", + "\n", + "\n", + "found = compare({BEFORE: one_agent, AFTER: with_subagents}, repeats=5)\n", + "for label, medians in found.items():\n", + " medians[\"decisions right\"] = f\"{sum(GRADES[label])}/{len(GRADES[label])}\"\n", + "show_medians(found, \"answers, s\", \"decision, s\", \"total, s\", \"decisions right\")\n", + "before, after = (medians[\"total, s\"] for medians in found.values())\n", + "print(f\"\\n→ with subagents the task waits ×{after / before:.2f} as long\")" + ] + }, + { + "cell_type": "markdown", + "id": "0885-subagents-after", + "metadata": {}, + "source": [ + "With subagents the task took 5.7 seconds instead of 9.5, and all five decisions were correct. The three answers came back in 1.5 seconds instead of 6.8 because they ran in parallel on a faster model. So when a task splits into independent lookups or checks, hand them to small subagents and give each one only the context it needs. We chose Haiku 5.5 for speed, which suits simple lookups like these. Subtasks that need greater judgment may call for a larger model, but we would expect the effect to still be directionally the same because of the subagent parallelism gains.\n", + "\n", + "If your subagents start with the same long context, such as a shared document, initiating the subagents at once means each one reads the document uncached, because the cache entry isn't ready until the first response begins. To fix that, [pre-warm](#pre-warming) the shared context, or send one subagent first and the other subagents once its reply starts streaming." + ] + }, + { + "cell_type": "markdown", + "id": "0890-prefetch", + "metadata": {}, + "source": [ + "\n", + "### Prefetch and bigger pages\n", + "\n", + "Sometimes your code knows which tool call the model will make first. When it does, your code can make that call itself, outside the agent loop, and put the result in the first user turn. Every desk agent task starts with `get_claim` for the claim the request names, and a quote also needs `get_estimate` for page 1 of that claim's estimate. **Prefetch** runs those lookups up front, which saves the model a round trip. **Bigger pages** doubles the estimate lines or ledger rows each lookup returns, so tasks that page through results need fewer lookups. Both make the opposite trade from [§Sending fewer tokens](#sending-fewer-tokens), adding input tokens to make fewer calls and pay fewer TTFTs. \n", + "\n", + "These lines replace the baseline's setup of tools and the first turn:\n", + "\n", + "```python\n", + "prefetch, big_pages = \"prefetch\" in cfg.loop, \"big_pages\" in cfg.loop\n", + "...\n", + "tools = desk_agent.tool_specs(big_pages=big_pages)\n", + "first = desk_agent.first_turn(task, prefetch=prefetch, big_pages=big_pages)\n", + "```\n", + "\n", + "And the table below shows prefetching and bigger pages each applied to our baseline eval." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "0892-loop-levers", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
settingcorrectcorrect vs first row, pointsp50p50 vs first rowp90p90 vs first rowcalls / taskoutput tokens / task$ / task
Opus 5.5 · medium98.4%6.2s11.8s3.5856$0.0377
Opus 5.5 · medium + prefetch99.4%+1.0 (+0.0 to +2.1)5.3s×0.87 (0.82 to 0.90)12.1s×1.02 (0.90 to 1.08)2.4846$0.0340
Opus 5.5 · medium + bigger pages98.5%+0.2 (-1.4 to +1.6)5.5s×0.90 (0.85 to 0.94)11.4s×0.96 (0.86 to 1.01)3.3829$0.0373
" + ], + "text/plain": [ + "setting correct correct vs first row, points p50 p50 vs first row p90 p90 vs first row calls / task output tokens / task $ / task\n", + "Opus 5.5 · medium 98.4% 6.2s 11.8s 3.5 856 $0.0377\n", + "Opus 5.5 · medium + prefetch 99.4% +1.0 (+0.0 to +2.1) 5.3s ×0.87 (0.82 to 0.90) 12.1s ×1.02 (0.90 to 1.08) 2.4 846 $0.0340\n", + "Opus 5.5 · medium + bigger pages 98.5% +0.2 (-1.4 to +1.6) 5.5s ×0.90 (0.85 to 0.94) 11.4s ×0.96 (0.86 to 1.01) 3.3 829 $0.0373" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "LEVERS = (\"prefetch\", \"bigger pages\")\n", + "SWEEP.results_table([BASE.with_loop(name) for name in LEVERS])" + ] + }, + { + "cell_type": "markdown", + "id": "0895-loop-levers-after", + "metadata": {}, + "source": [ + "Prefetch saved about one call per task and cut p50 by 13%. Bigger pages saved fewer calls and cut p50 by 10%. Neither lever changed p90 or accuracy significantly. Given those wins on p50 latency, we recommend prefetching whatever lookup your task always does first, such as pulling the order a refund request refers to, and returning bigger pages where tasks page through long results." + ] + }, + { + "cell_type": "markdown", + "id": "0896-ptc", + "metadata": {}, + "source": [ + "\n", + "### Programmatic tool calling\n", + "\n", + "In a normal tool loop, the model is sampled again after every round of tool calls. It asks for a call, your code runs it, and the result goes back into the conversation before the model can ask for the next one. A job that pages through 20 results one after another pays for 20 of those round trips, each with its own TTFT. The model also reads every result in full, even when all it needs is their total.\n", + "\n", + "With [programmatic tool calling](https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling), the model writes one script that makes all the tool calls from a code execution container. The model isn't sampled between those calls and reads only what the script prints ([see the cookbook](https://platform.claude.com/cookbook/tool-use-programmatic-tool-calling-ptc)). The tradeoff is a fixed overhead for starting the container and writing the script, and every call the script makes still goes out to your code and back. Programmatic tool calling pays off on jobs with many calls or large results. Skip it when the model needs to read each result before choosing the next call, or when a job makes only a few calls with small results.\n", + "\n", + "In the demo below, the model adds up a year of insurance payouts from a tool that returns them one page at a time. With direct calls, the model has to ask for each page in turn. With a script, code fetches the pages and the model reads only the total." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "0897-ptc-demo", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " fetching pages answering total output tokens correct\n", + "BEFORE: direct calls 17.3s 29.6s 46.8s 5,262 True\n", + "AFTER: from a script 26.8s 9.2s 36.0s 816 True\n", + "\n", + "→ 10.8s faster from a script, with 4,446 fewer output tokens\n" + ] + } + ], + "source": [ + "PAGE = 20\n", + "PAID = [row | {\"paid_usd\": float(row[\"paid_usd\"])} for row in csv.DictReader(LEDGER_ROWS)]\n", + "LIST_CLAIMS = {\n", + " \"name\": \"list_paid_claims\",\n", + " \"description\": (\n", + " f\"One page of the claims paid in a state on one year's losses, {PAGE} to a page, the most the \"\n", + " \"API returns. For the next page, pass the last page's next_cursor. Returns JSON: \"\n", + " '{\"rows\": [{\"claim_id\": str, \"loss_date\": \"YYYY-MM-DD\", \"type\": str, \"paid_usd\": float}], '\n", + " '\"next_cursor\": str or null}. next_cursor is null on the last page.'\n", + " ),\n", + " \"input_schema\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"state\": {\"type\": \"string\", \"description\": \"Two letters\"},\n", + " \"year\": {\"type\": \"integer\"},\n", + " \"cursor\": {\"type\": \"string\"},\n", + " },\n", + " \"required\": [\"state\", \"year\"],\n", + " },\n", + "}\n", + "\n", + "\n", + "def list_paid_claims(state, year, cursor=None):\n", + " \"\"\"The simulated API. A cursor is the last claim of the page before, so no page can be asked for ahead of time\"\"\"\n", + " rows = [r for r in PAID if (r[\"state\"], r[\"loss_date\"][:4]) == (state, str(year))]\n", + " claim_ids = [r[\"claim_id\"] for r in rows]\n", + " if cursor and cursor not in claim_ids:\n", + " return \"ERROR: unknown cursor\"\n", + " start = claim_ids.index(cursor) + 1 if cursor else 0\n", + " page = [{k: v for k, v in r.items() if k != \"state\"} for r in rows[start : start + PAGE]]\n", + " more = start + PAGE < len(rows)\n", + " return json.dumps({\"rows\": page, \"next_cursor\": page[-1][\"claim_id\"] if more else None})\n", + "\n", + "\n", + "REPORT = (\n", + " \"A regulator wants our Texas payouts on 2022 losses: the total paid, and the claim type we paid \"\n", + " \"the most on.\"\n", + ")\n", + "REPORT_SYSTEM = (\n", + " \"You are an analyst in Acme Insurance's auto claims unit. Answer from the paid-claims API, using \"\n", + " \"every matching claim. End with exactly two lines:\\n\"\n", + " \"TOTAL: \\nTOP TYPE: \"\n", + ")\n", + "REPORT_KEY = \"TOTAL: 2110804.91\\nTOP TYPE: collision\" # worked out from the ledger\n", + "SCRIPTS = \"code_execution_20260120\"\n", + "\n", + "\n", + "def run_report(cfg, scripted):\n", + " \"\"\"Answers REPORT with the one tool, which the model calls directly or (scripted) from a script it writes\"\"\"\n", + " tools, extra = [LIST_CLAIMS], {\"cache_control\": {\"type\": \"ephemeral\"}}\n", + " if scripted: # the pages go to the script, so the prompt doesn't grow: nothing to cache\n", + " sandbox = {\"type\": SCRIPTS, \"name\": \"code_execution\"}\n", + " tools, extra = [sandbox, LIST_CLAIMS | {\"allowed_callers\": [SCRIPTS]}], {}\n", + " request = cfg.kwargs() | {\"max_tokens\": MAX_TOKENS, \"system\": REPORT_SYSTEM, \"tools\": tools}\n", + " history, secs, tokens = [{\"role\": \"user\", \"content\": REPORT}], [], 0\n", + " while len(secs) < 40:\n", + " m, marks = timed_stream(**request, messages=history, **extra)\n", + " secs.append(marks[\"done\"])\n", + " tokens += m.usage.output_tokens\n", + " history.append({\"role\": \"assistant\", \"content\": m.content})\n", + " if m.container:\n", + " extra[\"container\"] = m.container.id # a paused script resumes only in its own container\n", + " # A script's calls come back as tool_use too, and their results must be the whole message\n", + " results = [\n", + " {\"type\": \"tool_result\", \"tool_use_id\": b.id, \"content\": list_paid_claims(**b.input)}\n", + " for b in m.content\n", + " if b.type == \"tool_use\"\n", + " ]\n", + " if results:\n", + " history.append({\"role\": \"user\", \"content\": results})\n", + " elif m.stop_reason != \"pause_turn\":\n", + " break\n", + " answer = next((b.text for b in reversed(m.content) if b.type == \"text\"), \"\")\n", + " reply = answer.replace(\"$\", \"\").replace(\",\", \"\")\n", + " return {\n", + " \"fetching pages, s\": sum(secs[:-1]),\n", + " \"answering, s\": secs[-1],\n", + " \"total, s\": sum(secs),\n", + " \"output tokens\": tokens,\n", + " \"correct\": reply.rstrip().endswith(REPORT_KEY),\n", + " }\n", + "\n", + "\n", + "before, after = run_report(BASE, scripted=False), run_report(BASE, scripted=True)\n", + "show([{\"\": \"BEFORE: direct calls\"} | before, {\"\": \"AFTER: from a script\"} | after])\n", + "saved, fewer = (before[k] - after[k] for k in (\"total, s\", \"output tokens\"))\n", + "print(f\"\\n→ {saved:.1f}s faster from a script, with {fewer:,} fewer output tokens\")" + ] + }, + { + "cell_type": "markdown", + "id": "0897-ptc-after", + "metadata": {}, + "source": [ + "Fetching the pages took 9.5 seconds longer from the script, but answering took 20.4 seconds less, so the whole job finished about 11 seconds sooner. Fetching was slower because those requests include writing the script. Answering was faster because the script added up the payouts in code and printed the total, so the model only had to report it. With direct calls, the model had to add up every payout from every page itself, which took about 4,400 more output tokens. \n", + "\n", + "Programmatic tool calling helps most when a job ends in a sum, a filter, or a count, which code does better than the model. Our desk agent tasks take only a few calls with small results, so we left programmatic tool calling out of the final sweep." + ] + }, + { + "cell_type": "markdown", + "id": "0900-output", + "metadata": {}, + "source": [ + "\n", + "## Output token management\n", + "\n", + "With input tokens and turns settled, the other variables in our latency formula concern output. The model writes output tokens one at a time, so every token it doesn't write shortens TTLT, thinking included. If your application needs only a decision and a one-line reason, every paragraph of explanation around that is time the user shouldn't need to wait on." + ] + }, + { + "cell_type": "markdown", + "id": "0910-shorter", + "metadata": {}, + "source": [ + "\n", + "### Prompting for shorter answers\n", + "\n", + "While it may sound trivial, you can simply ask Claude to emit fewer tokens. Outlining the output shape you want, ideally with an example, keeps the model from over-narrating its way to the answer. The cell below asks the model to decide the same claim twice. The first time it can answer however it likes. The second time it has to reply in exactly two lines, a decision and a one-sentence reason." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "0930-shape", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " done output tokens of which thinking\n", + "BEFORE: free-form 46.4s 4,913 2,083\n", + "AFTER: two lines asked for 4.9s 433 296\n", + "\n", + "→ asking for two lines: 41.5s sooner, with 1,787 fewer thinking tokens\n" + ] + } + ], + "source": [ + "question = claim_record(\"CLM-008\") + \"\\n\\nWrite up your decision on this claim.\"\n", + "shaped = f\"{MEMO_SYSTEM}\\n\\nRespond in exactly two lines and nothing else:\\n{TWO_LINES}\"\n", + "found = compare(\n", + " {\n", + " \"BEFORE: free-form\": lambda: timed(single_request(question, system=MEMO_SYSTEM)),\n", + " \"AFTER: two lines asked for\": lambda: timed(single_request(question, system=shaped)),\n", + " }\n", + ")\n", + "show_medians(found, \"done, s\", \"output tokens\", \"of which thinking\")\n", + "before, after = found.values()\n", + "saved = before[\"done, s\"] - after[\"done, s\"]\n", + "fewer = before[\"of which thinking\"] - after[\"of which thinking\"]\n", + "print(f\"\\n→ asking for two lines: {saved:.1f}s sooner, with {fewer:,.0f} fewer thinking tokens\")" + ] + }, + { + "cell_type": "markdown", + "id": "0940-shape-after", + "metadata": {}, + "source": [ + "Asking for two lines cut the decision from 46.4 seconds to 4.9. The model thought less too, about 300 tokens instead of 2,100, so a shorter answer means shorter reasoning. If your task requires deep reasoning but only a brief output, use [structured outputs](#structured-outputs) for the answer and set how much the model thinks with [effort](#effort). We recommend asking for a shape wherever the model writes more than anyone reads." + ] + }, + { + "cell_type": "markdown", + "id": "0945-commentary", + "metadata": {}, + "source": [ + "\n", + "#### No commentary\n", + "\n", + "We can also prompt the agent not to narrate between tool calls. The table below compares the baseline with a version that adds this instruction to the system prompt:\n", + "\n", + "> Write no text outside your tool calls: no plans, notes, summaries or explanations. Nobody reads that text, and the customer waits while you write it. Fill in the recorder call's arguments exactly as the manual asks." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "0950-commentary", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
settingcorrectcorrect vs first row, pointsp50p50 vs first rowp90p90 vs first rowcalls / taskoutput tokens / task$ / task
Opus 5.5 · medium98.4%6.2s11.8s3.5856$0.0377
Opus 5.5 · medium + no commentary99.5%+1.2 (+0.1 to +2.3)6.0s×0.97 (0.93 to 1.02)12.0s×1.01 (0.92 to 1.08)3.5836$0.0376
" + ], + "text/plain": [ + "setting correct correct vs first row, points p50 p50 vs first row p90 p90 vs first row calls / task output tokens / task $ / task\n", + "Opus 5.5 · medium 98.4% 6.2s 11.8s 3.5 856 $0.0377\n", + "Opus 5.5 · medium + no commentary 99.5% +1.2 (+0.1 to +2.3) 6.0s ×0.97 (0.93 to 1.02) 12.0s ×1.01 (0.92 to 1.08) 3.5 836 $0.0376" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "SWEEP.results_table([BASE.with_loop(\"no commentary\")])" + ] + }, + { + "cell_type": "markdown", + "id": "0960-commentary-after", + "metadata": {}, + "source": [ + "The no-commentary instruction changed neither p50 nor p90 significantly for our use case. It had little to cut because Opus 5.5 wrote the same amount on its way to the answer with or without it. Accuracy rose by a significant 1.2 points, which may come from the instruction's last sentence about filling in the recorder's arguments rather than from cutting commentary. This configuration is still worth testing when nobody reads the text your agent writes between tool calls, but check accuracy on each model you'd run it with, because commentary can help keep the model on track on long-horizon tasks." + ] + }, + { + "cell_type": "markdown", + "id": "0970-structured-outputs", + "metadata": {}, + "source": [ + "\n", + "### Structured outputs\n", + "\n", + "[Structured outputs](https://platform.claude.com/docs/en/build-with-claude/structured-outputs) enforce a shape rather than ask for one, by constraining the response to a JSON schema sent in `output_config.format`. The reply is then only the JSON, so there's no preamble to generate and no retry for output that fails to parse. The first request with a new schema takes longer, because the API has to turn the schema into rules that limit what the model can write. Those rules stay cached for 24 hours after their last use. Our desk agent already answers by using a custom tool that constrains model output like structured outputs, so a schema would save it nothing. If a free-text answer would come with a preamble or need parsing, send a schema instead, and keep it stable, because a changed or rarely used schema pays that first-request wait again." + ] + }, + { + "cell_type": "markdown", + "id": "1000-model-effort", + "metadata": {}, + "source": [ + "\n", + "## Model, effort, and thinking\n", + "\n", + "How many tokens a call writes also depends on how much the model thinks, and how fast they arrive depends on the model and its speed. The levers here change how much the model reasons or which model does the reasoning. That sets your application's intelligence ceiling, which is the hardest problem it can still handle. A lower effort or a smaller model may pass every task in your eval and still fail a harder request that shows up later. That's why these levers come after the ones that leave the model alone. The exception is fast mode, which serves the same Opus 5.5, just faster." + ] + }, + { + "cell_type": "markdown", + "id": "1002-fast-mode", + "metadata": {}, + "source": [ + "\n", + "### Fast mode\n", + "\n", + "[Fast mode](https://platform.claude.com/docs/en/build-with-claude/fast-mode) runs Opus 5.5 with a faster inference configuration, which gives up to 2.5 times the OTPS at two times the sticker price. The tables below compare fast mode with standard Opus 5.5 across effort levels." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "1004-fast-mode", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
settingcorrectcorrect vs first row, pointsp50p50 vs first rowp50 ratio in each roundp90p90 vs first rowp90 ratio in each roundcalls / taskoutput tokens / task$ / task
Opus 5.5 · high99.4%6.6s13.2s3.5943$0.0399
Opus 5.5 · high · fast mode99.2%-0.2 (-1.2 to +1.0)2.9s×0.44 (0.42 to 0.47)0.47 0.51 0.365.4s×0.41 (0.35 to 0.45)0.39 0.47 0.373.5961$0.0804
" + ], + "text/plain": [ + "setting correct correct vs first row, points p50 p50 vs first row p50 ratio in each round p90 p90 vs first row p90 ratio in each round calls / task output tokens / task $ / task\n", + "Opus 5.5 · high 99.4% 6.6s 13.2s 3.5 943 $0.0399\n", + "Opus 5.5 · high · fast mode 99.2% -0.2 (-1.2 to +1.0) 2.9s ×0.44 (0.42 to 0.47) 0.47 0.51 0.36 5.4s ×0.41 (0.35 to 0.45) 0.39 0.47 0.37 3.5 961 $0.0804" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
settingcorrectcorrect vs first row, pointsp50p50 vs first rowp50 ratio in each roundp90p90 vs first rowp90 ratio in each roundcalls / taskoutput tokens / task$ / task
Opus 5.5 · medium98.4%6.2s11.8s3.5856$0.0377
Opus 5.5 · medium · fast mode99.2%+0.8 (-0.6 to +2.1)2.8s×0.45 (0.43 to 0.47)0.47 0.51 0.385.0s×0.42 (0.37 to 0.46)0.46 0.45 0.363.5869$0.0766
" + ], + "text/plain": [ + "setting correct correct vs first row, points p50 p50 vs first row p50 ratio in each round p90 p90 vs first row p90 ratio in each round calls / task output tokens / task $ / task\n", + "Opus 5.5 · medium 98.4% 6.2s 11.8s 3.5 856 $0.0377\n", + "Opus 5.5 · medium · fast mode 99.2% +0.8 (-0.6 to +2.1) 2.8s ×0.45 (0.43 to 0.47) 0.47 0.51 0.38 5.0s ×0.42 (0.37 to 0.46) 0.46 0.45 0.36 3.5 869 $0.0766" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
settingcorrectcorrect vs first row, pointsp50p50 vs first rowp50 ratio in each roundp90p90 vs first rowp90 ratio in each roundcalls / taskoutput tokens / task$ / task
Opus 5.5 · low98.1%5.3s11.8s3.4755$0.0348
Opus 5.5 · low · fast mode97.7%-0.4 (-1.9 to +1.0)2.5s×0.47 (0.45 to 0.49)0.50 0.54 0.385.0s×0.42 (0.38 to 0.48)0.44 0.47 0.363.4764$0.0699
" + ], + "text/plain": [ + "setting correct correct vs first row, points p50 p50 vs first row p50 ratio in each round p90 p90 vs first row p90 ratio in each round calls / task output tokens / task $ / task\n", + "Opus 5.5 · low 98.1% 5.3s 11.8s 3.4 755 $0.0348\n", + "Opus 5.5 · low · fast mode 97.7% -0.4 (-1.9 to +1.0) 2.5s ×0.47 (0.45 to 0.49) 0.50 0.54 0.38 5.0s ×0.42 (0.38 to 0.48) 0.44 0.47 0.36 3.4 764 $0.0699" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "for effort in reversed(EFFORTS):\n", + " standard = Config(effort=effort)\n", + " display(SWEEP.results_table([replace(standard, speed=\"fast\")], base=standard, rounds=True))" + ] + }, + { + "cell_type": "markdown", + "id": "1006-fast-mode-after", + "metadata": {}, + "source": [ + "At every effort, fast mode cut p50 and p90 by 53% to 59%. Accuracy didn't change significantly, but the cost per task about doubled ($0.0766, compared with $0.0377 at `medium`). If seconds are worth twice the standard price and the task needs Opus-5.5-level intelligence, then fast mode fits. If your tasks are made of many short calls, fast mode might not be worth it because its gain is mostly in OTPS rather than TTFT." + ] + }, + { + "cell_type": "markdown", + "id": "1010-effort", + "metadata": {}, + "source": [ + "\n", + "### Effort\n", + "\n", + "**[Effort](https://platform.claude.com/docs/en/build-with-claude/effort)** sets how thorough the model is. In terms of tokens, that means how much it spends on thinking, text, and tool calls. With adaptive thinking, the model itself decides how much to think and effort steers it. Lower effort trades some capability for fewer tokens and calls, which shortens a call's TTLT and leaves OTPS about where it was. Note that [available effort levels](https://platform.claude.com/docs/en/build-with-claude/effort#effort-levels) and defaults vary from model to model and generation to generation; for Opus 5.5 in the table below, the default is `medium`." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "1012-effort-table", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
settingcorrectcorrect vs medium, pointsp50p50 vs mediump90p90 vs mediumcalls / taskoutput tokens / task$ / task
Opus 5.5 · high99.4%+1.0 (+0.0 to +2.1)6.6s×1.07 (1.03 to 1.12)13.2s×1.12 (1.04 to 1.24)3.5943$0.0399
Opus 5.5 · medium98.4%6.2s11.8s3.5856$0.0377
Opus 5.5 · low98.1%-0.2 (-1.3 to +0.8)5.3s×0.87 (0.83 to 0.91)11.8s×1.00 (0.87 to 1.06)3.4755$0.0348
" + ], + "text/plain": [ + "setting correct correct vs medium, points p50 p50 vs medium p90 p90 vs medium calls / task output tokens / task $ / task\n", + "Opus 5.5 · high 99.4% +1.0 (+0.0 to +2.1) 6.6s ×1.07 (1.03 to 1.12) 13.2s ×1.12 (1.04 to 1.24) 3.5 943 $0.0399\n", + "Opus 5.5 · medium 98.4% 6.2s 11.8s 3.5 856 $0.0377\n", + "Opus 5.5 · low 98.1% -0.2 (-1.3 to +0.8) 5.3s ×0.87 (0.83 to 0.91) 11.8s ×1.00 (0.87 to 1.06) 3.4 755 $0.0348" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ON_BASELINE_LOOP = SWEEP.pick(**LOOPS[\"baseline loop\"])\n", + "table([SWEEP.result_row(Config(effort=effort), BASE, \"medium\") for effort in reversed(EFFORTS)])" + ] + }, + { + "cell_type": "markdown", + "id": "1015-effort-after", + "metadata": {}, + "source": [ + "At `low`, Opus 5.5's p50 fell by a significant 13%, with no significant change in p90 or accuracy. At `high`, p50 rose 7% and p90 12%, both significant, and accuracy didn't change significantly. Those results suggest that relative to the complexity of our eval tasks, Opus 5.5 at `medium` effort might be over-levered, and we could win back latency by reducing effort. In general, start at the model's default, step down until your eval shows accuracy slipping, and only raise effort when the gain justifies the extra wait. We'll do this empirically in [§Putting it all together](#putting-it-all-together)." + ] + }, + { + "cell_type": "markdown", + "id": "1040-per-turn", + "metadata": {}, + "source": [ + "\n", + "#### Per-turn effort\n", + "\n", + "You can also change effort within a conversation, say from `low` to `high` when a hard problem comes in. On the 5.5 models, use the [per-message form](https://platform.claude.com/docs/en/build-with-claude/effort#change-effort-mid-conversation-beta), which persists your prompt cache by appending a system message with empty content and the new effort level. Changing the top-level `output_config.effort` would instead invalidate cached messages, so be sure to use the following syntax:\n", + "\n", + "```json\n", + "{\"role\": \"system\", \"content\": [], \"output_config\": {\"effort\": \"high\"}}\n", + "```\n", + "\n", + "The per-message form works on all 5.5 models with adaptive thinking, but not with Haiku 5.5's thinking off or Sonnet 5.5's `between_tools` (see [§Thinking off](#thinking-off)). In the cell below, Opus 5.5 decides four claims in one conversation at `high` effort. Only the fourth claim is hard, so if we match effort to difficulty, the first three can run at `low`, with a message raising effort to `high` for the fourth." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "1050-per-turn-effort", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " first three claims last claim total decisions right\n", + "BEFORE: high on every claim 12.6s 4.3s 17.3s 20/20\n", + "AFTER: low, then high for the last claim 9.3s 3.7s 13.0s 20/20\n", + "\n", + "→ 4.3s sooner with low effort on the routine claims\n" + ] + } + ], + "source": [ + "EFFORT_BETA = \"mid-conversation-output-config-2026-07-01\"\n", + "# Three routine claims, then one we want more care on\n", + "SESSION = (\"CLM-001\", \"CLM-004\", \"CLM-005\", \"CLM-008\")\n", + "KEY = {\"CLM-001\": \"APPROVE\", \"CLM-004\": \"SIU\", \"CLM-005\": \"DENY\", \"CLM-008\": \"SUPERVISOR\"}\n", + "BEFORE, AFTER = \"BEFORE: high on every claim\", \"AFTER: low, then high for the last claim\"\n", + "GRADES = {BEFORE: [], AFTER: []} # whether each decision matched KEY\n", + "\n", + "\n", + "def work_session(label):\n", + " \"\"\"Decides the SESSION claims in one conversation on Opus 5.5. Returns the seconds\"\"\"\n", + " system, history = new_session()\n", + " effort = \"high\" if label == BEFORE else \"low\"\n", + " secs = []\n", + " for n, cid in enumerate(SESSION, 1):\n", + " if label == AFTER and n == len(SESSION):\n", + " # Raise effort in a message, which keeps the cache\n", + " history.append({\"role\": \"system\", \"content\": [], \"output_config\": {\"effort\": \"high\"}})\n", + " history.append({\"role\": \"user\", \"content\": claim_file(list(CLAIMS).index(cid))})\n", + " extra = {\"betas\": [EFFORT_BETA], \"output_config\": {\"effort\": effort}}\n", + " secs.append(send_turn(cid, system, history, **extra)[\"wait s\"])\n", + " answer = \"\".join(b.text for b in history[-1][\"content\"] if b.type == \"text\")\n", + " GRADES[label].append(f\"DECISION: {KEY[cid]}\" in answer)\n", + " return {\n", + " \"first three claims, s\": sum(secs[:-1]),\n", + " \"last claim, s\": secs[-1],\n", + " \"total, s\": sum(secs),\n", + " }\n", + "\n", + "\n", + "found = compare(\n", + " {BEFORE: lambda: work_session(BEFORE), AFTER: lambda: work_session(AFTER)}, repeats=5\n", + ")\n", + "for label, medians in found.items():\n", + " medians[\"decisions right\"] = f\"{sum(GRADES[label])}/{len(GRADES[label])}\"\n", + "show_medians(found, \"first three claims, s\", \"last claim, s\", \"total, s\", \"decisions right\")\n", + "before, after = (medians[\"total, s\"] for medians in found.values())\n", + "print(f\"\\n→ {before - after:.1f}s sooner with low effort on the routine claims\")" + ] + }, + { + "cell_type": "markdown", + "id": "1055-per-turn-after", + "metadata": {}, + "source": [ + "Running the three routine claims at `low` saved 3.3 seconds, and the conversation finished 4.3 seconds sooner while preserving 100% accuracy. So run routine turns at `low` and raise effort in a message only for the turns that need it. In production, something has to decide which turns those are, such as the task type or a classifier. How much you save depends on your mix of turns, so measure it on your own conversations." + ] + }, + { + "cell_type": "markdown", + "id": "1060-model", + "metadata": {}, + "source": [ + "\n", + "### Model\n", + "\n", + "A smaller model, like Sonnet or Haiku, usually writes output tokens faster, which shortens tasks where most of the time goes to writing output. That's true of our desk agent, where output tokens add more to a task's seconds than the fixed cost of each call. The next cell measures how fast each model writes by comparing every call's seconds with its output tokens. How much longer a call takes for each extra token gives OTPS, and what's left over is the fixed time every call takes, roughly TTFT plus network time." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "1062-fit", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
settingoutput tokens per secondcalls / taskoutput tokens / taskfrom callsfrom tokens
Opus 5.5 · medium1533.58561.9s5.6s
Sonnet 5.5 · medium2363.38701.0s3.7s
Haiku 5.5 · medium5813.92,4921.2s4.3s
" + ], + "text/plain": [ + "setting output tokens per second calls / task output tokens / task from calls from tokens\n", + "Opus 5.5 · medium 153 3.5 856 1.9s 5.6s\n", + "Sonnet 5.5 · medium 236 3.3 870 1.0s 3.7s\n", + "Haiku 5.5 · medium 581 3.9 2,492 1.2s 4.3s" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAmIAAAGHCAYAAAATNz5KAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjIsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvgI3uAAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAxX5JREFUeJzs3Xd8U1X/wPHPvZlNuveijELZAgICigsVxT1xgHs+zset4N57z8cNrsfHvcdPHKAiCijI3tC9V3Zy7++PkNC0aZumaZu25/16+ZLe3Nx7ctI2357zPd8jud0uFUEQBEEQBKHbyT3dAEEQBEEQhP5KBGKCIAiCIAg9RARigiAIgiAIPUQEYoIgCIIgCD1EBGKCIAiCIAg9RARigiAIgiAIPUQEYoIgCIIgCD1EBGKCIAiCIAg9RARigiAIgiAIPaTfBWJ2u52XX36F2bNPZfr06Rx99DFcc821/P333x26ztSp0/jss89a/boz1xL6J6fTyaRJk/n++0U93ZR+p7i4mEmTJrN69Wr/sWeeeYbTTjutB1vVMV9++SXHHXc8U6ZM5Y477gRg0aIfOPHEk5gyZSrXXXd9D7dQEIRg+lUgVlJSwsEHz+DFF1/k+OOP47nnnuOmm27E4/Fw4IEH8euvv4Z8rY0bN1JfX9/q18FMmjSZr776qt1rCaFrrU978j7htklRFDZt2kRDQ0OHnxvtnnjiSebMmdPTzWiVy+Vi06ZN2O12/7GKikq2b9/Rg60KXUlJCWeffQ6HHz6TBQve4JJLLqamppY5c+YwdeoU3njjda655upO3SPa30NB6K20Pd2A7nThhRfhdrtZtOh74uLi/MenT5/OAQccgNvt7tL7b9q0KWjA9fvvS0lPT+/Se/dVrfVpT96nu9rUm1RUVLBjR+8IanyuuOJyzj33nJ5uRkjWrVuP0+lk7ty5xMfHA7Bs2TKsViunn346AwYM6PQ9euN7KAi9Qb8ZEVuxYiWLFy/m+uuvCwjCfE466USmT58OwFFHHcWkSZOZPHkfZs2axbx586isrOzU/adOnQbAbbfdzqRJk5k0aTLFxcUAnHnmWfz888/Anumpt956ixtvvJHDDz+CQw45lGeffRaXy8Vzzz3HrFmzOOigg7n11tuw2WwB91EUhVdeeZXjjjuefffdlzlz5rJ8+Yo223beeedzyy23tjj++ONPcPTRx/i//vzzz3dP6e7PnDlzwh6JslqtPPjggxx22EymT5/OBRdcyD///ON/vLy8nEmTJvPXX38FPO/+++/n4osv9n/dWp/6+vD999/39+Fhh83kxRdfRFXViN0nmLbObe91B7N27VoOPngGDz/8SMCxSy+9lOnT9+fQQw/jiSeeDPgj4uGHH+bcc8/j888/54wzzuCAAw7k/PMvYMuWLQHXLikp4YYbbuDQQw/j8MOP4Pbb76Curq7N9gTzzjvv+F/r9OnTmTNnDt99953/8WeeeYa33nqLjRs3+c97+OGHW72er/1vvfUWp59+OtOn7895553Ptm3bWbVqFeeeex7Tp09n9uxT+fPPP4P2WVv9A95pvGOPPY799tuPc845ly1btra4zrvvvstNN93k/3r+/Pktpvd27drFpEmTWbduXcTaH0xbr+n+++/n8ssvB+Dgg2f4+/jcc88D4Jhjjg2Y8v7555+ZM2cO++67L0cffTQvvvgiiqK0aP9HH33Msccex5QpU7n55nkdeg8FQQhdvxkR+/XXXwDYb7/9Wj1Hlr1x6dNPP4Pb7QK8H1ZPPfU0Rx11NEuWLEan04V1/4ULFzBp0mQuvfRSZs06AoC0tDQgcGrSNz11/fU3MH/+PE477XR+/fUX5s2bz4IFCxk3bi/uvPNOamtrueKKK3G7Xdx///3++1x44UV8++233HHHHYwfP54vvviCo48+mh9+WMSIESOCtm3KlH246667ufnmmzCbzQB4PB7+85//cOqppwLw008/ce6553HfffcxZco+FBcXs3DhQpKTk5kyZUqH+uKss85mw4YN3HffvaSnp/Pyy69w6KGHsXjxzwwbNsw/TdQ8yCwrK6ewsLDdPvV4PGzatIlLLvkXV1xxBffddy+rV//D/Pnzqa+v5/rrvR+mnb1PMG2d297rbu777xdxzjnn8K9/XcL1118HwNKlSzn++BOYOXMmDz30IPX19dxww43s2rWLRx99xN/+Tz/9lIqKCq677jrMZhP33/8AJ5xwIn/8sQyDwQDAqaeeRlpaGnfddSd6vZ5ff/2NefPm8eyzz4byNvodccQsJk6cCIDNZuO3335j7twzee21VznyyCM57bTTWLduHcuW/cFbb70JQGJiYqvXKysr55NPPqGmpobrrrsWgOuuu55jjz0Gvd7AzTffTH7+lbz88kuc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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# The three models at medium effort and standard speed\n", + "MEDIUM = [\n", + " cfg\n", + " for cfg in ON_BASELINE_LOOP\n", + " if cfg.effort == \"medium\" and cfg.thinking == \"adaptive\" and cfg.speed == \"standard\"\n", + "]\n", + "rows = []\n", + "for setting in MEDIUM:\n", + " a, b = SWEEP.fit(setting) # a call's seconds = a + b per 100 output tokens\n", + " calls = SWEEP.value(setting, \"calls\")\n", + " out = SWEEP.value(setting, \"output_tokens\")\n", + " rows.append(\n", + " {\n", + " \"setting\": setting.name,\n", + " \"output tokens per second\": round(100 / b),\n", + " \"calls / task\": calls,\n", + " \"output tokens / task\": round(out),\n", + " # what calls and tokens each add to the average task's seconds\n", + " \"from calls, s\": calls * a,\n", + " \"from tokens, s\": out * b / 100,\n", + " }\n", + " )\n", + "display(table(rows))\n", + "speed_chart(SWEEP, MEDIUM)" + ] + }, + { + "cell_type": "markdown", + "id": "1063-fit-after", + "metadata": {}, + "source": [ + "Haiku 5.5 is the [fastest model in the current lineup](https://platform.claude.com/docs/en/models/overview), writing 581 tokens a second against Sonnet 5.5's 236 and Opus 5.5's 153. But faster tokens don't always mean a faster task. Notice how Haiku 5.5's calls stretch much further right, because it writes more tokens to achieve the same task. Smaller models are faster, but that doesn't mean they're more efficient.\n", + "\n", + "The table below compares Sonnet 5.5 and Haiku 5.5 at `high`, `medium`, and `low` against the Opus 5.5 baseline. Watch accuracy and output tokens as well as the seconds." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "1064-model-table", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
settingcorrectcorrect vs first row, pointsp50p50 vs first rowp50 ratio in each roundp90p90 vs first rowp90 ratio in each roundcalls / taskoutput tokens / task$ / task
Opus 5.5 · medium98.4%6.2s11.8s3.5856$0.0377
Sonnet 5.5 · high97.5%-0.8 (-2.5 to +0.8)4.0s×0.65 (0.61 to 0.69)0.64 0.68 0.648.7s×0.74 (0.67 to 0.83)0.76 0.69 0.783.41,008$0.0201
Sonnet 5.5 · medium94.4%-3.9 (-6.4 to -1.3)3.5s×0.57 (0.53 to 0.62)0.56 0.58 0.578.1s×0.69 (0.59 to 0.74)0.63 0.68 0.763.3870$0.0184
Sonnet 5.5 · low95.3%-3.1 (-5.2 to -1.0)3.4s×0.55 (0.51 to 0.59)0.53 0.57 0.557.9s×0.67 (0.58 to 0.71)0.61 0.68 0.713.3827$0.0178
Haiku 5.5 · high97.5%-0.9 (-2.1 to +0.2)4.9s×0.79 (0.75 to 0.85)0.83 0.72 0.8115.7s×1.33 (1.10 to 1.47)1.51 1.09 1.444.03,441$0.0028
Haiku 5.5 · medium96.0%-2.4 (-4.8 to +0.0)4.0s×0.64 (0.60 to 0.69)0.69 0.60 0.6412.2s×1.03 (0.81 to 1.13)1.10 0.88 1.143.92,492$0.0023
Haiku 5.5 · low90.4%-8.0 (-11.0 to -5.3)3.6s×0.58 (0.55 to 0.62)0.64 0.53 0.589.8s×0.82 (0.68 to 0.94)0.98 0.66 0.873.82,017$0.0020
" + ], + "text/plain": [ + "setting correct correct vs first row, points p50 p50 vs first row p50 ratio in each round p90 p90 vs first row p90 ratio in each round calls / task output tokens / task $ / task\n", + "Opus 5.5 · medium 98.4% 6.2s 11.8s 3.5 856 $0.0377\n", + "Sonnet 5.5 · high 97.5% -0.8 (-2.5 to +0.8) 4.0s ×0.65 (0.61 to 0.69) 0.64 0.68 0.64 8.7s ×0.74 (0.67 to 0.83) 0.76 0.69 0.78 3.4 1,008 $0.0201\n", + "Sonnet 5.5 · medium 94.4% -3.9 (-6.4 to -1.3) 3.5s ×0.57 (0.53 to 0.62) 0.56 0.58 0.57 8.1s ×0.69 (0.59 to 0.74) 0.63 0.68 0.76 3.3 870 $0.0184\n", + "Sonnet 5.5 · low 95.3% -3.1 (-5.2 to -1.0) 3.4s ×0.55 (0.51 to 0.59) 0.53 0.57 0.55 7.9s ×0.67 (0.58 to 0.71) 0.61 0.68 0.71 3.3 827 $0.0178\n", + "Haiku 5.5 · high 97.5% -0.9 (-2.1 to +0.2) 4.9s ×0.79 (0.75 to 0.85) 0.83 0.72 0.81 15.7s ×1.33 (1.10 to 1.47) 1.51 1.09 1.44 4.0 3,441 $0.0028\n", + "Haiku 5.5 · medium 96.0% -2.4 (-4.8 to +0.0) 4.0s ×0.64 (0.60 to 0.69) 0.69 0.60 0.64 12.2s ×1.03 (0.81 to 1.13) 1.10 0.88 1.14 3.9 2,492 $0.0023\n", + "Haiku 5.5 · low 90.4% -8.0 (-11.0 to -5.3) 3.6s ×0.58 (0.55 to 0.62) 0.64 0.53 0.58 9.8s ×0.82 (0.68 to 0.94) 0.98 0.66 0.87 3.8 2,017 $0.0020" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "SMALLER = [cfg for cfg in ON_BASELINE_LOOP if cfg.model != OPUS and cfg.thinking == \"adaptive\"]\n", + "SWEEP.results_table(SMALLER, rounds=True)" + ] + }, + { + "cell_type": "markdown", + "id": "1066-model-after", + "metadata": {}, + "source": [ + "At `medium`, the same effort as the Opus 5.5 baseline, Sonnet cut the median task time by 2.7 seconds and Haiku by 2.2. Sonnet was faster because it wrote far fewer output tokens than Haiku, even though Haiku was emitting its extra tokens faster. That's even more apparent at p90, where Haiku at `high` took 3.9 seconds longer than Opus. Both Sonnet and Haiku were less accurate at `medium`, however, by 3.9 and 2.4 points respectively, so the time they save comes out of quality. And while cost per task falls steadily with model size, by about 2x on Sonnet and 16x on Haiku, accuracy and latency don't. Haiku at `high` scored 2.2 points higher than Sonnet at `low` but took 7.8 seconds longer at p90. \n", + "\n", + "The lesson here is to compare settings on your eval rather than by model size and sticker price alone, as we do in [§Putting it all together](#putting-it-all-together). For speed, we recommend moving only jobs that need little reasoning to a smaller model." + ] + }, + { + "cell_type": "markdown", + "id": "1070-thinking-off", + "metadata": {}, + "source": [ + "\n", + "### Thinking off\n", + "\n", + "Thinking is the reasoning a model writes before and between its answers and tool calls. It's a large part of what makes a model capable, so turning it off is for when speed matters more than accuracy. Haiku 5.5 is the only one of the three models that accepts `thinking: {\"type\": \"disabled\"}`, and Sonnet 5.5's lowest thinking setting is [`thinking: {\"type\": \"between_tools\"}`](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-sonnet-5-5#running-without-up-front-thinking), which turns off up-front thinking. Both work only at `high` effort or below.\n", + "\n", + "We ran Haiku 5.5 with thinking off at all three effort levels, and the cell below compares each against Haiku 5.5 at `high` with thinking on." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "1072-thinking-off-table", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
settingcorrectcorrect vs first row, pointsp50p50 vs first rowp50 ratio in each roundp90p90 vs first rowp90 ratio in each roundcalls / taskoutput tokens / task$ / task
Haiku 5.5 · high97.5%4.9s15.7s4.03,441$0.0028
Haiku 5.5 · high · thinking off73.5%-24.0 (-27.8 to -20.2)3.7s×0.76 (0.71 to 0.79)0.75 0.77 0.768.9s×0.56 (0.50 to 0.61)0.56 0.56 0.573.81,962$0.0020
Haiku 5.5 · medium · thinking off70.9%-26.6 (-30.7 to -22.5)3.4s×0.71 (0.67 to 0.74)0.72 0.70 0.697.7s×0.49 (0.46 to 0.55)0.47 0.48 0.523.81,739$0.0019
Haiku 5.5 · low · thinking off72.0%-25.5 (-29.7 to -21.0)3.3s×0.67 (0.62 to 0.69)0.70 0.68 0.637.6s×0.48 (0.44 to 0.53)0.45 0.51 0.493.81,574$0.0017
" + ], + "text/plain": [ + "setting correct correct vs first row, points p50 p50 vs first row p50 ratio in each round p90 p90 vs first row p90 ratio in each round calls / task output tokens / task $ / task\n", + "Haiku 5.5 · high 97.5% 4.9s 15.7s 4.0 3,441 $0.0028\n", + "Haiku 5.5 · high · thinking off 73.5% -24.0 (-27.8 to -20.2) 3.7s ×0.76 (0.71 to 0.79) 0.75 0.77 0.76 8.9s ×0.56 (0.50 to 0.61) 0.56 0.56 0.57 3.8 1,962 $0.0020\n", + "Haiku 5.5 · medium · thinking off 70.9% -26.6 (-30.7 to -22.5) 3.4s ×0.71 (0.67 to 0.74) 0.72 0.70 0.69 7.7s ×0.49 (0.46 to 0.55) 0.47 0.48 0.52 3.8 1,739 $0.0019\n", + "Haiku 5.5 · low · thinking off 72.0% -25.5 (-29.7 to -21.0) 3.3s ×0.67 (0.62 to 0.69) 0.70 0.68 0.63 7.6s ×0.48 (0.44 to 0.53) 0.45 0.51 0.49 3.8 1,574 $0.0017" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Against Haiku 5.5 at high with thinking on, not the Opus 5.5 baseline\n", + "THINKING_ON = Config(HAIKU, \"high\")\n", + "THINKING_OFF = [cfg for cfg in ON_BASELINE_LOOP if cfg.thinking == \"disabled\"]\n", + "SWEEP.results_table(THINKING_OFF, base=THINKING_ON, rounds=True)" + ] + }, + { + "cell_type": "markdown", + "id": "1074-thinking-off-after", + "metadata": {}, + "source": [ + "At `high`, turning thinking off cut Haiku 5.5's p50 by 1.2 seconds and its p90 by 6.8, but accuracy fell 24 points. Lowering effort saved a little more time but still degraded accuracy. The speed gains cost roughly one answer in four, so when it comes to your own agents, we recommend only keeping thinking off if your eval shows accuracy holding.\n", + "\n", + "Sonnet 5.5's `between_tools` works differently from turning thinking off. It skips the thinking before a reply's first output and keeps a lighter amount between tool calls. That saves time only when a reply would otherwise open with a long think. Our desk agent's replies always start with a lookup, which leaves nothing to skip. But it makes a bigger difference when we prompt for a long written reply. The cell below asks Sonnet 5.5 at `high` to write up its decision on a claim, once with adaptive thinking and once with `between_tools`, and checks whether each decision is right." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "1076-between-tools-demo", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " first thing on screen done output tokens of which thinking decisions right\n", + "BEFORE: adaptive thinking 15.8s 33.9s 4,633 1,944 5/5\n", + "AFTER: between_tools 0.5s 23.2s 3,217 0 3/5\n", + "\n", + "→ text on screen 15.2s sooner with between_tools, and done 10.7s sooner\n" + ] + } + ], + "source": [ + "MEMO_DECISION = (\n", + " claim_record(\"CLM-008\") + \"\\n\\nWrite an adjudication memo covering coverage analysis, damages, \"\n", + " \"fraud review, authority, and a final recommendation. End the memo with exactly these two \"\n", + " f\"lines:\\n{TWO_LINES}\"\n", + ")\n", + "MEMO_GRADES = {\"adaptive\": [], \"between_tools\": []}\n", + "\n", + "\n", + "def sonnet_memo(thinking):\n", + " \"\"\"Streams the memo on Sonnet 5.5 at high effort. Returns its seconds and token counts\"\"\"\n", + " cfg = Config(SONNET, \"high\", thinking=thinking)\n", + " message, marks = timed_stream(**single_request(MEMO_DECISION, cfg, system=MEMO_SYSTEM))\n", + " text = \"\".join(b.text for b in message.content if b.type == \"text\")\n", + " decision = text.rpartition(\"DECISION:\")[2].partition(\"WHY\")[0]\n", + " MEMO_GRADES[thinking].append(\"SUPERVISOR\" in decision)\n", + " counts = token_counts(message.usage)\n", + " return {\n", + " \"first thing on screen, s\": min(marks.values()),\n", + " \"done, s\": marks[\"done\"],\n", + " \"output tokens\": counts[\"output_tokens\"],\n", + " \"of which thinking\": counts[\"thinking_tokens\"],\n", + " }\n", + "\n", + "\n", + "found = compare(\n", + " {\n", + " \"BEFORE: adaptive thinking\": lambda: sonnet_memo(\"adaptive\"),\n", + " \"AFTER: between_tools\": lambda: sonnet_memo(\"between_tools\"),\n", + " },\n", + " repeats=5,\n", + ")\n", + "for medians, grades in zip(found.values(), MEMO_GRADES.values(), strict=True):\n", + " medians[\"decisions right\"] = f\"{sum(grades)}/{len(grades)}\"\n", + "show_medians(found, *next(iter(found.values())))\n", + "before, after = found.values()\n", + "print(\n", + " f\"\\n→ text on screen {before['first thing on screen, s'] - after['first thing on screen, s']:.1f}s sooner \"\n", + " f\"with between_tools, and done {before['done, s'] - after['done, s']:.1f}s sooner\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "1078-between-tools-after", + "metadata": {}, + "source": [ + "With adaptive thinking, Sonnet 5.5 thought for about 1,900 tokens before writing, and the user had to wait for 15.8 seconds during that time. `between_tools` put text on screen in half a second and finished emitting its last token 10.7 seconds sooner. Yet speed came at the cost of accuracy again, with just three out of five decisions correct. So you can use Sonnet 5.5 with `between_tools` to limit TTFT and TTLT on reasoning-heavy tasks that a user waits on, but be sure to check accuracy on your evals." + ] + }, + { + "cell_type": "markdown", + "id": "1080-limits", + "metadata": {}, + "source": [ + "\n", + "## Limiting the longest task\n", + "\n", + "The levers so far shorten p50 and p90 latency, but none of them bounds p99. Our application needs levers that mitigate the most extreme wait times, which are often caused by erroneous trajectories like a call that stalls, a reply that runs on, or a loop that keeps looking things up. Limits come in two kinds: a **stop** is enforced from outside the model, by your code or by the API, while a **signal** is a count the model can see and pace itself to. You can count tokens, calls, or seconds to know when a task has gone on too long, using the following mechanisms:\n", + "\n", + "| Limit | Kind | What it counts |\n", + "|---|---|---|\n", + "| `max_tokens` | Stop, by the API | Tokens |\n", + "| A task budget | Signal | Tokens |\n", + "| A turn cap | Stop, by your code | Calls |\n", + "| A last-call message | Signal | Calls |\n", + "| A timeout | Stop, by your code | Seconds |\n", + "| A clock shown to the model | Signal | Seconds |\n", + "\n", + "Stops and signals work best together. A stop alone cuts the task off with no answer, and a signal alone won't help if a call stalls. With both, the model sees the limit coming and answers before the stop has to act. Pick the limit that matches the problem: seconds when a user is waiting, calls when loops are the risk, and tokens when replies run long." + ] + }, + { + "cell_type": "markdown", + "id": "1081-tokens", + "metadata": {}, + "source": [ + "#### Tokens: `max_tokens` and a task budget\n", + "\n", + "`max_tokens` is a hard cap on how many tokens the model can emit on a given turn. The model doesn't see it, so a lower cap doesn't necessarily make it write less. Whenever thinking is on, the cap covers thinking and tool calls as well as text, so a low cap can end a request before any answer is written. Set it high enough that real answers don't reach it, and catch `stop_reason: \"max_tokens\"` the way you'd catch an error.\n", + "\n", + "The API's limit on a whole agent loop's tokens, a [task budget](https://platform.claude.com/docs/en/build-with-claude/task-budgets), is not deterministically enforced. It's one allowance of tokens shared by every request in the loop, counting thinking, tool calls, tool results, and text. The model paces its work to the remaining budget, and too tight a budget can make the model stop early or skip steps. A budget limits seconds only indirectly, so when your limit is in seconds, the clock below is a better fit." + ] + }, + { + "cell_type": "markdown", + "id": "1081-calls", + "metadata": {}, + "source": [ + "#### Calls: a turn cap and a last-call message\n", + "\n", + "A cap on model calls is a crude stop for a loop that never records an answer. These lines stop the loop at `TURN_CAP`, 16 calls, and tell the model after its 15th call that its next is its last:\n", + "\n", + "```python\n", + "while len(calls) < desk_agent.TURN_CAP:\n", + " ...\n", + " if len(calls) == desk_agent.TURN_CAP - 1:\n", + " results = [f\"{r}\\n\\n{desk_agent.TURN_CAP_MESSAGE}\" for r in results]\n", + "```\n", + "\n", + "Without the message, the cap would end the task mid-lookup with no answer, but with it the model spends its last call recording its best answer." + ] + }, + { + "cell_type": "markdown", + "id": "1081-seconds", + "metadata": {}, + "source": [ + "#### Seconds: a timeout and a clock\n", + "\n", + "The model has no clock of its own, so it can't innately tell the difference between one second and ten minutes. If your task needs to complete in some amount of time, add the elapsed time against that limit to the end of the newest user message before each request. The model will pace its work to finish inside that limit and usually finishes well before it. The code snippet below adds a clock to our baseline, measured against a 60-second `TIME_LIMIT`:\n", + "\n", + "```python\n", + "def add_clock(message, seconds):\n", + " \"\"\"Adds the elapsed time, against the limit, to the end of a user message\"\"\"\n", + " clock, last = f\"elapsed {seconds:.0f}s / {TIME_LIMIT}s\", message[\"content\"][-1]\n", + " if last[\"type\"] == \"tool_result\":\n", + " last[\"content\"] += f\"\\n\\n{clock}\"\n", + " else:\n", + " message[\"content\"].append({\"type\": \"text\", \"text\": clock})\n", + "\n", + "\n", + "task_start = time.perf_counter()\n", + "while True:\n", + " add_clock(history[-1], time.perf_counter() - task_start) # the newest message only\n", + " ...\n", + "```\n", + "\n", + "Each earlier clock stays where it is, so the cached prefix still matches on the next request. In cases where the model doesn't respect the clock, you should define a timeout in code. Set each stop above what your healthy tasks need, so it only catches runaway ones, and decide what the user sees when one fires, such as a partial answer, a retry, or a handoff. Before you set any of these stops, count how often each would have fired on your recorded tasks, since each of those tasks would have ended with no answer. The next cell does that for the sweep." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "1082-limits-sweep", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "model task runs over 60s most calls in a task calls at 16,000 output tokens\n", + "Opus 5.5 6,893 0 5 0\n", + "Sonnet 5.5 2,760 0 5 0\n", + "Haiku 5.5 5,519 0 8 1\n" + ] + } + ], + "source": [ + "rows = []\n", + "for model, name in NAME.items():\n", + " runs = [line for (cfg, _), got in SWEEP.rows.items() if cfg.model == model for line in got]\n", + " outputs = [tokens for line in runs for tokens in line[\"call_output_tokens\"]]\n", + " rows.append(\n", + " {\n", + " \"model\": name,\n", + " \"task runs\": len(runs),\n", + " f\"over {TIME_LIMIT}s\": sum(line[\"secs\"] > TIME_LIMIT for line in runs),\n", + " \"most calls in a task\": max(len(line[\"call_secs\"]) for line in runs),\n", + " f\"calls at {MAX_TOKENS:,} output tokens\": sum(t >= MAX_TOKENS for t in outputs),\n", + " }\n", + " )\n", + "show(rows)" + ] + }, + { + "cell_type": "markdown", + "id": "1085-limits-after", + "metadata": {}, + "source": [ + "In the sweep, a 60-second timeout wouldn't have ended any of the 15,172 task runs, no task took more than 8 of its 16 calls, and only 1 call reached `MAX_TOKENS`. The stops cost almost nothing while capping how long any user waits, so `run_task()` in [§Putting it all together](#putting-it-all-together) keeps all three, plus the last-call message. We didn't proceed with a task budget or a clock because our tasks are short and take few calls, which leaves the model little to pace." + ] + }, + { + "cell_type": "markdown", + "id": "1088-ux", + "metadata": {}, + "source": [ + "\n", + "## User experience design\n", + "\n", + "No matter how good a model or harness is, there's always some amount of wait time incurred. And in user-facing applications, how long that wait feels matters just as much as how long it is. The levers in this section put something on screen sooner, which shortens the perceived wait even when the total time stays the same." + ] + }, + { + "cell_type": "markdown", + "id": "1089-streaming", + "metadata": {}, + "source": [ + "\n", + "### Streaming\n", + "\n", + "[Streaming](https://platform.claude.com/docs/en/build-with-claude/streaming) sends the reply as it's generated, so the user starts reading at its first token instead of waiting for the whole reply. The API delivers the reply as a series of events, each carrying the next piece of text or tool input, and your application shows each piece as it arrives. Turning it on takes one change, streaming each request instead of calling `create()`. In the Python SDK it looks like this:\n", + "\n", + "```python\n", + "with client.messages.stream(**request) as stream:\n", + " for text in stream.text_stream:\n", + " print(text, end=\"\", flush=True) # show each piece as it arrives\n", + " message = stream.get_final_message()\n", + "```\n", + "\n", + "Streaming can also save time in an agent loop. A reply's tool calls arrive one after another, and each finishes streaming before the reply does, so your loop can start each tool as soon as its call arrives instead of waiting for the whole reply. [Fine-grained tool streaming](https://platform.claude.com/docs/en/agents-and-tools/tool-use/fine-grained-tool-streaming) goes a step further and streams each tool's input as it's written, though the input may not be valid JSON until it's complete. Your application should stream whenever a user watches the reply arrive and start tools early when replies carry several tool calls." + ] + }, + { + "cell_type": "markdown", + "id": "1090-thinking-state", + "metadata": {}, + "source": [ + "\n", + "### UI during thinking state\n", + "\n", + "Streaming only helps once output tokens are being emitted. With thinking on, the model thinks before it writes its answer, and by default the API doesn't send that thinking to the client. The [`display`](https://platform.claude.com/docs/en/build-with-claude/thinking#controlling-thinking-display) field defaults to `\"omitted\"`, which is also our baseline's setting. With it, nothing reaches the screen until the model finishes thinking. But if you set `display` to `\"summarized\"`, then the API streams a readable summary of thinking as it goes, so the user sees the model working instead of a blank screen.\n", + "\n", + "In an agent loop, the short [progress updates](https://platform.claude.com/docs/en/build-with-claude/thinking#progress-updates) that Opus 5.5 and Sonnet 5.5 write between tool calls arrive as thinking, so an interface left on the default also goes quiet while the agent works. `\"updates\"` (in beta, with the `thinking-display-updates-2026-08-18` header) keeps the reasoning hidden and returns those notes readable. Without an API setting, your interface can also show which tool is running, such as \"Searching the ledger…\", which keeps the screen from going quiet. Sonnet 5.5's `between_tools` removes the empty screen another way, by skipping the think instead of showing it, as discussed in [§Thinking off](#thinking-off).\n", + "\n", + "The cell below streams one memo, outside the agent loop, with the thinking omitted and then summarized. Watch the `first thing on screen` column." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "1092-streaming", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " first thing on screen first answer text done output tokens\n", + "BEFORE: thinking omitted 26.3s 26.3s 64.5s 6,923\n", + "AFTER: thinking summarized 4.2s 25.1s 58.2s 6,339\n", + "\n", + "→ the screen stays empty for 64.5s without streaming, 26.3s streaming with the thinking omitted, and 4.2s with it summarized\n" + ] + } + ], + "source": [ + "MEMO = (\n", + " claim_record(\"CLM-008\") + \"\\n\\nWrite an adjudication memo covering coverage analysis, damages, \"\n", + " \"fraud review, authority, and a final recommendation.\"\n", + ")\n", + "\n", + "\n", + "def memo(display):\n", + " thinking = {\"type\": \"adaptive\", \"display\": display}\n", + " return timed(single_request(MEMO, system=MEMO_SYSTEM, thinking=thinking))\n", + "\n", + "\n", + "found = compare(\n", + " {\n", + " \"BEFORE: thinking omitted\": lambda: memo(\"omitted\"),\n", + " \"AFTER: thinking summarized\": lambda: memo(\"summarized\"),\n", + " },\n", + " repeats=5,\n", + ")\n", + "show_medians(found, \"first thing on screen, s\", \"first answer text, s\", \"done, s\", \"output tokens\")\n", + "before, after = found.values()\n", + "print(\n", + " f\"\\n→ the screen stays empty for {before['done, s']:.1f}s without streaming, \"\n", + " f\"{before['first thing on screen, s']:.1f}s streaming with the thinking omitted, \"\n", + " f\"and {after['first thing on screen, s']:.1f}s with it summarized\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "1095-ux-after", + "metadata": {}, + "source": [ + "The summary put text on screen 22.1 seconds sooner. Showing the thinking shouldn't change how long the model takes to answer, and the small differences in answer and finish time are within run-to-run variance. For an agent that someone follows on screen, we recommend showing something while it thinks, whether a summary of the thinking, the `\"updates\"` display, or a status line naming the current tool." + ] + }, + { + "cell_type": "markdown", + "id": "1100-together", + "metadata": {}, + "source": [ + "\n", + "## Putting it all together\n", + "\n", + "Now that we've covered the different levers, let's decide which ones cut latency most for Acme's phone line (p90 TTFT) and chat agent (p50 TTLT). Testing every combination would blow past a reasonable budget, so we'll narrow the field first. Based on what the earlier sections showed, we'll sort the levers into those that have no negative impact on cost or accuracy, those that don't fit our use case, and those that need further testing. Then we'll shortlist what's left and run every combination, letting each product pick the fastest setting that clears its quality bar.\n", + "\n", + "**Clear wins** (these help latency and cost without any tradeoff):\n", + "\n", + "| Lever | Why it stays on |\n", + "|---|---|\n", + "| [Prompt caching](#prompt-caching) | Cut cost by 85% with no impact on latency or accuracy |\n", + "| [Streaming](#streaming), [UI during thinking](#ui-during-thinking-state) | Get something on screen sooner without changing task time |\n", + "| [Turn cap, last-call message, timeout](#limiting-the-longest-task) | Bound the worst case at almost no cost |\n", + "| [Structured answers](#structured-outputs) | Responses go through an answer tool with fixed fields |\n", + "\n", + "**Ruled out** (these don't fit our product's shape, degrade latency, or result in accuracy below the quality bar):\n", + "\n", + "| Lever | Why it's ruled out |\n", + "|---|---|\n", + "| [Sending fewer input tokens](#sending-fewer-tokens) | Most of our prompt is the policy manual the tasks need |\n", + "| [Pre-warming](#pre-warming) | Our prompt is too short for this to matter |\n", + "| [Message threads](#message-threads) | Our tasks take too few calls for the per-call saving to add up |\n", + "| [Background compaction](#background-compaction) | Each task is one short conversation that runs short of a compaction threshold |\n", + "| [Subagents](#subagents) | Our tasks are a few lookups in a row instead of independent pieces |\n", + "| [Programmatic tool calling](#programmatic-tool-calling) | Our tasks take few calls with small results |\n", + "| [No commentary](#no-commentary) | Our agent writes almost nothing between tool calls |\n", + "| [Per-turn effort](#per-turn-effort) | Each task is one job at one difficulty |\n", + "| [`between_tools`](#thinking-off) | Our replies open with a lookup so there's no up-front think to skip |\n", + "| [Thinking off](#thinking-off) | Failed the accuracy bar on every effort |\n", + "\n", + "**Needs testing** (these sped things up on their own, but it's not yet clear how they'll interact with each other):\n", + "\n", + "| Lever | Why it needs testing |\n", + "|---|---|\n", + "| [Prefetch](#prefetch-and-bigger-pages) | Cut task time on the baseline but slowed the first token |\n", + "| [Bigger pages](#prefetch-and-bigger-pages) | Cut task time on the baseline, only measured there |\n", + "| [Model](#model) | Smaller models wrote faster but sometimes wrote more |\n", + "| [Effort](#effort) | Lower effort was faster, with accuracy costs that varied by model |\n", + "| [Fast mode](#fast-mode) | Much faster on Opus 5.5 but twice the price |\n", + "\n", + "We'll apply the clear wins as our new baseline and run a multivariate test with the levers that need testing. That's prefetch and bigger pages, each on or off, crossed with eight model settings: Haiku 5.5 at `medium` and `high`, Sonnet 5.5 at every effort, and Opus 5.5 with fast mode at every effort. Opus 5.5 at standard speed is left out because it was too slow for either product, and Haiku 5.5 at `low` because, at 90.4%, it was too far below the 95% bar for a loop change to close the gap. That makes 32 settings, each run on all 154 tasks for three rounds with the loop below." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "1105-loop", + "metadata": {}, + "outputs": [], + "source": [ + "def run_task(task, cfg):\n", + " \"\"\"Runs one task until it records an answer, gives up, or runs out of time. Returns its id, type, grade, and a row\n", + " per model call that finished\"\"\"\n", + " prefetch, big_pages = \"prefetch\" in cfg.loop, \"big_pages\" in cfg.loop\n", + " prompt = desk_agent.system_prompt(no_commentary=cfg.commentary == \"none\")\n", + " system = [cached({\"type\": \"text\", \"text\": prompt})]\n", + " tools = desk_agent.tool_specs(big_pages=big_pages)\n", + " first = desk_agent.first_turn(task, prefetch=prefetch, big_pages=big_pages)\n", + " history = [{\"role\": \"user\", \"content\": [{\"type\": \"text\", \"text\": first}]}]\n", + " calls, recorder, nudged = [], None, False\n", + " deadline = time.perf_counter() + TIME_LIMIT\n", + " while len(calls) < desk_agent.TURN_CAP:\n", + " # Cache breakpoints on the first user turn and the newest one. They go on a copy, so the\n", + " # history we keep never carries an old breakpoint\n", + " messages = list(history)\n", + " for k in {0, len(messages) - 1}:\n", + " *before, last = messages[k][\"content\"]\n", + " messages[k] = {\"role\": \"user\", \"content\": [*before, cached(last)]}\n", + " try:\n", + " m, marks = timed_stream(\n", + " **cfg.kwargs(),\n", + " max_tokens=MAX_TOKENS,\n", + " system=system,\n", + " tools=tools,\n", + " messages=messages,\n", + " deadline=deadline,\n", + " )\n", + " except TimeoutError: # past TIME_LIMIT: nothing recorded, so it counts as wrong\n", + " break\n", + " history.append({\"role\": \"assistant\", \"content\": m.content}) # thinking blocks included\n", + " uses = [b for b in m.content if b.type == \"tool_use\"]\n", + " calls.append(\n", + " {\"secs\": marks[\"done\"], \"tools\": [b.name for b in uses], **token_counts(m.usage)}\n", + " )\n", + " if m.stop_reason in (\"max_tokens\", \"refusal\"): # counts as wrong\n", + " break\n", + " recorder = next((b for b in uses if desk_agent.is_terminal(b.name)), None)\n", + " if recorder or (nudged and not uses):\n", + " break\n", + " if not uses: # one reminder, then the task ends with nothing recorded\n", + " nudged = True\n", + " reminder = {\"type\": \"text\", \"text\": desk_agent.NUDGE_MESSAGE}\n", + " history.append({\"role\": \"user\", \"content\": [reminder]})\n", + " continue\n", + " with ThreadPoolExecutor(max_workers=8) as pool: # one turn's lookups run side by side\n", + " results = list(\n", + " pool.map(\n", + " lambda b: desk_agent.call_tool(task, b.name, b.input, big_pages=big_pages), uses\n", + " )\n", + " )\n", + " if len(calls) == desk_agent.TURN_CAP - 1:\n", + " results = [f\"{r}\\n\\n{desk_agent.TURN_CAP_MESSAGE}\" for r in results]\n", + " blocks = [\n", + " {\"type\": \"tool_result\", \"tool_use_id\": b.id, \"content\": r}\n", + " | ({\"is_error\": True} if r.startswith(\"ERROR: \") else {})\n", + " for b, r in zip(uses, results, strict=True)\n", + " ]\n", + " history.append({\"role\": \"user\", \"content\": blocks}) # one message, in call order\n", + " recorded = {\"name\": recorder.name, \"args\": recorder.input} if recorder else None\n", + " correct = bool(desk_agent.grade(task, recorded)[\"correct\"])\n", + " return {\"task\": task[\"id\"], \"type\": task[\"type\"], \"correct\": correct, \"calls\": calls}" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "1210-race", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
settingcorrectfirst token p90p50p90$ / task
Opus 5.5 · high · fast mode100.0%0.73s3.7s7.1s$0.0804
Opus 5.5 · high · fast mode + prefetch98.1%1.19s2.8s6.1s$0.0712
Opus 5.5 · high · fast mode + bigger pages98.7%0.72s3.6s6.4s$0.0776
Opus 5.5 · high · fast mode + prefetch + bigger pages99.4%1.15s2.7s5.5s$0.0678
Opus 5.5 · medium · fast mode99.2%0.77s3.6s6.7s$0.0761
Opus 5.5 · medium · fast mode + prefetch99.0%1.03s2.6s5.9s$0.0664
Opus 5.5 · medium · fast mode + bigger pages98.4%0.70s3.3s5.9s$0.0729
Opus 5.5 · medium · fast mode + prefetch + bigger pages97.9%1.13s2.4s5.2s$0.0641
Opus 5.5 · low · fast mode98.8%0.65s2.9s6.0s$0.0689
Opus 5.5 · low · fast mode + prefetch97.7%0.92s2.4s5.7s$0.0591
Opus 5.5 · low · fast mode + bigger pages97.5%0.65s2.8s5.3s$0.0653
Opus 5.5 · low · fast mode + prefetch + bigger pages96.9%0.95s2.3s5.1s$0.0557
Sonnet 5.5 · high97.9%0.71s5.4s13.2s$0.0205
Sonnet 5.5 · high + prefetch98.1%1.69s4.9s15.0s$0.0196
Sonnet 5.5 · high + bigger pages97.7%0.69s5.0s13.2s$0.0193
Sonnet 5.5 · high + prefetch + bigger pages97.5%1.78s4.4s14.1s$0.0179
Sonnet 5.5 · medium94.8%0.71s4.7s11.1s$0.0186
Sonnet 5.5 · medium + prefetch97.1%1.23s3.9s10.6s$0.0162
Sonnet 5.5 · medium + bigger pages95.9%0.65s4.4s11.1s$0.0175
Sonnet 5.5 · medium + prefetch + bigger pages94.7%1.04s3.7s9.8s$0.0150
Sonnet 5.5 · low94.4%0.68s4.6s10.6s$0.0180
Sonnet 5.5 · low + prefetch94.9%0.92s3.6s10.7s$0.0155
Sonnet 5.5 · low + bigger pages94.8%0.73s4.3s10.6s$0.0170
Sonnet 5.5 · low + prefetch + bigger pages93.8%0.85s3.5s9.3s$0.0144
Haiku 5.5 · high96.0%0.82s9.0s31.6s$0.0028
Haiku 5.5 · high + prefetch95.9%3.39s8.8s31.9s$0.0025
Haiku 5.5 · high + bigger pages96.1%0.82s9.7s33.1s$0.0029
Haiku 5.5 · high + prefetch + bigger pages95.6%3.40s8.6s32.3s$0.0024
Haiku 5.5 · medium96.2%0.82s7.5s24.1s$0.0023
Haiku 5.5 · medium + prefetch96.4%2.60s7.1s25.5s$0.0020
Haiku 5.5 · medium + bigger pages94.5%0.84s7.6s24.0s$0.0023
Haiku 5.5 · medium + prefetch + bigger pages96.2%2.61s7.0s22.8s$0.0019
" + ], + "text/plain": [ + "setting correct first token p90 p50 p90 $ / task\n", + "Opus 5.5 · high · fast mode 100.0% 0.73s 3.7s 7.1s $0.0804\n", + "Opus 5.5 · high · fast mode + prefetch 98.1% 1.19s 2.8s 6.1s $0.0712\n", + "Opus 5.5 · high · fast mode + bigger pages 98.7% 0.72s 3.6s 6.4s $0.0776\n", + "Opus 5.5 · high · fast mode + prefetch + bigger pages 99.4% 1.15s 2.7s 5.5s $0.0678\n", + "Opus 5.5 · medium · fast mode 99.2% 0.77s 3.6s 6.7s $0.0761\n", + "Opus 5.5 · medium · fast mode + prefetch 99.0% 1.03s 2.6s 5.9s $0.0664\n", + "Opus 5.5 · medium · fast mode + bigger pages 98.4% 0.70s 3.3s 5.9s $0.0729\n", + "Opus 5.5 · medium · fast mode + prefetch + bigger pages 97.9% 1.13s 2.4s 5.2s $0.0641\n", + "Opus 5.5 · low · fast mode 98.8% 0.65s 2.9s 6.0s $0.0689\n", + "Opus 5.5 · low · fast mode + prefetch 97.7% 0.92s 2.4s 5.7s $0.0591\n", + "Opus 5.5 · low · fast mode + bigger pages 97.5% 0.65s 2.8s 5.3s $0.0653\n", + "Opus 5.5 · low · fast mode + prefetch + bigger pages 96.9% 0.95s 2.3s 5.1s $0.0557\n", + "Sonnet 5.5 · high 97.9% 0.71s 5.4s 13.2s $0.0205\n", + "Sonnet 5.5 · high + prefetch 98.1% 1.69s 4.9s 15.0s $0.0196\n", + "Sonnet 5.5 · high + bigger pages 97.7% 0.69s 5.0s 13.2s $0.0193\n", + "Sonnet 5.5 · high + prefetch + bigger pages 97.5% 1.78s 4.4s 14.1s $0.0179\n", + "Sonnet 5.5 · medium 94.8% 0.71s 4.7s 11.1s $0.0186\n", + "Sonnet 5.5 · medium + prefetch 97.1% 1.23s 3.9s 10.6s $0.0162\n", + "Sonnet 5.5 · medium + bigger pages 95.9% 0.65s 4.4s 11.1s $0.0175\n", + "Sonnet 5.5 · medium + prefetch + bigger pages 94.7% 1.04s 3.7s 9.8s $0.0150\n", + "Sonnet 5.5 · low 94.4% 0.68s 4.6s 10.6s $0.0180\n", + "Sonnet 5.5 · low + prefetch 94.9% 0.92s 3.6s 10.7s $0.0155\n", + "Sonnet 5.5 · low + bigger pages 94.8% 0.73s 4.3s 10.6s $0.0170\n", + "Sonnet 5.5 · low + prefetch + bigger pages 93.8% 0.85s 3.5s 9.3s $0.0144\n", + "Haiku 5.5 · high 96.0% 0.82s 9.0s 31.6s $0.0028\n", + "Haiku 5.5 · high + prefetch 95.9% 3.39s 8.8s 31.9s $0.0025\n", + "Haiku 5.5 · high + bigger pages 96.1% 0.82s 9.7s 33.1s $0.0029\n", + "Haiku 5.5 · high + prefetch + bigger pages 95.6% 3.40s 8.6s 32.3s $0.0024\n", + "Haiku 5.5 · medium 96.2% 0.82s 7.5s 24.1s $0.0023\n", + "Haiku 5.5 · medium + prefetch 96.4% 2.60s 7.1s 25.5s $0.0020\n", + "Haiku 5.5 · medium + bigger pages 94.5% 0.84s 7.6s 24.0s $0.0023\n", + "Haiku 5.5 · medium + prefetch + bigger pages 96.2% 2.61s 7.0s 22.8s $0.0019" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Haiku 5.5 at low fell short of the bar on the baseline loop, so it's left out\n", + "RACE = Sweep(\n", + " \"results/race.jsonl\",\n", + " Config,\n", + " keep=lambda line: (line[\"model\"], line[\"effort\"]) != (HAIKU, \"low\"),\n", + " stop=TIME_LIMIT,\n", + ")\n", + "rows = [\n", + " {\n", + " \"setting\": cfg.name,\n", + " \"correct\": f\"{RACE.value(cfg, 'correct'):.1%}\",\n", + " \"first token p90\": f\"{RACE.value(cfg, 'first token p90'):.2f}s\",\n", + " \"p50\": f\"{RACE.value(cfg, 'p50'):.1f}s\",\n", + " \"p90\": f\"{RACE.value(cfg, 'p90'):.1f}s\",\n", + " \"$ / task\": f\"${RACE.value(cfg, 'usd'):.4f}\",\n", + " }\n", + " for cfg in RACE.settings\n", + "]\n", + "display(table(rows))" + ] + }, + { + "cell_type": "markdown", + "id": "1215-isolate", + "metadata": {}, + "source": [ + "25 of the 32 settings cleared the 95% bar, but no single setting was fastest on every measure. Let's now isolate each product's measure, p50 TTLT for the chat agent and p90 TTFT for the phone line, to see which setting fits each. The fastest setting that meets the quality bar wins." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "1220-choose", + "metadata": {}, + "outputs": [], + "source": [ + "@dataclass(frozen=True)\n", + "class Bounds:\n", + " \"\"\"What a product fixes before it looks at any result\"\"\"\n", + "\n", + " bar: float # the share of tasks it needs right\n", + " metric: str # the wait its users feel: \"p50\", \"p90\", \"first token p50\", or \"first token p90\"\n", + "\n", + " def outside(self, cfg):\n", + " \"\"\"Why the setting is out, in words. Empty if it meets the bar\"\"\"\n", + " return \"under the bar\" if RACE.value(cfg, \"correct\") < self.bar else \"\"\n", + "\n", + "\n", + "PRODUCTS = {name: Bounds(bar=0.95, metric=metric) for name, metric in MEASURES.items()}\n", + "SETTINGS = list(RACE.settings)\n", + "\n", + "\n", + "def report(name, shown=8):\n", + " \"\"\"One product: the settings that meet its bar, fastest first at its metric, and the chart\"\"\"\n", + " bounds = PRODUCTS[name]\n", + " print(f\"{name}: quality bar {bounds.bar:.0%}, ranked by {in_words(bounds.metric)}\")\n", + " inside = [cfg for cfg in SETTINGS if not bounds.outside(cfg)]\n", + " inside.sort(key=lambda cfg: RACE.value(cfg, bounds.metric))\n", + " pick = inside[0]\n", + " rows = []\n", + " for cfg in inside[:shown]:\n", + " tied = cfg != pick and RACE.versus(cfg, pick, bounds.metric).verdict == \"not significant\"\n", + " rows.append(rank_row(RACE, cfg, bounds, \"\" if cfg == pick else \"yes\" if tied else \"no\"))\n", + " display(table(rows))\n", + " title = f\"{name}: every setting, by {in_words(bounds.metric)}\"\n", + " frontier_chart(RACE, SETTINGS, bounds, pick, title)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "1224-chat-agent", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Chat agent: quality bar 95%, ranked by p50 seconds per task\n" + ] + }, + { + "data": { + "text/html": [ + "
settingcorrect (hardest level)p50p90$ / tasktied with the fastest
Opus 5.5 · low · fast mode + prefetch + bigger pages96.9% (90.3%)2.3s5.1s$0.0557
Opus 5.5 · low · fast mode + prefetch97.7% (90.3%)2.4s5.7s$0.0591yes
Opus 5.5 · medium · fast mode + prefetch + bigger pages97.9% (94.4%)2.4s5.2s$0.0641yes
Opus 5.5 · medium · fast mode + prefetch99.0% (96.3%)2.6s5.9s$0.0664no
Opus 5.5 · high · fast mode + prefetch + bigger pages99.4% (98.1%)2.7s5.5s$0.0678no
Opus 5.5 · low · fast mode + bigger pages97.5% (90.7%)2.8s5.3s$0.0653no
Opus 5.5 · high · fast mode + prefetch98.1% (90.4%)2.8s6.1s$0.0712no
Opus 5.5 · low · fast mode98.8% (94.4%)2.9s6.0s$0.0689no
" + ], + "text/plain": [ + "setting correct (hardest level) p50 p90 $ / task tied with the fastest\n", + "Opus 5.5 · low · fast mode + prefetch + bigger pages 96.9% (90.3%) 2.3s 5.1s $0.0557\n", + "Opus 5.5 · low · fast mode + prefetch 97.7% (90.3%) 2.4s 5.7s $0.0591 yes\n", + "Opus 5.5 · medium · fast mode + prefetch + bigger pages 97.9% (94.4%) 2.4s 5.2s $0.0641 yes\n", + "Opus 5.5 · medium · fast mode + prefetch 99.0% (96.3%) 2.6s 5.9s $0.0664 no\n", + "Opus 5.5 · high · fast mode + prefetch + bigger pages 99.4% (98.1%) 2.7s 5.5s $0.0678 no\n", + "Opus 5.5 · low · fast mode + bigger pages 97.5% (90.7%) 2.8s 5.3s $0.0653 no\n", + "Opus 5.5 · high · fast mode + prefetch 98.1% (90.4%) 2.8s 6.1s $0.0712 no\n", + "Opus 5.5 · low · fast mode 98.8% (94.4%) 2.9s 6.0s $0.0689 no" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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F38Jd+7cxfTp05EjR/YE54jUz+rS5U2VdSSrYMpKnSEhIRg0aOALf52lTc+eH6Fnz15qlciKFSuqqYpSq+yff/5W9cTefLMLPvjgA9VvycBbuHCh+vwZNmwYbCH7koBcjx7vqBVjJRgnYxIdHW3TcSXndUnpzxhh6v1gzeeiLccpWYZS3+/NN99E69Zt1Cqjya2nRkREREREacdOqvzzBUg+mbqzYcMGNVXn7t27KiOhVKnSeOutruqiSYILnTq9ri5o9TNvZNqOZOlIBpr+BeWCBQtw//4D5M+fH++8844KRHTq9Jouu0QyI+QxUlNKsiHmzp2jMqdMsWZ/so9Zs2arGj0SWHn11bbYsuVvlSkkmRL6ZMqpZNrcuXNHHZtceHbs2EFNi7LlOM0dw+TJP+PIkSMWi/xb6otG9v32291V3+bNm6subG3Zj7lj0icZJbdu3cLhw4dMTpcztnXrNlVQ/c6d2yoI07nz63jllVdsOjZz42fufsl8+eSTT9CkSWObXidrzw3Zn2Q1rV5tPqilPe9nn32mgiVS50mmv8m52L59+2SPrfQ1T568aqqcv/+9RPcvReV//fU3lS0k2UOyqIBksklQ1dihQ4fUVLv79++rGl4S0LEmyy0lXmchny1r1qxRxebLli2HPn16685jCWZJrTV5LgniSTbcRx99iAIFChiMuTWvtWRgSUBK7ndxiXutZfrr1atXMX78eJuOK6mvS0q8H/WZez9Y87mY2HGa6ofUgBswYAAcHZ1UkNXahV+IiIiIiCh9YbCMdNPS9At7y0WlZHm88UYXVRyfzJMsHplqKytG9unTJ0ueGxL4kGlzMmWyadMmaTa2WlDml19+QYcOpoNvlPr4uhARERERUUbCaZikyFQ3qdFTt25dhIaGqCyaiIhItfogmSZ1ow4cOKhWaZTpie+++26WPTckm7J58xYpFijLKmNLRERERERE6U/SlxOjTGXQoEFq+pYUEo9b9a2JKvRtbUH1rOjevXuqzpGzsxNWrlyRoN5WVjo3ZBqbTG9L67F1cHBAgwYN4Ovrk2J9oeTj60JERERERBkJp2ESERERERERERHFY2YZERERERERERFRPAbLiIiIiIiIiIiI4jFYRkREREREREREFI/BsmSIjY1FVFSU+k5ERERERERERBkfg2XJEB0djYMHdqjvRERERERERESU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vAKmOYmtjElERESpECyrW68eYmKisWLFCqxfv07d5+eXDz179lLbiIiIiIgoZbLK7GCHWDNTMPVJO2lf3+clroxJRESU2sEyUb9BQ/UVFham/jF2cXFJTj+IiIiIiEhPREw07oQGWxUoE9Lubthj9TgXhyT/mk9ERJTlJftfUUdHR/VFREREREQpRwJea+v3RED4M6sfk9slOwNlREREyZSkKFdUVBRWrlyB7du2IiAgAH8uW6HunztnNtq2fRV5/fyS2y8iIiIioiwvn5un+iIiIqJ0vhrmX6tWYt9/e9G9xzsG90ux/+XLl6VU34iIiIiIiIiIiNJ/sGzHju3o91l/1KnzisH95cqWw+HDh1Oqb0REREREREREROk/WPbo0SP45Y2bainF/XU7c3BAREREyvWOiIiIiIiIiIgovQfL/Pzy4dz5c/G3ngfLdu/ehcKFC6dU34iIiIiIiIiIiNJ/gf+OHV/DlJ9/RqdOndTtffv+w7Fjx7Bj+zZ8/vmAlO4jERERERERERFR+g2W1a1XTyWUrVyxHLGxMfjxh+9VttknfT9FzVq1Ur6XRERERERERERE6TVYduHCBdStW099RYSHIyY2Fq6urinfOyIiIiIiIiIiovRes2zE8KG6n51dXBgoIyIiIiIiIiKirBssy507N/zv3k353hAREREREREREWW0YNkbb3TBjBnTcO3qVURFRqZ8r4iIiIiIiIiIiNKAXVRUZKytD3qjc9wqmOb8uWwFsoKoqCgcPLADNWo2hKNjksq/ERERERERERFROpKkCM+w4SNSvidEREREREREREQZMVh25fJldOj4Wsr3hoiIiIiIiIiIKKPVLPvzz6WIjo5O+d4QERERERERERFltGBZ4cJFcOHC+ZTvDRERERERERERUUabhvlynTr4adIktGvfHgUKFEhQ3L5cufLISk6ePAE7u+dxRy8vLxQpUgRhYWE4d+5cgvaVK1dW3y9evIhnz54ZbCtUqDBy5vTGw4cPcevWLYNt7u7ueOmll1RW38mTJxPst1y5cnBycsKVK1fx+HGwwbZ8+fLB19cXgYFBuH79msE2Nzc3lCpVSv18/PhxxMYarvkg26TNjRs38OjRI4Ntsk/Z95MnT3D58mWDbdIX6ZM4ffo0Io1WTg0OfozKlSupMbh//77Btpw5c6JQoUIIDQ3F+fOGgVk7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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "report(\"Chat agent\")" + ] + }, + { + "cell_type": "markdown", + "id": "1225-chat-agent", + "metadata": {}, + "source": [ + "**The chat agent**\n", + "\n", + "- Our pick: Opus 5.5 at `low` with fast mode, prefetch, and bigger pages, with a p50 TTLT of 2.3 seconds at 96.9% accuracy and $0.056 per task.\n", + "- If cost is a constraint: Sonnet 5.5 at `medium` with prefetch costs about a third as much, but it gives up about 1.6 seconds at p50 with 97.1% accuracy.\n", + "- Across models, most of the p50 speed gain came from prefetch. On Opus 5.5 at `low` with fast mode, prefetch cut p50 by about half a second by saving the agent's first lookup. On a task of only a few calls that's a large share of the wait." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "1222-phone-line", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Phone line: quality bar 95%, ranked by p90 seconds to the first visible token\n" + ] + }, + { + "data": { + "text/html": [ + "
settingcorrect (hardest level)first token p90p50p90$ / tasktied with the fastest
Opus 5.5 · low · fast mode98.8% (94.4%)0.65s2.9s6.0s$0.0689
Opus 5.5 · low · fast mode + bigger pages97.5% (90.7%)0.65s2.8s5.3s$0.0653yes
Sonnet 5.5 · medium + bigger pages95.9% (92.6%)0.65s4.4s11.1s$0.0175yes
Sonnet 5.5 · high + bigger pages97.7% (98.1%)0.69s5.0s13.2s$0.0193yes
Opus 5.5 · medium · fast mode + bigger pages98.4% (96.3%)0.70s3.3s5.9s$0.0729yes
Sonnet 5.5 · high97.9% (98.1%)0.71s5.4s13.2s$0.0205no
Opus 5.5 · high · fast mode + bigger pages98.7% (94.4%)0.72s3.6s6.4s$0.0776yes
Opus 5.5 · high · fast mode100.0% (100.0%)0.73s3.7s7.1s$0.0804no
" + ], + "text/plain": [ + "setting correct (hardest level) first token p90 p50 p90 $ / task tied with the fastest\n", + "Opus 5.5 · low · fast mode 98.8% (94.4%) 0.65s 2.9s 6.0s $0.0689\n", + "Opus 5.5 · low · fast mode + bigger pages 97.5% (90.7%) 0.65s 2.8s 5.3s $0.0653 yes\n", + "Sonnet 5.5 · medium + bigger pages 95.9% (92.6%) 0.65s 4.4s 11.1s $0.0175 yes\n", + "Sonnet 5.5 · high + bigger pages 97.7% (98.1%) 0.69s 5.0s 13.2s $0.0193 yes\n", + "Opus 5.5 · medium · fast mode + bigger pages 98.4% (96.3%) 0.70s 3.3s 5.9s $0.0729 yes\n", + "Sonnet 5.5 · high 97.9% (98.1%) 0.71s 5.4s 13.2s $0.0205 no\n", + "Opus 5.5 · high · fast mode + bigger pages 98.7% (94.4%) 0.72s 3.6s 6.4s $0.0776 yes\n", + "Opus 5.5 · high · fast mode 100.0% (100.0%) 0.73s 3.7s 7.1s $0.0804 no" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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hZ23ValSxdalSxfzs07bt2+frUKFCrZvv52c5uspVqyY7bvvvk3xsdXP//HHH9t69+6d5v44s62///7b7NeuXTsd650+fcrm5+dnmzLlB6e3Y399derUsQUHH3Nsa8OG9Wb6unXrHNMOHTpoK1q0qO23335Ndd8nTJhgq1y5su38+VDHNN3XHTu2Z+g46XNPnTol2fZTm56Z9+zs2bO2MmXK2F577TXHtJkz/zTrduzYMcO/F/bn1c+0vib76+3QoYPttttuy/KxdXb7q1atNMv98ssvidatVq2amW5/b/R46eOE77vefvxxqpl++PChbH2f9fe/UqVKtvvvv98WERFupl29GmWbNGmS5d8Pui393ho8eJBjmh7rpO91eq8rtVtKn0tn9j8j27se34WdO99qe+aZZxJN69Wrl+3hhx9O8/vCmeOW2u9u0psz321Jf+edef6UviPS+11Kul5Wjm1mPyP2fdXf54sXL9geeOABW926dW27d+9ybGf48GFmHX3N+jgmJtr29NNP25o1a+bY7sCBA812Ev5f99VXX5n1Tpw4nu77wo1jwGeAzwCfAT4DfAZiUj0GNJewiF551JLPBQsWyKBBg2Tu3HkyZMgbiZbp06ePBAQEmJ/1is3NN3eQHTt2Oubr1dLz58/LsGHDHFeAWrVqJd26dZNvv/0uQ9v6448/TKdaH3wwylFJUaVKZXn00UcTlYhnllXP//zzz8l3332b5nM5s62bbmpnrr5NmfJf2/mff/5ZChYsKD179szwMXniiSfMlVG7Ro0amSvcX3/9tWPa5MnfmqYxt912rXQ6JXqVTSta9IqjXfv2N0mtWrUyvE/Z/Z7Nnj3LlCy/9tqrjmn62lq2bJml59XXoq9J6Wt85ZWXzdVKe8eomT22zm6/efPm5jOgzSUmTpwof/zxp9x//wOOUnCt0kh47+mZuMDLw+Pa45iY2Gx9n3///Q/TseCnn35irsZfe24PcxXX6u+H2bNnm+ocrQCw02OkxyojrysjMrL/GZHT34UpfV9Yedyc+W5LKrPPn97vUlJWH9uMfEa0iUr37j3MSBeLFv1tKn/sr33ixEly7733mNestIrhrbeGyu7du2X58hWObWgfGwkrObQZjFYzaTUGAADIPJpLWETLUrWk1svLy5Rfaidh7dq1S7SM/Q9hu0KFCpr2r3aHDh2W0qVLO9qD22nprZaDZ2Rb+/cfMKXdZ86cNTc7/cNT23tn1fV8fme2pX9E9u79oHzzzWRTWq4nilOn/mjKxrUMNqP7pO9hUn36PCnPPz9QRox412xTy3OffPKJZCelCek+aTtlHdlAO4zTE3bdpxtuaGz5ccrqe3bkyFFzomQ/XnbVqlUzQz9mlpYrJ3587WTg8OEjjjLszBzbjGxfgyxtlrFixT9y6dJF6dGjh+mX4YMPPhBf32tl9/byey2tTnistMmTsi+XXe/zoUOHzO9/0vcpO74f9Njoe20PM+xq1KguBw4cdPp1ZURG9j8jcvq7MKXvCyuPmzPfbUll9vmd+V1KyOpjm5HPyJtvvmlCJf2/N+Hy2oeDBhUaemjwn5A2DdK+GOzhQ9LPjgY3KuHnBwAAZBwhg4WjS2ib0azw8/N1nNAkpNOStidPT+HC1/74TNiW2E6vGusV65Ta/1rFyud3dlsPPvigjBr1gfz111+mLbGOZT9mzOgMbccupbbEd955p7zxxhD56aefJCCglISFhZn28mnRk4Bvv50sERERpmOxBQsWmuERJ078Uu6+++4cf5+S/gGubblTGtYxK5J+pu3bS/iZzsyxzcj29f3U7SXc5v333y9NmzYx1QKqVq2a5v7Agf1StWoVx3IasGg7dm0fnp3vs/aLoOvrldiU2p5b+f2g73VK29KAJSOvKyOs3P+MuB6/Y0m/L6w8biq977akMvv8zvwuZeexzchn5M03h5iKp4cffsh8b9grKTQo0N8fDSX27NmbaJ2GDRua3zMAAJC9CBlykRYtWpiTvMWLl0iHDjebaVq6OW/efNMTfkZ07NhR3n9/lHzxxefJrkCFhYVn+4mrs8+vZal61UlLYrO6LS0p1uoRLSvWP8R1mLkmTZpkaDup9fCutEpFT1L1imLJkiWka9euUqZMmTSPg25Xr7LpSd0tt9xibtpjvZ4s6B/7zr42PWnQjgeTSm16ZrRo0dyU62/cuNFx3LSkXv9Yr1GjRqJlnXnf7ObMmWtK2u10WEg9YdCrk1k5thnZfsIOWJWWTWuHo5MmTXJM0w7ytOM67fyuc+fOjg4AZ82aZcq1s/t97tChg4wYMdI8X8IyePu+W/n9oMN56hXftWvXmu3aTyiXL1+eqKQ+vdeVmpQ+l1nZ/6x8znPiu9CZ45aR15Ted1tmnj+zv0tWHdusfkbKli1nhozWDix79rxdfv31FylevLipzrnxxpamgkMrlRLS58vIiBkAACBzCBlyEW0Pff/998mTTz4pr7462FzR/fbbb80f/9pTdkY0bdpUnn76aenevbvprV7LXrUN69Kly8TDw920Tc9Ozj6/M6NLZOS16FWtfv36m6tZegwzu53UPP74Y/LZZ5/Jvn37THvk9IwfP84Mk6Z9C5QrV9a0FV+/foM88cSTGdqnRo0ayvTp000psZeXt/kjWv+AT216ZmhJdffu3eThhx8x/YoUKVLEPL+eaCe9su7sqCBKh/Xr16+fOVHX0RM++eRTee+9kclKvTN6bDOy/YEDXzAnQVq5oO3LdZmHH35Y7rzzjkTb0rbl9913vwQFlTGjSmgTCx3mcfDgQdn+Pusyffs+JX379jM99jdo0MCUo2s79b///svS7wd7PxWPPPI/M0qBhhjjxo1LNsxfeq8rNSl9LrOy/yltLzd/Fzpz3DL6u5vWd1tmnj8rv6tWHFsrPiNaYaR9yWhV0m23dTOjimgzoI8//lh69OhpQtIOHTqKl1cBU/3x88/T5LfffpPKlVMfLQMAAGQdIYMFtG23Dg+WGi3H1mHGSpVK3P5TT3r06nFC+of+1KlTZdGixebkRss7x44dI2XLls3wtt59d7i50qRXZnWoPv3jS//oTHpilZRuPzAwKMXHVj9/rVq15cqV9Nu/Ovta9I/d9u2nmRNjHUYto9tJ7fXZlStXTtq0aSPHjx93tOtNi3asp++ldrS3cOECc/L622+/ms9MRl7bhAkTZOzYsWZINq22sA/3ltr0zL5n2vmiDu02d+5csx3tK2Hhwr9M1UJCZ8+GmKupabE/78CBA80Jy6+//mauIn799Vdy++23Z/nY2n3yycdy+vSZNLevv0P6ur7//ntzZVZLze3VCglpSbkO1all2FpVoX0UfPjhh+lWVVj1PuuV1/bt25thGbdt2yZ16tSVn3/+KVu+H776apI5CdSrwd7ePtK/fz/TTEWHLszI60pJap/L9PY/I9vz9/fP9u9C7ZRUP5cJ6RVyexiQ2vF25rildoxSk953W8LfeWeeP6XvCGd+V5P+/5DZY5vZz0jSY67VGhocvPzyy6aqQoNC/W5as2a16SxSX7e7u4fUrVtH5syZ7fhd1t9td/fE4an2d6HbTm14VgAA4Bw3HWLCyWWBfE+vqNWtW8+MwDBgwACXOx565S9hZ4D6x79erbz33vtMp3NKTz70RE5Pwjt16phjx1b3rXTpQPnuu+/kjjuShxYAAAAArj8qGQAnaLv4devWm1EPtBmBDtHmirS5gral1oqCyMgr5op+dHSMGenB7tSpU3LrrZ0tCxjyy7EFAAAA8oPkXegDSEbHgv/iiy9M214tv02tjXJeN3jwYNMBonY+eK1H+o6mc8CEzQW0bFlL7XP62KbXtAUAAADA9UdzCQAAAAAAYAkqGQAAAAAAgCUIGQAAAAAAgCUIGQAAAAAAgCUIGbLAZrNJbGysuQcAAAAAIL8jZMiCuLg4Wb9uqbkHAAAAACC/I2QAAAAAAACWIGQAAAAAAACWIGQAAAAAAACWIGQAAAAAAACWIGQAAAAAAFxX4WFhEh4enuu2ZacjCIaEnJXTp09LXhQdHS0nT5zIkef2zJFnBdIRFRUlf/zxh8yePUfCwiPE389XunfvJnfccYf4+Phw/AAAAJCnnTt3TuLiYiUgoJS4u1//a79XLl+Wc6GhiaYFBARIwYIFLVk+PTNnzRQPd3fp/dDDKc6PiIgQW3y8+Pn7Z3lbGRUfFydvv/2WCRmqVasuL738Soa3Ea6hh83m1P5nBw0Y3n9/pEz4clL+DBn27N4tJ06ekBtuaCL+KbwJsbGxsmvnTgmPCJcKFSpKpUqVMryMflC2bdsmNrFJgwYNxcPDI9H85cuXSdMmTaVQ4cLZ8AqREXPnzpX+A56V8LBQKVi2kbgVChDboWCZNaufDH71DZkwfox07dqVgwoAAIA8Z8uWzfL1V1/JhQsXxMurgJnWu/dD0v7mDtd1PzZv2SwTxo+XUqUCHNOeeLKP1KlT15Lls2rVqpVy9epVueOOO+V627d/v1y4ECHjxn8pbm5umdrGnNmzJCYmRh597HHJb3I0ZNi0caNMnfqDuLt7yNGjR+Stt99JFjJcvHhRhr3ztrmyXaFCBfML2a5dO/OBzsgyH338oZwPPS/6GZk/b5689vobjnmLFy+StWvWSLt2N12nV460AoYHez8kBSu1lTLdnpUC/hUd82LCjkr4qtHywIO95cepU+S2227jQAIAACDPOHTwoHz4wSh57LHHpWOnW8wJ7ObNm+SzTz8Rn4IFpWXLG03pv560+Pr6SmhoqDk/SniB9HxoqBTw8pKiRYs6yuK1KqJMmTKOZaKvXjVX0kuWLCnuSS6uJlSjRnV5c+jbTu9/Rpd3lu5/saJFxcvb2zGtVavWppIhIX3tRYsVM00ZzoWESJmyZZ3aVkZoxcbBgwdMhUZwcLAUK1bMHP+wsDBzLlmyZPLqjaTHOzIy0pyjashw7Ngx8fb2ktKlA5M9l/299vPzM69HX5v3v/utVRSFCxeRQoUKJVvv0sWLEh8fL8V8fZPNsx+j1Og58+XLl6VEiRLikiGDm7ubPD/wRSlcuLD07/dUisvoyaSWEX340cemTP7AgQPyxuuvyg1Nmkjjxjc4tcyxo0dl7549plREc6j+/fuZD07VqtXMh+GXGdNl2LB3r/OrR0ofeK1g0IChZNdR4uae+AtRAwedfm7eYOnbb4AsW7LA8UsIAAAA1+fl5S0BpYIkr/r999+kadNm0umWWx3T9Hyle4+e5pxEQwYt/T9x/LicOHFc4uLiJCrqqrzw4oumGlv99NOPUr5CBenZ83bzODj4mHzy8UcydtwE83jpksXy7beTpWjRYv/+fT3AVIynJD7eJmfOnDbLpnQym9Xl0xN8PFgGPv+sxMTEysWLF2TgCy869nXe3Dlm/7USQJtOjHr/PTl9+pRpWtKkSVPZunVLoqYAaW0rI3bv2S2zZ82SS5cuyueffSIdOnYygc6ff/xuXr+GGK1atZJ+/QeYkCil4+1VwEvWr1+vPTvIkSOHpWLFSvLc8wOTPZe+13quqsdU3+srV67Ic88NNJ+T8+dDzevW52nTpq0jXPj880/N+a4+d/nyFeSFF18yIYVWxugxOnXqpLi5uUvTpk2TBSETJ02U9evWSaFCBU1Q8sqgwRIU9F845RIhgz0k0IQuJZrOrFq1Su6+5x5HO/xq1apJ9eo1ZOU//5j1nVnmzNkz5uAVKHCtHKlcubJy5vQZEzJM/uZr80tdMuC/sh/kDO2DQZtIaAVD0oDBTqf7tXpGTk65R2bPmSvdunW57vsJAAAAZMbevXvk/gceTDa9YcNGMmP6NHOSqfbs2S3vvTfKXKlfsmSxjB0zWkaPGSdeXl7pPseMGTNk0KBXpU7duuaK9bp1a1NcrnChwqZJwPvvjZSQkBCpW7euPP3Mc+bKvRXLa0VAeEREogqLpA4fOiwj33vfXFVfsGC+TJ82LcVgYNrPP5mKjuHvjjDVDaNGvZfpbaW3bxpgxETHyPz58+Ttd4Y5ptur3vWYvv3WUNm4YYM0bdYsxeN9880dpEOHDk41l9BqiffeHyXFixeXbyd/Ix988L4MHfq22Z5u67tvv3WEDD9P+1nPiGTSpK/Fzd1dPv30Y5nyw/fyzLPPmWOk1S/Dhr9rzpHfGzki0fP89tuvpnLiy4mTzHnzzJl/yqSJE2XoW2+7Zp8MqQkNPSeRkVekXLlyiaaXK19eDh866PQy+sEPCzufYLuhUsy3mGzcuEHOnQuR5zoPlG3btpoPgSaE9jAiKX2z9Gan1ROwjnbyqH0wJGwikZIC/pWkUIXmsmjZGulwKyEDAABAfhHvZpPLVxOX0Oc2WlJfyCvljhz1SneRwkWSTS9atIhjvtJqB3tTAD1h/XHqVNO8XC+kpkdL9jWkqFipkqkY1/VT0qhxY3NTenL80Yej5PvvvjUnrFYsv2HjBnPia6+wSEnz5s0dZfsNGjSQn3/6MdV+LJ555rlrzUY8PKRr124yceKETG3L2X1LSvv4Ox8WZs49a9WqZQIjDRmcPd6p0f3WgEFpsLB9+zZzr+rWrWfOV7XKQV/75k2bpG/ffuL57/nqHbffKSNGvOs4Rk8//axZTm+3desmX02a6Hie1atXSY+et5vzZ5tNpF69+vLTj1NN34aenp75J2SIvBJp7rUtSkJFihSRK//Oc2aZ6tWqm+BgwoTxptdRValiJXnttcHyyiuDZfy4seaXVhOdWTNnmr4hUurg48Txw3L8+OFserXQUSS0k0dnFKzZTc74RMqCPZnriAUAAAB5j6dnvPiejJDczN1N5K6mvlLYO3nQ4O9fXELOhSSbfvbsWXOip30JqKRt6osVK2ra+Dvj5VcGyYL580wIoE0HtOK7UaNr4UBq9ORYq7sTnpRmdXldJq0qBpVw1DgPD0+JjY1LcTkNNYoWu3ZsVJF/j1NmtuXsviW0YcN6+XLCBPHwcDfNRC5duiSN/q3Kz8zxTn2/PRI/dnc3/U/YQwZtwpGwckR/vnLlspmv+5TwGBUrlri/hvDwCJn55x+mGYqdHgM9tloBkW9CBns5UFTktbDATh/b5zmzjHa+8fY7w2XhgvnmTXpn2LsybdrP0rp1G/Mmrl+/Tr78cpJZ/rnnnpFdu3aa1CipsuUqS1CZiokqGTZt/CcbXnn+pMNU6igSzriy8zcJquUvd9S/1hYNAAAArs/H20PKlsuZIQGt0KRpU1m8aJF07dI1UYeMf/210DSZsF+hDj52LNF5zdmzIVKqVGnzWM9fEp77aECRkLa1v/uee81t3759MnLEcJn87ffJLqImvYKt7f8TdmiYtElBessne61NmpqbFXSoTG1WoH0QqOPB/x2fzMjovk2dMkWeePJJ02eG+u7byeakPq3j7eHhIVejo8VKpUqVkqPHjkqlypXN4yNHj5iOKPW5dF7wsf+O0bFjRxOtW6ZMkNxxZy9p0aKlY1p2VDHk+pBBS080hTobkvgXR3+RAgMDnV5GaWcY9953v/l53969smPHDvngw49MaYt+aLU3V3szizOnT6cYMmgnIzkxhm1+0b17NzNMpY4ikVaTiZiwIxJ5cqvc+twI8fHO3Li8AAAAyJsdP+Zlve7sJRvWrzMl7t26dzcXOZcuXSq7d+2WESNGOpbbtWuX/PH7b1K7Th2ZM2e2VKlS2dE8vEbNmqYpgM7TvgO07D+hN4e8Ll1v6yZly5aVTRs3mE4LU6rSnjjxS6lcubLpz+7UyZPy048/yu133JFqk4L0ls9O2vmidvavJ/R61f7XX3/N9NCSmaHPu2f3tfPGI0eOyOLFi00zh7SOd8mSJWXRokVy6NAhKVy4UIqjS2TUrZ27mPde+8fw8PQwzVW6dO1q5uloJT/+OEUKFioocbFx8tuvvyRa984775LJk782o5EEBQbJ4SOHZd3aNfLGkKGSr0IGTfIaNmooq1aulI4dO5k3S4cO2blzh2N4SmeWSSg2Jka+/HKC9HnqKdOEQktMdIQJ7WtBAwQd5jKloUCQ/e644w4Z/OobZpjKlEaXULb4OAlfNUb8/EvIY489kaicCAAAAMjNtMx/5Mj3zagCv/36qzlhrlqtmrw/apQEBJRyLNe5c2e5cPGi/PD99+bktc8rfR3zWrdqLadOnZKff/pJAkoFyEMPPSILFsxzzNc+En7/7TeZN3euqUJ49bXXU9yX//3vUXMi+s+KFebE+OFHHpG2bdul2qQgveUzSjtyTHgBV6+oJ+xnz9fPT3yuXjU/d+16mzlWesx0vTt79TKl/85uK6O0SYRWBtjpiBE6qsc3X38tlatUMU0iLv9byZDa8W7Tpq0cOHhQvpww3ryHKY0ukXS/NcxIGEbovPLly4v7v4HKLbfcappQzJs315y/apOVzp2v9VHXpUtXU5lgP0b/e/QxU8lv17xFC/Ep6CMLFy6QsPPnpVKlytK//9OSHdxiY2NskkN0eA1N6fQNmjLlB+nRo6fp4KRy5SpSpUoVs8zx4GAZMuR10zFF9Ro1ZNnSJeYD/9bbwxylHc4sYzdjxnRzUJ/q28881uYTrw5+xZSVaD8Oa9eukc8/H+3UuKr6Jq5ft1SaNW+fLWUm+dG8efPkgQd7m2Es/Vo9m6iiQSsYNGCIPLLCdFLS9d/UDgAAAHAV33//nTmR7P3Qwzm9K7mGdrqYsHmJnmRv2rhR3hjyZo7uF3JhyKA9ci5ZvDjZdO1NVXvqtDsXEiJLly4xbYIqVKhgeuxMOgKEM8toaYiGGfffd78UKlzYMV07UdHOOjQ06NTpFqeHsyRkyB5z586Vvv0GyIWIcClYpqHpDNJ2JcQ0kdAKhgnjxxAwAAAAwCURMiR37NgxmT9vrhlGUpvJ67COjz/xhOljD7lPjoYMeR0hQ/Y5dHCvzJ4zV5YsWSYRFy6Kb7Gicuutt9BEAgAAAC5t1qyZpky+W7fuOb0rucqiRX/LPyuWS4ECXiZsaNO2bU7vElJByJAFhAzZ58TxIxJ1NfGIIdrJY9lylbLxWQEAAAAAWcFQCQAAAAAAwBKEDAAAAAAAwBKEDAAAAAAAwBKEDAAAAAAAwBKEDAAAAAAAwBKEDAAAAAAAwBKEDAAAAAAAwBKEDAAAAAAAwBKEDAAAAAAAwBKEDAAAAAAAwBKEDAAAAAAAwBKEDAAAAAAAwBKEDACQiy1ZslSat2xt7gEAAIDcjpABAHIpm80mw4a/K3t37zT3+hgAAADIzQgZACCXWrRosWzauEGKNnrQ3OtjAAAAIDcjZACAXEirFkaMfE8KBtUX/zYDzb0+ppoBAAAAuRkhAwDk5iqGZn3Ezc3N3FPNAAAAgNyOkAEAcnEVg0+Flmaa3lPNAAAAgNyOkAEAcnkVg6KaAQAAAHkBIQMA5PIqBjuqGQAAAJDbETIgX4qKipKff/5ZHnroYenWvae518c6HchtVQx2VDMAAAAgtyNkQL4zd+5cqVmrrvTt20/+3hQsm057m3t9rNPnzZuX07uIfCqtKgY7qhkAAACQmxEyIN8FDA/2fkii/etJmYd+kVK9JklAl5HmXh/r9Ace7G2WA3JTFYMd1QwAAADIzdxiY2NsOb0TeVVsbKysX7dUmjVvL56enjm9Oy7lxPEjEnU1MtE0H++CUrZcpUxvU5tCaKWCBgklu44SN3ePZMvY4uPk3LzB4hW2Q/bu2Sk+Pj6Zfj4go1UMHTreIjsOnpbinUfq13NaS8v5Ba9LvaqBsnjRX6kGEgAAAMD1xpkx8o0//vhDwsNCpUy3Z1MMGJRO92v1jJycco/8+eefct999133/UT+FB0dLcdPnJTo8JNyetojTq1z4qTNrOft7Z3t+wcAAAA4g5AB+cbs2XOkYNlGUsC/YprLFfCvJAXLNJRZs2YTMuC60aBgyaKFcu7cOafXCQgIIGAAAABArkLIgHwjLDxC3AoFOLWsLqfLA9dTuXLlzA0AAADIqwgZkG/4+/mK7VCwU8varoSIv1+FbN8nZI/g4GAJDQ11evkSJUpI+fLleTsAAACALCJkyAe0zbaXl5fkd927d5NZs/pJTNjRNJtMxIQdkciTW6XH2wOu6/7BuoChadPmEhWVuOPQtPj4FJQNG9YRNAAAAABZRMiQDxAwXHPHHXfI4FffkPBVo9McXSJ81Rjx8y8ht99++3V/r5B1WsGgAUOJW4dJAf/K6S4fE3ZYQhcONetRzQAAAABkDSGDi4uJiZECBQo47vMzHY5ywvgx8sCDvc0wlX6tnk1U0aAVDBowRB5ZId/8OJXhK/M4DRi8S9XK6d0AAAAA8hVCBhenwcKMGTPknnvuyeldyRW6du0qP06dIv0HPCsnp9xtRpHQTh61DwZtIqEVDBow6HIAAAAAgIxxz+DyyGO0gmHIkDclNjY2p3cl17jttttk756dMnHil9KpSQW5ISja3OtjnU7AAAAAAACZQyWDC4uLi5N//lkpp0+fNvdt27YRD4/k/RDk16YT9913n7kBAAAAAKxBJYMLc3Nzk7lz55qf9V4fAwAAAACQXQgZXJi7u7vMnz/f/Kz3+jgv+OCDD6RuvcYyadI3Ob0rAAAAAIAMyBtnncgwm80m+/btk2PHjpnHR48elX379ueJgGHEiJHiXa6ZjB8/iaABAAAAcEH/rFghixf9naP7sGHDehn9xefy7beTJS86e+aMTBg/TnIb+mRwUdrR46xZsxJNmz17ljz77LO5dihLe8Dg27Kf+DV7QsLXfy3jx08w8/r0eTyndw8AAACwpN+0FcuXyY6dOyUuNlaqVa8uHTt2uu7Dp+/ZvVtmzvoz0bS77rpbqlatZsny6Tl+PFiioqIkp5w7d07Gjhkt//vfo1IyICBT21i+bKk57+rQsZPkhCtXrsiWLZsltyFkyCOio6PFy8srQ+vMnDkz0eM///zThAwZcfXqVfH29pbrHTAo+709aHj2maezfT8AAACA7Bz57d3hw+TixQvSqdMt4uXtLSuWL5e//1oo7wx7V4oVK3bdDn7o+VAJOXtW7rn3v47QS5Qoadnyud2xo0elfPkK0v7mDpneRnBwsHlPkRghQx6hAYOmnmFhYfL88wPNBzotupy9qYTdli1b5YYbmoi/v3+a61aoUEE+++xTs1xOBQx2CYMGT48C8u6Ikdm+P3ANMWGHLV0OAAAgq2bNmikhIWflk08+E5+CBc20Djd3kHfeeVt++P47efqZZ2XpksXi5u5uLvZp8+dyZctK9+49xPPfauS5c+dIQECANGvW3DzWkeT+/ON36duvv3l84cIFmTd3jpw5c0YqVa4sXbvelmols4YazZu3cHr/M7p8RuzauVNWrVop8fHx0qJlS2nYsJE5BqNHfy4DB74onp6esm7dWtPMYuALL5r+5nT5y5cvyy233Jrh55oxY7qcPXtGPvjgfWnZoqUUKlxYFi9eJG7iZo5vx06dTAiR2jE9cuSw2R/d37MhZ6VMmbLy0EMPJ3sufT9t/1403r9vn5QODJQ77rhTtm/bJitX/iO+vr7Sq9ddUqRo0TSPhd3GjRtk7Zo14ufvL3Xr1k0xPFm6dIlcvHhRGjZqJG3atJXrjZAhD9HhJ/38/GTcuLHy2GOPyaJFizO8DQ0ekoYPCXXs2FHGjh1jwoXQc2ckJiZastP48RNl9JhxKQYMdvbpulwxXz8ZNGhQtu4T8rYSJUqIj09BCV041Ol1dHldDwAAIDutXrVSbrm1syNgUO4eHtKjR0/5/PPPpH//AXIsOFgW/f23ObmsV6+e/LVwoRw+fFheePEls/zhQ4dMib7d5cuXZNu2rY7HX3z+mRQpWsSEEEePHJHvv/tWnniyT4r7c+rUKfn8s0+laLFi0qpVa6lVq1aa+5/R5Z21Yf16GTt2tPS6624TJuhreOzxJ8wJcvCxYDlw4IB5rn/+WSGbN2+WI0eOSJUqVWT58mUmIMgoPdGvW6+eRG+6Ku3b3yxlgsqYEEd/1r7t9LgNfXOIfPzxp1K8RIkUj6nua/kKFcx7oesVKVIkxec6FhxsKlW0SUyDBg3kt99+la1btkjRokXlxlatZPWqVeb8a/Crr6V7LNauXSMTxo+Xe+6911yAHjd2rCQcQHDPnj3y4QejpFu3blKhYkUTPoWGhsrtt98h1xMhQx6jHzT9AP/yyy/y3nvvy4cffmh+EbJKh7d85ZVX5LXXXpUrVy7JqVNHTXKWnXT0CO3cMa2Awc4+XyseFEEDUlO+fHnZsGGd+UJ1lgYMuh4AAEB2Onv2rAQFBSWbHlQmSK5ejZKICxfM47Jly8qAAdeaCjdufIMM6N/XrFuqVKl0n+PEiePyxhtvSrny5aV16zZy5fLlFJerXau2PPrY4+Zvfj1pH/HucBNytGrd2pLl9Wr8ihXLHRUWafn991/lvvsfkC5duprHhQoVkl9/+cWcWNeuU0d27dxhQgatBNAKg127dkqlSpVk75498thjj2f4+fVvv2pVq8mB/fsTVWYEBgaa+xYtWprqhRX/rDAn6CkdU618CAoMMs0l0qvuqFO3rvzv0cfMz3r8fvjhB3n77XdMsFGrVm158YXnnToWM//8Q3o/9JBpamM3Z/Z//fBN+/knufuee0ylhapRvYa8+eYbhAxwrqJBvf76a9K8eXPp0+dJCQsLz/Sh8/f3k0mTvjJVDJsPnpMth+wnZwliMYstXbpcFi0+LiW7fSSFq9zk1DoaNBQoUU0++2WRHIr+ySR0QMp8/705J/icyJZz1/5TBwAAyAq9styhdhEp5J18ID9PzwKmCUBS9g4Q7c0atDNIOy2nL1WqtJw8ecKpkEH7TPj44w+lfoOGUr9+fWlyQ5MUl9Mr9M3/reRs2fJGcyHzjz9+TzU0yOjy50LPJaqwSMuJEyekRo2ajsc1a9aS06dPSXxcnNSpU0eWL1smLVueED8/f2napKnMnTfHNBXQzjJLlw7M8vOrqMhIWbR4kakaibxyxTx/Ro9pasqV++9illaBlC5d2tH8pVjRoqYphYYV+v6ndSx0XvUEn40aNWrInATPc/ToEUfAYtNGGjYxzSb0ppUT1wuVDHmYVh/cfHN7+eeflfLAAw/Itm3bMryNhg0bytQfp0pAQCnZdShYIi9dlprpf3dl2eCpX4hXYAOnAwY7XT7ywGL5ZeIIeaP/Xdm2fwAAAEBm/0b3KZDyxboqVSqbq+833dQ+0XSdpn+P20vuo5MEERpC+HhfG31C+yJIWMmsJ6gJdejQUdq2bScHDuw3zS4WLpgvbwxJvxmpVk+Eh4c5/TrTW75u3XryVN9+Tm1LwwKt5Ej4erVPOm1KUqdOXZk0caJs37HdVDXoibX207Bz506pXaeuJc+vxo0fK1GRUdKqVSspVKiwrFmz2hEIZfaY2iX9NCRs4mBnf0/TOhbe3jrvv/c76egcOl/7YShTpoxjWrubbrou/ewlRMjgAs0nAgNLy6JFf8vAgS/I1KlTnV63d+/epoPH2NhoOXP6mBR0i5GC16lD2ycf7GqaSnj6V0i3qURCOqzl5b1z5Y03XpfyJTI22gYAAACQk7p16yEffjhKWt54ozRo0NBM0/7Sfv/9N7nr7nsSde5nv/q8ffs2M1ShtrG3l/ofPnzIsezq1auTDavY7qb2Urt2HSlapKgMHvyKOYHV8CMh7bTwhsY3mCvqepVcqwUSDkeZtLlBessnpfvpbJ9Xuq+LFi0y9+rvv/9y/FyyZEnx9S0mc+fMkYcfecSMyKHVC9pXRY+ePS15fnXwwEF5+plnTKgRGxMjM2f+6WjaktoxLViwoGlWYaXaaRyL2rVrm04dNWhRS5csSbRuo0aN5Mzp06Z5hL7f+j6tWrUqw6MUZhUhg4sEDfoh1w4h582bJ+fPn093Hf2F0+WvXL4kYWGh4unhaW7Xiw5HqaNFaGeOypmgQQOGiDUTTMBAnwwAAADIaxo1biyP/O9R+fijD037fz35O3LkqHTt2lU6d+7iWE5Pol9/bbCULBkgBw8eMB3/adt8pZ0Maj9qb7z+mimxTzpy3K5du2T69GkSFFTGjIBw223dkgUM6tLFi/L8889KYGCQnDlz2lztHjT41VSbG6S3fFY88GBvGTliuLzyso4a4WE6s3z99SGO+Xriv2zZMtN/wbXHdUwHijrdKm3btZOPPvzABCfaPKFYMd90j6kGRcOHv2MqOspXqJji6BJWHov7H3hQhr3zlgwe9IrEx8eJr69fonV7937INOt47tmnzWdI+5K4uUNHud7cYmNjst5rYD6lPYmuX7dUmjVvb070c5oOW1mlSlWnOmzUMitNQHW0ipyU1vCVCREwAAAAwFVERkbKwQMHJC4+TipVqmz6XbD7/vvvxMPdXXr0vN0MRxgYFGSu5id06dIl87e8NrHQagct4084zKEOk3ny5EnTMWGp0qVT3Q8NDg4fOWyuzusw9lqSb6edaB8/Hpxou2ktn1HHjx83V9rtFRoamOgJvJ7LVK5U2VQs2J0+dUpOnzktjRo1duybjrLRtFmzTD+/Xpg9e+aM1Kp9LbiwV5VERIRLhQoVTb8MVyIjzSgWaR3Tc+fOSXDwMRO6pBR6BAcfM8NiaqeRKjw83PSvYV9Wj8GGjRukadNm5hwtvWOhfUccPHRQ/P38zbncvv37HMcl4bE9fz7UvI6cON8jZHCRkEE/iNOnz5ABAwY4vc6ECePl7rvvTnXc3NwSNBAwAAAAIL+whwy9LbgqDuSE5F2eIk/SoGD+/Pmpjh6REm1akdMBg9KmD9oEQptCaKCQEAEDAAAAAOQdhAwuQisZFi9enGiallVpEqrj2Op90jKrxYuXmGqM3CCloIGAAQAAAPnNzTffnGz0CSAvIWRwAXFxcWYYS22bZder152mV9pu3bqZx3qvj3W6nfZYq+vp+rktaDjzx9N08ggAAIB8p3z5Co72+0BeRMjgArRn0zlz5piftVrhhx9+kMmTJ0uxYsUcfUXovT7W6TrfXtWg66XU22xOBw1Xj69nFAkAAAAAyGPo+NFFOn6sX7+BNG3aRD799FMpUqRImvuj+61VDy+88IJs3Lgp0dA02dWx48iR78nrr7/G0JMAAAAA4MJyftxFZInNZpOQkBAZMWKE9OzZwwxzYh/6JDUJqxpmzpwlZ8+elVKlSmXryBE+5Zube3u1AgAAAADA9RAy5HGxsXEmILjttq7mcXoBg519OV1PQwftONLqkSaSDk2pHTkSNAAAAACA6yJkyOPi4mLFw8M90801dD2tftBbdgYMyn5P0AAAAAAAromQIY/z8fHJ8ja0qsHb21uyM2CwI2gAAAAAANdFyABLpRUw2BE0AAAAAIBrImTAdQ0Y7AgaAAAAAMD1EDLgugcMdgQNAAAAAOBa3GJjY2w5vRN5VWxsrKxft1SaNW+f6Y4XXYWfn794l2smpe8Ym+F1z/zxtFw9vl7Cw8OyZd8AAAAAANeHc+MdAul4/fXXJCp4nRmmMiN0eV1P1wcAAAAA5G35+/I7LDNo0KBEw1M602RCA4aINRPkjTded6wPIOOCg4MlNDTU6eVLlCgh5cuX51AjkfjzpyX+coTTR8W9sK+4Fw/kKAIAgEQIGZAjQQMBA2BdwNC0aXOJiop0eh0fn4KyYcM6ggYkChgiht0nEhvt/FHx9BLfodMIGgAAQCKEDLjuQQMBA2AdrWDQgKHErcOkgH/ldJePCTssoQuHmvWoZoCdqWDISMCgYqPNelQzAACAhAgZcF2DBgIGIHtowOBdqhaHFwAAADmKkAHXLWggYAAAAAAA10bIgOsSNFw9scmMIkEnjwAAAADguggZcF2ChpEj3yNgAAAAAAAXlydChp07d8jWrVvlyuXLUr1GDWnbpq24e3gkWmbP7t2yafMmuXzpkpQMCJC2bdtJyZIlHfPDw8Jk/vx5YrPZpHOXrlK8eHHHvOirV+X777+TBx/sLYUKF76ury2/BA0MUQkAAAAArs9dcrlpP/8kH4x6X9zd3aVMmTIye9ZM+eDDUSYssJs1a6YMHz5M4uPjpWLFinJg/355YeDzcvToETM/Pi5O3n57qFy8eFEuX74sb7/1psTGxjrWnzFjungWKEDAAOC6WrJkqTRv2drcAwAAAK4gV4cMly5elN9++00ee/wJuf/+B+S2bt3lrbfekZ07dsj69escy/21cIF06dJFHnroYbm1cxd5+ZVB4u/vJyuWLzfz9x/YLzExMdLnqb7yZJ+nzLQ9e3ab+yOHD8uaNWvM9gHgetGgdNjwd2Xv7p3mPmFwCgAAAORVubq5xLnQULHZ4qVChYqOaUWKFhV/f3/ZsGGDNG/ewkwLCAiQsPBwxzJXo6IkMjJSAkqVMo8vXLgg/v7/NY8oUaKEXIi4YCocvvxyvDzxxJPi4+NzXV8bRGwxVyV682KJ2bpcbFcixK2QrxRo2E68GncQtwLeHCK4tEWLFsumjRukaKMHZdPGH83jTp065vRuAQAAAK4bMgQFBYm3t49s2LBeqlSpYqYdO3ZMQkJCxM/vlGO5AU8/K5MmfilvvP6aCRwOHToot9zaWW7pdIuZX7pUaTl16qRER0eLu5ubHD9+QgIDA2XO3DkSVKasVKtWTaZPnyYx0dFya+fOEhBwLZxISptj6M0uLu6/JhfImOhtK+TKD8PFFnlRxM1dxBZv7mO2LpXIGZ9KoUfeFK/6bTmscElatTBi5HtSMKi++LcZKLFntpvHHTt2EDc3t5zePQAAAMA1QwZvb2/p26+ffDlhguzcsV2KFi0mR44clsqVq0hMTLRjub1798iBA/ulXbubpHRgoETHRMua1aukffubpVSpUlKhYkWpWauWDHnjdfMHfNWqVaVIkSIyb+4cee/9D+Tdd4dLhQoVTJXE0DeHyOefjxYv7+RX0k8cPyzHjx++zkfBNQOGy5MGi9irwzVgSHBvi7wklycOFukzSrwaEDTAdasYSvX8wnwnFW3WRzbNfC5L1QwxYYctXQ4AAADIDLfY2Jhc3xD4QkSEHDhwwFQi1K1XT8aM/txMf+31IWZanycfl7vvuVd69OjpWOfNIW+YESReePEl81ibRuzYsUNsYpN69erL+++NMCNQVKxUSYYPe0cmTvradC45eNDLcs+990nTps2cqmTYtPEfada8vXh65uq8Jlc1kYh4vYcJEv5LGVLiJm4Fi4jvyFk0nYDLVTF06HiL7D55VQLu+tqEDDot5NcnpHYZb1m86K8MVTMEBwdL06bNJSoq0ul1fHwKyoYN66R8+fKZfBVwNfHnT0vEsPtEYv8L8NPl6SW+Q6eJe/HA7Nw1AACQx+SJM+Nivr5yQ5Mm5mcNFfbu3Su333GneawjRmj/C0n/WNbKhIMHDzoe65CXDRo2ND8vW3atJ/d2N7WX7du3iZ+fnwkYlH/x4ibUSIkuY18OmaN9MJgmEumymeWiNy8R7+ZdONxw2SoGlZVqBv3u08AgNDTU6XW0XxoCBiSkQYEGBvGXU/7/LyXuhX0JGAAAQN4LGXbv3iXVqlWXAgUKmMc///yTeHh4SseOncxjrVYoVqyYbFi/Xho1amymRUVFmfCgTt16ybanAYIOi/n228Mc/TWcPXvWBBXeXl4SfCxYeva4/bq+xrwsct43EjXnK/Hp9qQU7Pp4ustrJ4+OPhjSY/poWEbIAJfsi8GnQstE8/SxTs9M3wwaGBAawIqggaoEAADg8iFDRHiEvPzSi1KxUkU5dfKUXLp0SV597TUTLCj9Q3zA08/I6C++ME0qSpUuJfv27pWiRYumOCzlt99Olttu6yalSpc2j/W+abPmpr8G7QOiVKkAqV2nznV/nXk3YJhkfrbfpxc06CgSTgUMZuH4a8sDLlzFYGdV3wwAAABATsoTfTKEh4XJnr17pHDhwlKrVm1HVUNCVy5flgMHD8ili5ekZECAGTEiadMGbWqhHUK2adPWNJ+w034Wdu3cKbGxsVKvXj3xTGH7KdHl169bmi/7ZEgYMCTk061PmkHDpUmvScy25U5XMhRo0E6K9Hkvq7uLDNJ2/pTfZ39fDCktk9m+GQAAAIDcIE+cGfv5+0vLljemuUyhwoWlQYNrfS6kxsvLy/TDkJSGEfXq18/yfub3gMGZioYCDduZYSqdYouXAg1vyvyOIlPoSPD6VzHYUc0AAACAvC5PhAzIGwGDM0GDV+MOEjnjU6dHl/BqfHOW9xkZoxUMOlJBiVuHSQH/yk4NiRi6cKhZj34B0u6LwcuvnLgX9JOrZ/ekejx1vi6Xmb4ZAAAAgJxGyABLA4b0gga3At5S6JE35fLEwSI2t1SCBjfzT5fT5ZEzNGDwLlWLw28Bbap1/MRJiQ4/KaenPeLUOidO2sx62lcMAAAAkFcQMsDygCG9oMGrfluRPqPkyg/Drw1naR9t4t97rWDQgMEsB7gADQqWLFoo586dc3qdgIAAAgYAAADkOYQMyJaAId2goUFbKTBylkRvXmKGqdRRJNwK+Zo+GLSJBBUMcDXlypUzNwAAAMCVJR5+AS7vgw8+ED8/f3PvrKg5X2XpOVNbX4ME7+ZdzOgRRZ8fZ+71MQEDAAAAAORNhAz5iAYLI0aMFO9yzcy9s0GDT7cns/S8WV0fAAAAAJA30FwinwUMvi37iV+zJyR8/dfmsRo0aFCa69qbOmSmyYRPtz6pDmcJAAAAAHAthAz5MGBQ9vvsDBoIGAAAAAAgf6G5RD4MGOz0sU53tumEBg0aHDiDgAEAkJKYPesk4t0HzD0AAHA9VDLk04DBLjsqGggYAAApsdlsEjlzgsSfPmLuPWs2Ezc3Nw4WAAAuhJAhHwcM2RE0EDC4jpiww5YuBwCxu9dK3LHd5kDovT4uUKclBwYAABdCyJDPAwYrgwYCBtdQokQJ8fEpKKELhzq9ji6v6wFAmlUMsyeKuLmL2OLNvT72rN2CagYAAFyIW2xsjC2ndyKvio2NlfXrlkqz5u3F0zP35DV+fv5mmMrSd4zN8Lpn/nharh5fL+HhYU4tHznvG4ma85UZppJRJFxHcHCwhIaGOr28Bgzly5fP1n0CkLfF7Fojl8a9kGx6kQGfUs0AAIALyT1nxrDM66+/ZioSdJhKZysZlC4fFbxO3njjdafX0WCBcMH1aGBAaAAg26oY7KhmAADA5RAyuCB7Uwd70wdnggYNGCLWTDABQ3pNJQAAyGxfDInY4umbAQAAF0PI4KIyEjQQMAAArnsVgx3VDAAAuBRChnweNBAwAABypIrBjmoGAABcCiFDPg4aCBgAADlaxWBHNQMAAC6DkCGfBg0EDACAHK9isKOaAQAAl0HIkA+DhqsnNjlGkaCTRwBA9lYxuOmD9FdwczPLe9ZuIW66DgAAyJMIGfIRe6AwcuR7BAwAgOwVGyPxYWecCxiUzSbx4WfMelLAi3cHAIA8yi02NsbJ//2RVGxsrKxft1SaNW8vnp7kNQAAJKQhQ/ylcKcPinsRf3H3L8VBBAAgD+PMGADymfjzpyX+coTTy7sX9hX34oHZuk9wTe7+pc0NAADkH4QMAJDPAoaIYfeJxEY7v5Knl/gOnUbQAAAAgHS5p78IAMBVmAqGjAQMKjY6Q5UPAAAAyL8IGQAAAAAAgCUIGQAAAAAAgCUIGQAAAAAAgCUIGQAAAAAAgCUIGQAAAAAAgCUIGQAAAAAAgCUIGQAAAAAAgCUIGQAAAAAAgCUIGQBkiyVLlkrzlq3NPQAAAID8gZABgOVsNpsMG/6u7N2909zrYwAAAACuj5ABgOUWLVosmzZukKKNHjT3+hi5g3thXxFPr4yt5Ol1bT0AAAAgHW6xsTFcYsyk2NhYWb9uqTRr3l48PT0zuxnApWjVQoeOt8juk1cl4K6vJeTXJ6R2GW9ZvOgvcXNzy+ndg4jEnz8t8ZcjnD4WGjC4Fw/k2AEAACBdnBkDyJYqhlI9vzChQtFmfWTTzOfM9E6dOnK0cwENDAgNAAAAkB1oLgHA0iqGESPfk4JB9cWnQkszTe/1sU6nbwYAAADAtREyALC+L4ZmfRxNIxzVDPTNAAAAALg8QgYA2VbFYEc1AwAAAJA/EDIAyLYqBjuqGQAAAID8gZABQLZWMdhRzQAAAAC4PkIGANlaxWBHNQMAAADg+hjCEoAlVQxefuXEvaCfXD27J9Vldb4up8t37Ngh1UACAAAAQN5EyAAgS6Kjo+X4iZMSHX5STk97xKl1Tpy0mfW8vb05+gAAAIALIWQAkCUaFCxZtFDOnTvn9DoBAQEEDAAAAIALImQAkGXlypUzNwAAAAD5Gx0/AgAAAAAASxAyAAAAAAAASxAyAAAAAAAAS9AnAwAAAFzKiSvhcj76itPLF/cqJGUL+WXrPgFAfkHIAAAAAJcKGG5eMlquxsc6vY63u6csuflZggYAsADNJQAAAOAytIIhIwGD0uUzUvkAAEgdIQMAAAAAALAEIQMAAAAAALAEIQMAAAAAALAEIQMAAAAAALAEIQMAAAAAALAEQ1gC10FUXIzMPblLFpzeLeExkeJXoKB0Dqwtt5WpIz4eBXgPAAAAALgEQgYgm/11eo+8tOV3iYiJEndxk3ixmfv5p3fL2zvnyieNekmnwJq8DwAAAADyPJpLANkcMPRZ/5NciIkyjzVgSHiv059c/6NZDgAAAADyOkIGIBubSGgFg7oWKSRnn67L6fIAAAAAkJcRMgDZRPtg0CYSqQUMdjpfl5t7ahfvBQAAAIA8jZAByCbayaP2veDcL6KbLDi1m/cCAIAsKu5VSLzdM9btmJebh1kPAJB1dPwIZBMdRcLe90J6dDldHgAAZE3ZQn6y5OZn5Xz0Fce0jWHB8taOuamu837DnmY9AEDWUckAZBMdptK5OoZrlQy6PAAAyDoNDOr7lTG3er5B8mvwFvFI5X9lnf7t4bViszl3YQAAkDZCBiAbOfvnilYydA6qzXsBAIDFlocclG0RJyUulf+VdbrO1+UAAFlHyABkg8/3LZX5p53rY0Gvq/gW8JHbgurwXgAAYCGtTvhoz6JUqxjsdL4uRzUDAGQdIQOQDQHDJ3uXOL28Xlf5pFEv8fEowHsBAMB1rGKwo5oBAPJRx4/R0dEyd+4c2bpli1y5clmqV68h99x7n/j6+iZa7tKlSzJz5p+yc8d28fLylk633CKtW7dxzN+zZ4/MmP6zaHO7e+69V2rX/u+qcXhYmHzyycfy6quvSaHCha/r60P+Dhjsdl44JZ0Ca2bLPgEAkJ+rGNzETWxONGDU5XT5dgFVxc3N2V6VAAB5rpLh888+lSWLF0mPHj3lyT5PyeXLl+Xtt9404YPdpYsX5Y3XX5UD+/fLAw/2lgd795ZNGzeaYEFFRUbKhx+8L23btpOb2reXD0a9b7Zj9/XXX0mr1q0JGJAjAYPS9XR9AABgjej4ODkZGeFUwKB0uVNRF8x6AAAXrWQ4d+6crF+/Tl597XW54YYmZtrTz1SRp/o8IcuXLZVOt9xqpk2b9rPExsaaSgQvb28zTSse4uKu/Sex/8B+8fPzl/Y3dzCP586ZLfv27ZXGjW8w2w8LC5Nbb+2cY68TruHTTAYMCdd/vkZ7y/YHAID8zNvDU2a16yuhV/+7sJSekt6FzXoAgMzL1d+ikZHXxjcuWrSoY5qnp6cULFhItm/f7ggZVq1aKbfccqsjYLDz8PAw91r14J1gno9PQbl69apcuXJFvvt2srz66uvi7p7rizosETnvG4ma85X4dHtSCnZ9PKd3x6W8UPPmTFcy2NcHAADWKVPQ19wAANdPrg4ZgoLKSIkSJWXO7Nny9DPPSoECBWTlyn8kJOSs+Pv7m2UuRETIxYsXpWRAgEwYP04OHTpk5mmziFatWptlKlSoIMHBwXI+NFTc3N3lyJHDUqliJZk65Qdp1+4miYmNkRHvDpeYmBi5s1cvadiwUYr7Ex8fb252cXGxkvcChknmZ/s9QYN17FUImQkaXqx5M1UMAAAgXztxJVzOR1+7yOiM4l6FpGwhv2zdJwAuFjJo1cLLr7wi48eNlScef1QKFiwoAQGlTDMHDRaUNpNQU374Xu697365tXMXObB/n4wZ/YXpd0ErHHSd22+/XV544XnTrc9tt3WT8PBw2bNntwx/d6S8MPB5ueuuu6RYMV/55OOP5YvRY5J1LKlOHD8sx48flrwoYcBgR9CQPUHD7ojTMs/J4StV16DaBAwAAEDye8Bw85LRcjXe+Yt43u6esuTmZwkagFwmV4cMqmrVavLRx5+aUEGbPZQoUULeGvqmuVdFihQRNzd3adqsuQkPVJUqVeTw4cPy919/mZBB3X3PvY75Xl5eMmjQy/JU3/5y8sQJ8fT0MOGEmjdvruzatVNuvLFVsn0pW66yBJWpmKiSYdPGfyQvBgx2BA3W++yGu2Tx/Ped+k9S/3P8rPFd2bAXAAAAeYdWMGQkYFC6vK5HNQOQu+SZjgi0XwYNFrQCYd++fdKocWMzXfthqFChvAkbki4fFRWVaJoOT6m3X3/9RerUqSu1atWSq9FXk/TX4GP6a0iJ9tug1RX2m0ce6BgorYDBTufrcrCGj0cBGdfkXqeW1eV0eQAAAABwBbk+ZNBRJE6fPm1+1uYP48eNkbJly5i+FOw6d+kqq1etlLNnzpjH50JCZMWKFdL4hhuSbe94cLCsWLFcHuz9kHlcrlx5CQkJMc+h1RL79++TSpUqiytwJmCwI2iwVqfAmvJVswdMpUJKdPrXzR40ywEAAACAq8j1l+LLlisnH4x6TyIjo+TSpYtSr159GTJkqOkE0q5Tp1sk5OxZefnlF6Vw4SJy4cIFad2mjTz4wIOJtqWdNk6YMF7+9+hjUqhQITNN+1645977ZNArL5lKhZtv7iCVKlWS/BQw2NF0wlq3BNaSbV1elYGbf5V5p3Yn6oNBm0hQwQAAAADA1bjFxsbYJA/QkSF8ChZ0hAMpib56VcIjIqS4v794Jggh7GJjYiTkXIgZtSKpyMhIiYuLS9bsIi3a6eT6dUulWfP2pvlEXg4YEvLp1odRJyz2+b6l8uneJWaYSvsoFAAAALhme/hJ6b7iywwfjtlt+0p9v+R/2wPIObnnzDgdxf/t6DEt2j9DqVKlUp2vwUNKAYPSkStcRdScr7K8PkNbWkuDBcIFAAAAAK4u1/fJgIzz6fZkjq4PAAAAAMifCBlckFYhaJOHzKCpBAAAAADguoYM69atzdQ85O6ggYABAAAAAHDdQ4aPPvwgU/OQe4MGAgYAAAAAQK5qLnEhIiLN0R+QO4MGAgYAAAAAwHUfXWLEu8NT/FnZbDY5efKE1K5dx5Idg3XsI0WkNKwlAQMAAAByWnGvQuLt7ilX42OdXkeX1/UA5OGQoXyFCuZ+69Ytjp8dG/LwkBYtW0qbNm2t3UNkW9BAwAAAAIDcoGwhP1ly87NyPvpKoouYL275XQ5eOifxYhN3cZOqRUrKJ43uFDc3NxMw6HoA8nDI8Mgj/zP3xYoWlTvu7JVd+4RsDxq+MsNU2h8DAAAAOU0Dg4ShwbKzB2T/pRDHYw0a9HFYTKTcVKpaDu0lgPS4xcbG2NJdCimKjY2V9euWSrPm7cXTM0N5DQAAAIBUaBVDzxUTZWfEKYmT/05XPMRN6voGycy2T5lqBgAu0vHjqlUr5YvPP0s2XaetWb3aiv0CAAAAkE8tDzko2yJOJgoYlD7W6TofgAuFDDOmT5e77r472XSdNmPGdCv2CwAAAEA+rWL4aM8iU7WQEp2u83U5AC4SMpw9e0b8/PyTTff19ZPTp09bsV8AAAAA8qHUqhjsqGYAXDBkKFOmrKxduybZ9DVrVktQUKAV+wUAAAAgn0mvisGOagYg98pUb4W3336HjB8/ToKPHZPadeqIhoy7du+SvxYukP79n7Z+LwEAAADkmyqG9CSsZmCkCcAFQoY2bdtKfHyc/PrrrzJnzmwzLSiojPTt28/MAwAAAIDMVDG4iZvYUmkqkZAup8u3C6jKSBNALpLpcRfb3dTe3KKioswvtbe3t7V7BgAAACDfiI6Pk5OREU4FDEqXOxV1wazn7cFw8kBukeXfRk9PT3MDAAAAgMzSoGBWu74SevWy0+uU9C5MwADkMplKB2JjY+W3336VJYsXSWhoqEyf8auZ/tWkidK9ew8JDAqyej8BAAAAuLgyBX3NDUA+G13ij99/kzWrV8nDj/wv0XTtBPKXX2ZYtW8AAAAAAMDVQ4alS5fI8wNfkFatWieaXrdOXdm4caNV+wYAAAAAAFw9ZDh//rwEBV5rEqGdPjo25uEh0dHR1u0dAAAAAABw7ZBBh6vcs3fPv4/+CxlWrFguFStWtGrfAAAAAACAq3f8eOedvWT0F1/IXXfdZR6vWbNatmzZIkuXLJYXX3zZ6n0EAAAAAACuGjK0advWFDD89usvYrPFyycff2SqG5559jlp3qKF9XsJAAAAAABcM2TYt2+ftGnT1tyir16VeJtNfHx8rN87AAAAAADg2n0yDH3zDcfPXt7eBAwAAAAAACBzIUPJkiXl9KlTHD4AAAAAAJC1kOHee++T8ePHypHDhyU2JiYzmwAAAAAAAC7GLTY2xpbRle6959qoEqmZPuNXyQ9iY2Nl/bql0qx5e/H0zFT3FgAAAAAAuIxMnRkPeXOo9XsCAAAAAADytEyFDIcOHpQ77uxl/d4AAAAAAID81SfD9OnTJC4uzvq9AQAAAAAA+StkqFixkuzbt9f6vQEAAAAAAPmrucSNrVrJZ59+Kj1vv13KlSuXrNPDunXrSX6yffs2cXP7L6/x8/OTSpUqSVRUlOzZsyfZ8o0aNTL3+/fvl8uXLyeaV6FCRSle3F/OnTsnx48fTzSvaNGiUrVqVVNFsn379mTbrVu3rhQoUEAOHTosFy5EJJpXpkwZKVWqlISFhcvRo0cSzStYsKDUrFnT/Lx161ax2RL3BarzdJljx47J+fPnE83Tbeq2L168KAcPHkw0T/dF90nt3LlTYpKMRBIRcUEaNWpojsHZs2cTzStevLhUqFBBIiMjZe/exIGWm5ubNGzY0Pys83SZpCGYv7+f2ebChX9JlSqVpVChQmZesWK+5rHui+5TUvXr1xcPDw/zWvQ1JaSfdR2+9fz5MDl27GiieYULF5bq1aubn7ds2ZJsu7Vq1RIfHx85cuSIhIeHJ5oXGBhobhcuXJBDhw4lmuft7S21a9c2P+/YscN0NppQtWrVpEiRInLixAkJCQlJNK9EiRJSvnx5uXLliuzbty/RPHd3d2nQoIH5WT+j+llVHpfOi0fUJQkqU8Z83s6HhprPYkJFihSVMmXLmGN44ORZiStSPNF83a5u/8CBA3Lp0qVE83R/dL9CQ0MlODg4yXaLmNcTHx8v27ZtS3YM69SpI15eXnL48BGJiEh8DIOCgqR06dLm2OoxTkiPux5/pdvV7SdUo0YN8/nQ/dH9SiggIEDKli1rXoe+noT0e69evWvfdbt375arV68mml+lShUpVqyYnD592twS4jvCue8I/b7Tz+HJkyez7TtCt50Q3xFpf0fY6f9x+jk+c+aMnEoypLWvr59UrlxJoqOjZdeuXZIU3xF8R1j1dwTfEbnv7wi+I0Idf+cD+ZqOLpHRW687e6Z5y8w28+ItKirStmL5PFtAQElb4cKFHbfHHnvMzN+7d2+i6fabff327dsnmzd16hQzb/z4ccnm9ejRw8w7fz40xe2ePn3KzL/77ruSzfvss0/NvBkzZiSbd+ONNzr2yd/fP9n87du3mXn9+vVLNm/IkCFm3pIli5PNq169umO7dWtWtz1UL8j2fdcatpl31Db3ZUqVtC3+a4HZRtJ19bl0vUPfvGs707eJ7dWWFR3zdB/t29V9T7quvkadp6856Tw9NjpPj1VKx1CPrc7XY510nr4nOk/fo6Tz9L2071NK29XPgs7Tz0bSecOHDzPz5s+fn2xevXr1HNutUKFCsvmrVq008wYNeiXZvOeff97M27BhfbJ5gYGBju02adLk2vsV4GsL7nODLaRfU6dvuryul3Dbly9fMtvt3PnWZM/79ddfm3l6n3SeLq/zdP2UjuHRo0fM/AcffDDZvFGjRpl5M2f+mWyevj77a9XXnXS+Hh+dp8cr6Tw9rjpPj3PSefp+2Ler71PS+fp+6jx9f5PO4zsi+XeE/pz0OOn3is5L6ztCv5+SzuM7Inu+IxLe9HdN5+nvXtJ5+juq8/R3NqXfZb4j+I7IzN8RfEfk/r8j+I649ndETp+fcOMYxOaCY5CpISzT649BrwTnpyEsfQoWp5IhjSsQ0dtWyMXv3hb3q1fEJm7iJjZzf8P0vTL+lurS+KnX5LRvRXn11Vfl8cefkBo1qpurlMf++Eoq7JgvRb2ufZ7Cm/SQiMa3ZegqpabsH3/8seNKSHZdpdTXqvul90mrU/Sqgl4N0Kvwp06dlkuXLkrlypXNFVr71fKIiAhzxV2vQiSkVQS673qlPruvQHidOyZBf7wnGXXqjtckumQFx2OuUl5DJcM1XKV0rWonOyoZrqHaKWcrIqlk4DsiN1ZEUskAiGQqZEDikKFZ8/bJmozgGg0YLk8aLGI+ZYk/ao2n75Nx7crJjUGFpXCfUeLVoK1jXuS8b6T6wy/LNx3KS7NS15o6KJ9ufaRg18edPrxlypSVP//8Q5o1a5Ztb8ns2bPlueeeN39s6n9O+sfStGk/mz+cVM+et5v/sPQ/MLthw96RFi1amM9Qt27dTZig/zF98skn0qvXnWYZ/UOsc+cuMmvWTHOCkd1ig/fKxVGPZni9ooO/Fc/y1/64BAAAAJC/ZarjR6Up3pbNm2X27Fkye9ZM83PSZA95n17h0v4ftE26XkVbv369ma5XKVavXp2oHbpejd+wYYPj8eYN62XZh4Nk09krEhqV+OrDf2zm35Ufhsv6NavMNjRg2PTDaIm3iewJuyrrz16RQxeuyv7wq3Jg2jgz306fP+l+pESvkOhVvqRVD3pFUdfX15W07wG1bt06s65WJ2zevCVZHwMaDPTt20/efPNNWbt2jezYsV1KlQqQQYMGJ1quX7++smDBfMdNAwb1119/mWO5YcN6mTLlB/nggw8c6+g2XnzxhesSMAAAAACAFTJ1+V1Pxj4Y9b4pGddySxE3CQ09ZzotHDT4VVNSjrzvzz//lAEDnjbltHoyfdNNN8nChQtMuaOe1Hfp0lW2bdsqFStWdJSQPfLI/+Tw4WvlvF+MeFuObT8iMfE2OXghWrpWKCof3BhkmhUkZhNb5EW59577ZNLzD0uTI0vku73nJSouXqbuC5MiBdylXZnCUtDTXeYcvSB/FJlk1tKKhhkzZsioUR/I1q3Jy4/tJkz4UlasWCH+/v6mZHjChPHSvXt3M2/MmLGmvE1LMLVc+Pbbe8qYMWMc+3jHHXdKt27dzPraydzYsWMcJc9q69ZtJoB46KHejtLO++9/QPr06WMCDS0PVVrhsGnTZilTJihRaKDHVTtI0+fTsk97x4Pz5s0zgcsDDzxgyXsJAAAAALk2ZJj8zdfi61tMxo2bIMVNyCCmF/rx48eaea8kuYqLvEdPdp9++hn5/PPP5O677zYVDXfe2StD2xh9WwOJKRcuYouXiKtxcuf8I7Ig+KJ0qVAs+cJu7mKLiZLoNbNFAgvLqBvLyNyjF2V4i0BHc4nwq3Hy8ZYQ2Xk+SurOuRY0fPPNVHnkkYdN++HUnD59yoQh2qbuhx9+kAEDBkirVq3NKB5ffXVtO0pH3rjllltk1qxZ0rNnT8d0HalD19d2fEn5+vqaSgTt/0FHIVBnzpw2ocXhw4dN+7+6devIsmXLzUgXOqJIkyZNzPNqcwptxvHWW2/LzJkzZfHiJdKyZUsTSOi033//zTSZ0J7btb2fBhgAAAAA4HLNJXTIxr79BjgCBqU/6zSdh7xPmxDoCbQGDEo7tHnqqacytA3blQgJjYyW7aGRsi/iqtTx95GNIZGpLByvbXDS3J6ft4d0r1RMftwfZh5v/GG0aabz0EMPpbme7rcGDOrhhx+WAgW8ZP36dYkqc7QpxJ49u03Hj2vX/jdPPfHEEykGDEqH4LzhhhvkiSeelPnz55sQY/z4CWaeDt+m3nvvPdNEYunSJabJhk5/4YUXHZ1hffTRRzJlylQTVnz66Sfy2muvyTPPPG2Gfrvhhiby2GOPy803dzBBDwAAAAC4ZJ8MyUve4Ur0arqfn2+iaTomeloS9iatJ9L9f10rN/1xUF5dc0pGbTorm0KuyLnIxD2fZ9TDNfzlz8MX5HLMtaYUN5cpJH5b5qW5jjaTSEjDE319uo+PPvqYNGrUWJ577jl5++13TB8MISFn01w/IR2J4o8/fpfWrVvLxImTZPnyFTJ06FAzz17ZkHhbfvLkk0+a5hd2d955h0yfPs1UjWgfEToCxSOPPCIffviRjBs3VtatWyvlypWV33//3enjBAAAAAB5JmSoV7++TPxygoSHXbuirMLCwsy0+vWvDXmFvE37HTh06HCiodQ2bdqUaNg0rQ7Q991u//4Djp/1ZHvNsXOy9q7qMqdbFfmlSyVpWqpQkvEl0lbA3U3ikgyD1bBkQalSzMtUM8w8ckEeqO4nUXO+SnM72hdCwqoF7YNBhzjSfVy5cqWpYFixYrmpNtDmCkmeMl1a5fDmm0Pkt99+lUmTJsrGjRtMMwgdbUKDjKRDymmfFjpEZ1Lasebrr78hX3zxuaPJig6DqPQ+NDTxsF/InJg96yTi3QfMPQAAAIBc0CfD4489IR98MEr69+/7b8eP106IypevkKxXfeRNOvpBw4YNTUeOAwb0NyfGEyZcawZgr2Rp06aN6Tvg2WefNfN1+EW7gICScuFKlPx+PEoqettkzZnLstD0x1DU6X2oVMxLZh6+IG7iJgEFPaRKMW8z/aEa/vLG2lNSwsdT2pcpIj7dnkxzO9qRo45RX758Ofniiy+kRYvmpl8EHctbO1f8+edp5iT+n3/+kTlz5kiPHj0ydKxefvkVqVevrum4ccmSJTJ16lT588+ZZp721fDww4/I//73P9OBpgY1epzefffdZNsZMuRN07RDO5hUN954o3z88bUhLf/440/59tvJGdovpFxtEzlzgsSfPmLuPWs2oyoLAAAAyOlKhpIBAfL+qA9k8ODXpHOXrmaUAf1Zp+k8uIYZM6ZLo0aNZNKkr+TgwYOmv4CEdJQGrXgYN26cHDx4wJzM6xV8pQHFl19+KStspWXirlDx8XCX124oZaoQ7BqXLChFvTw0sZACTW/97/G/RrYIlCux8aazx9lHLjim96xUTDzc3OTeqn5SuMdTZpSJ1DRv3lwmTZok+/btNa+jefMWMm3atET7+Pfff5nwoWBBHxk27B2pXr1aovWLFk07GHnvvZFy8uQpGTt2nMTExJqgoXHjRmZeuXLlzHHSkTdGjx4tR44clh9//FGeeCLxPh88eEhiYqITTR8x4l3TvOLrr7+RIUPeMPuCrIndvVbiju02P+u9PgYAAABgHbfY2JgMFofDTsvg169bKs2atxdPz0wVheS5ziDvu+8+U7WQEdHbVsiVH4abYSp1FAnTyeO/924Fi0qhR94Ur/ptJXLeNxL176gRadHRJXrOPSxrvhgiNR55WVzN5/uWyqd7l8gLNW+W52u0v27PGxu8Vy6OejTD6xUd/K14lq8peaGK4eKHT0hc8F7HZ9CjfE0p+srXVDMAAAAAFsnUmbEOq7dq1Urp3j1xWfns2bOkdes2aXaUh/zHq0FbKTBylkRvXiIxW5eZUSfcCvlKgYY3iVfjm8WtwLVmEPaKhNSChug4m2w6d0XGbAuV7i0buWzA8MneJeZn+/31ChrcC/uKeHqJxF4bFcMpnl7X1stjVQyGLd5RzVCgTsuc3DUAAAAgf4cM33zzlbRt2y7ZdO3obvLkr+XFF13v5A8ixYoVk2bNMleyr0GCd/Mu5paWtIKGizFxpulEpVp15f3JP7t0wGB3PYMG9+KB4jt0msRfjnB+ncK+Zr080RfD7In/VdLYubmb6Z61W1DNAAAAAORUyLB92zYZMOCZZNPr16sv48eNtWK/kAvVrVtXfv31l2x/ntSCBu3ocdYXI9Lsg8GVAoacChryQmiQ5SoGO6oZAAAAgJzv+FGH7AsJOZtsuvaknx/6JkD20yDBp1ufRNP0cX4LGOx0vi6HLFYxpOTfagZdDgAAAEDWZCoRaNK0mUz88kt5fuALUqpUKTPt7JkzMnHil9K06bXRBeCabDFXJXrzYonZujxB3wrtxKtxB0ffCtZXNHxlhqnMrwGD3fXuo8HlqxjsqGYAAAAAcnZ0iUuXLsmId4fLoUOHpGTJEuYKYGjoealSpYq8MeRNKVKkiOQH+W10CWdHiYD1AUNCL17nUSfysmQjSqSGkSYAAACAnB3CMj4+XrZu3SKHDx0ScXOTypUrS8OGjcTdPVMtMPKk/BQyaMBwedJgEfNpSekj42b+Fe4zyowmgewJGOwIGpwTs2uNXBr3gtPHtciATxlpAgAAAMiJkAH5J2TQJhIRr/cQW+SlVAIGOzdxK1hEfEfOsrzphKupNOutNI9ketxE5EiPdyzcI1euYtijD9Jfwc1NPMrXkqKvfM1IEwAAAEAm5Z+yA2Sa9sFgmkike1psM8tFb878Ffr84oWaN+fo+vlCbIzEh51xLmBQNpvEh58x6wEAAADIHNe9/A7LaCePjj4Y0uPmLjFbl4l38y68A2mw96lAnwzZx62AlxQb9I3EXwp3eh33Iv5mPQAAAACZQ8iAdOkoEk4FDGbh+GvLI1uCBvpiyBh3/9LmBgAAACAPNZeIiYmRbdu2yulTp6zYHHIZHabSVDI4tbD7teXhdNCgwYEzCBgAAAAAuGTIsGXLZhkz+gtH52o6nKXeBg58TtavX2f1PiKHFWjYLkOVDAUa3pTdu5TvggYCBgAAAAAuGzJM+/kn6da9u/l5//79cvLkCZn01TcyYMDT8usvv1i9j8hhXo07iFvBov+OaSDpjC5RVLwa0ymhlUEDAQMAAAAAlw4ZgoODpWzZcubnHdu3SfPmLaRYsWLSsuWNcuLECav3ETlMh6Ms9Mib/2YMqQUNbuafLsfwldYFDQQMAAAAAFw+ZNBA4ciRI6apxNq1a6Ve/fpmelh4mPj6FrN6H5ELeNVvK4X7jBK3gkWuTbD30fDvvU4v/NQosxyyHjRolEPAAAAAACBfjC7RqdMtMnLEcPH3Ly5RUVHSuPENZvq6deukRYuWVu8jcgmvBm2lwMhZEr15iRmmUkeR0E4etQ8GbSJBBYN1QYN95AkAAAAAcPmQodddd0ulSpUl5FyINGvWXLy9vc10Nzc3ufPOXlbvI3IRDRK8m3cxNwAAAAAAshwyBAcfkxuaNEk2vXv3HrJh/Xpp2qxZZjYLAAAAAADyW58M7w4fLmfPnk02XQOGTz/9xIr9AgAAAAAA+SFkaNu2rbw7/B2JiIhwTFu/fp0JGPr27Wvl/gEAAAAAAFcOGR56+BGpVbuOjHh3uFy5ckXWrVsrn336qfTt10/a3USHdQAAAAAA5EdusbExtsysGB8XJx9//JGcOXNaTp06Lf3695e2bdtJfhIbGyvr1y2VZs3bi6dnprq3AAAAAADAZTh9Zrxz545k02659Vb5csJ4adeunRQvXtyxTN269azdSw014uMlJibGMZJFauLi4uTy5cvi5eUlPj4+ibcRFyeaqHh4eCRbT9fRbRMWAAAAAACQzZUM995zl9MbnT7jV7GKdjD5zTdfyY7t28Vms0lQUJA89VQ/qVGzZorLT/xygvz9919y223d5NHHHndMX7Bgvvw4dYr5+b77HzDz7Q4dOiSff/aJfPDhx+mGGAlRyQAAAAAAQCYqGX76ebpcb1q9MOr990yVxIQvJ0mhQoVk/ry5MmLEu/L551+In79/ouXXrF4tBw8ekLJlyyWaHhYWJlN++EFGjfpA3NzdZNArr0jzZs2lZECAqW7QaozHn3gyQwEDAAAAAADIZMeP2sQgtZuGAdpUIuTs2RSbImTW6VOnJDj4mNx9zz1SpEgRcXd3l9u6dTdhw+Ili5NVPEye/LU8+9zAZE0eDh8+JOXKlZMyZctKUFAZqVy5sqleULNmz5Ly5ctLw4aNLNtvAAAAAADyo0yNLrFly2YZM/oL87M2YdBRJvQ2cOBzZihLq3h4XgssoqOjHdM00IiNjZF9+/Ym6ofhi88/k1533W3ChGTb8fAwTRvs9Gfd9unTp2Xhgvnyv0cfM9vV7QAAAAAAgMzJ1JAI037+SZ7q28/8vH//fjl58oRM+uob2bJ5k/z6yy/SrFlzsUKpUqWlZs2aMuWH76VPn75StFhRmTNnjly6dEkuRFxwLPfzTz9K4cKFpXPnLilup2rVaqbSYdPGjaYa4sSJ41KtWnX54vNP5YEHesvmTRvlm2++NkHDnb3ukjvv7JXidnS+3uzi4v4LLgAAAAAAyO8yFTIEBwc7+j3YsX2bNG/eQooVKyYtW94okyZNsmzn3Nzc5JVXBsv06dNk7NjRpqLhxhtbmec5dy7ELLN79y75+++/Zfjwd+XChWvBgwYB0TEx5rHulza1eO755+Wnn6aayotnnn1ONm3aKB4entKocWN5ekA/eWfYu2a5l196QVo0b2GaViR14vhhOX78sGWvDwAAAAAAye8hg564HzlyRKpXry5r166VO3tdu/IfFh4mvr7FLN3BYr6+8mSfpxJNG/TKy1KxYkXz86mTJ8Xd3U3eeuvNRMNRalOItWtWy6RJX4u7h4c0adLU3FRERIS8OniQDBs+XI4dOyrFi5eQSpUqmXk1atSUAwf2pxgylC1XWYLKXHteeyXDpo3/WPp6AQAAAADIVyFDp063yMgRw8Xfv7hERUVJ48Y3mOnr1q2TFi1aWrqDWnmgFQ12R48ekSNHDsv99z9gHnfo2MncEnrl5Zekbt26iYawTGjyN19L9x49JCCglJw/fz6F/hpSPiza1EJvAAAAAADAopBBO1isVKmyhJwLMf0v2Id+1DAgtf4MMuvXX2aYoSbr1a0nJ0+elK++mmiaTNzQpEmmtqf9Mmj/DM89P9A8rlixkly+fElWr15lKjS0imHA089Y+hqArIjZs06u/PKpFLr7BSlQy5r+TgAAAAAg14QMKqWT/O7de4jVunTpKlOnTpEZ06ebzh07drol3ecpUqSw+Pj4JJuufTrMmDFN+vd/2lGRoMsNfOFFmTrlB1PF0LdffylZsqTlrwPIbCVP5MwJEn/6iLn3rNksUWUPAAAAAOQmbrGxMbasbEBPzBOOuKC8vLwkP9DXvn7dUmnWvL14ptLEAsiKmF1r5NK4FxyPiwz4VArUsbZJEgAAAABYJVNnxlGRkfLTTz/KmjWrJTw83FxtTWj6jF+t2j8gf1cxzJ4o4uYuYos39/rYs3YLqhkAAAAA5EqZ6sXwxx+nyv79++Wpvv3MidCQN4fK/Q88KIUKFZL7/u2QEUDWxO5eK3HHdl8LGJQt3jzW6QAAAADgMiHD+vXrTOeI9iEh69WrL7163SXPPPOcbNywwep9BPJ3FUNC/1YzJK0eAgAAAIA8GzLosI9lypQxPxcsWFCuXL5sfq5Xv74ZYhKAxVUMdlQzAAAAAHC1kEGvotpHZwgKKiMbN200P+/evUuKFCli7R4C+UyqVQx2VDMAAAAAcKWOHwMCAhw/337HHTL6i8/llxkz5Ny5EPpkAKyqYkhNgmoGRpoAAAAAkOdDhrHjJjh+vvHGVqbpxIEDB6RsmbJSq3ZtK/cPyN8jSqSGkSYAAAAAuEpziacH9Ev0uGLFStKxYycTMCSdB8CCvhiSom8GAAAAAK4SMoSEhKQ4PS4uznQKCSArVQxuzq3g5sZIEwAAAADybnOJLZs3p/izirfFy/59+6RUqdLW7R2Qn8TGSHzYGU0bnFveZpP48DNmPSngld17BwAAAADpcouNjXHyjEbk/vvuMffx8fGO0SXsPDw8pVSpAHn44f/JDU2aSH4QGxsr69ctlWbN24unZ6a6twAS0ZAh/lK400fFvYi/uPuX4igCAAAAyBUydGb887QZ5r7Pk0/IpK++zq59AvItd//S5gYAAAAA+aZPBgIGAAAAAABgScgAAAAAAACQFCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAACwBCEDAAAAAADIPyFD9NWrcmD/ftm6dYtcuHAhxWUiIyNl9+5dsm/vXvNzUjabTQ4ePCAHDhwwPye1ZfNmuXLlSrbsPwAAAAAA+YGn5HLbt2+TMaO/kCJFikqxYkXl4MGD8tDDj8itt3Y28zUw+O67b2XVyn8kKChIrl6NljNnTstjjz8h7drd5NjOuLFjZO/ePeLm5iZVq1WX55573jFv9epVMn/ePHn7nWE58hoBAAAAAHAFuTpkiImJkc8+/cSEBf979DEzTYOCt996S2rVrCUVKlY0IUNAQICMGTNOvLy9zTJz58yW8ePGSZ06daVkyZJy4sRx2bBhvYwf/6WIm5sM6N9Xjhw5IpUqVZLLly/LlB9+kDfeGGICCAAAAAAA4ILNJU6ePCEXL16UNm3bOqbVrFnLBAfLli01j93d3aVbt+6OgEG1btNW4uJi5dixo+bxqZOnpGzZcuJTsKD4+PhIxYoVzbbVD99/Jx07dpQyZcte99cHAAAAAIArydUhg5+fv7k/ffq0Y5r2txAREW4qEVKza9dOc1/23+CgcJHCEhER4ZgfHh4hRYoUkZ07d5h+GnrefoccOXxY9u3bJ/Hx8aluV+fFxsY6bhpkAAAAAACAPNBcwtfXVzp06CiTv/laws6fl6LFismiv/821QhXrlxOcZ1z586Z5Tt07CSlSweaadWrVTeBwI9Tp5jKh8jIK1KlSlUZ8sZr8vQzz5pqhg0bNoi3t5cEBgXJoEGvprjtE8cPy/Hjh7P1NQMAAAAAkFe5xcbGJB9qIRfRPhdW/vOP7Ni5Q6Kjo6XVja1kxYrlpjIhaUeN4eHh8s7bQ01zikGDX5MCBQo45mlnkLNmzdINSvfuPWTx4kVme9179JQXBj4v48dPEG8fH3n2mQHywosvmWYZKVUyJKx00OBi08Z/pFnz9uLpmavzGgAAAAAAsl2uPzPWzhi1T4aE/TJMnvyNNG3aNNFyGjoMe+ctKV68hLzyyuBEAYPSqoYnn+xjftamFqtXr5YPP/zIDGlZunQpKVK0qJlXqXJlOXHiRIohg1ZB6A0AAAAAACSX68+YL126lOjxunVrTZOIm2/u4Jh24d+Awd+/uAwe/GqiTiCTio+Lky8njJfHn3jCdASp/TVcuHDBVEyoiH/7awAAAAAAAC5WyTBv3lwJDQ2VenXrmREhZs+eJb179zYVB/ZhLocPf8cEBXf2uku2bN3iWLdy5coSEFAq0fbmzp0jgYGB0rjxDeZxxQoVpVChQvLdd99K0aJF5ezZs1K/foPr/CoBAAAAAMj7cn3IcPfd98jy5ctk8+ZNUrhwYXljyJuJmjLoKA8BpUqZ26pVKxOtqx1EJgwZtA8GbSrx2GOPO6a5e3jIkDffkpkz/zRhxjvvDJOCBQtep1cHAAAAAIDryPUdP+ZmGnCsX7eUjh8BAAAAAMgLfTIAAAAAAIC8gZABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAABYgpABAAAAAAAQMgAAAAAAgNyDSgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJQgYAAAAAAGAJz7xwHIODj8n27dvlyuXLUr1GDWnYsFGyZS5evCirV62U8IgIqVChgjRv3kLc3f/LUK5cuSLLly0Vm4jc1O4mKVS4sGNeXFyc/PrrL9K9W/dE0wEAAAAAgAtVMsybN1dee3WwHDt2TKKjo+XLCeNl3LixiZY5e+aMvPzSC7Jq1Sq5GhUlP3z/nYx6/z2Jj4838202mwwf9o7s2LFDdu3cKe+885Zjnpo58085FxJCwAAAAAAAgKtWMmj1wffffSePPvaYdO7cxUzr0qWrPPvs09KmdRtp0LChmTZl6g8SEFBKhg59S9w9POTWzp1l4PPPyapVK6VNm7Zy8MABOX/+vIx8732z/DNP95e9e/dI7dp15NSpk/L3Xwtl1KgPc/S1AgAAAACQ1+XqSgatUIiLi5Xq1Ws4phUvUUJKliwpa9asdjR12Lhho7Rt184EDKp06UCpU6eOrFu71jwOCw+TgIAAcXNzM7dSpUpL2PkwM2/ilxOkd++HpUjRojnyGgEAAAAAcBW5OmQoHRgonp6esmvXTse0kJCzEhISIidOnDCPz50LkZiYaAkMDEyybpCpUlAlipeQM2fOSHxcnGkmcfr0KRNULFr0t3h7+0iTpk1l4cIFMmfObLlw4UKq+6PrxsbGOm4agAAAAAAAgDzQXKJgwYLyyCP/k++//0727dsrxYoWk61bt0rZsmUlOvqqWeZq1LX7ggULJVq3UKFCEvXvvCpVq0qZMkEyYsRw0xlkiRIlJaBUKfn0009k+Lsj5INR70mBAl6mTwZtOvHhR5+YcCOpE8cPy/Hjh6/LawcAAAAAIK/J1SGD6tL1NmnQsJHs2b3LdPzYo2dP+XbyZImNjTHzfXx8zP2VK5cTracjUdjnqTfeeNM0sdDRJVq2vFHGjhktPW+/XaKiouTw4cMycdLXJlh48YXnZcf27dKoceNk+1K2XGUJKlPR8VgrGTZt/CcbXz0AAAAAAHlHrg8ZVJkyZcxNaTMFrWro3KWreazNHrTJw8mTJ6VRo/+CAX1ctlxZx2Mvb29pd1N78/OG9eslNDTUdCa5c+cOKV68uKNyQftzOH8+NMX90CqIhMNiAgAAAACA/+T6M+YjR44kGm5y9qyZJmjo1LGTeaydPTZv3lyWL1smsTHXqhuOBwfLnj275cYbWyXbXmRkpHz77TfSr3//a00nipeQc+fOScy/62o4UbJkwHV7fQAAAAAAuIpcX8lw6NBBGT9urNSsVUtOnTwhBw4ckBdeeMmMMmHXu/dDMnToEHnjjdelSpUqsmHDBtMkonnzFsm2N3XKD9K2bTspX76CeVymbFmpUaOmvDt8mOkDwsvLS+rVq3ddXyMAAAAAAK7ALTY2RrspyNW0MmHHzh1SuHBhadyocYrDTUZFRppwITwiXCpUqCANGjRMtoz26bBgwXzp0qWrFChQwDFdKyDWrFlj+nlo0fJGEzY4Qysq1q9bKs2at0+xo0gAAAAAAPKTPBEy5FaEDAAAAAAA5KE+GQAAAAAAQN5AyAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACxByAAAAAAAACzhac1m8iebzWbu4+Jic3pXAAAAAOQCHh4e4ubmltO7AeQYQoYsiI+PM/ebNv5j1fsBAAAAIA9r1ry9eHpymoX8yy02Nuba5XhkWHx8vMTERIu7e9pp5fZt66R+g+b59ghrpYcGMTc0aSMeHq73hesq729eeh2u/plC3sdn1LXx/iK34zOas6hkQH7HX+dZ4O7uLt7ePukupwEEaaZ+4Xq65HFwlfc3L74OV/1MwXXwGXVtvL/I7fiMAsgJdPx4HQQGlrseT4Mc4irvr6u8DgAAAAA5h5DhOggMKn89ngY5xFXeX1d5HQAAAAByDiEDsv9D5u4u5cpVNvcAnynkB3zvuTbeX+R2fEYB5CQ6fgQAAAAAAJbg0jIAAAAAALAEIQMAAAAAALAEIQMAAAAAALAEA8wjy3bt3CmrVq+SmOhoqV+/gbRu00bc3NxSXDYk5KxMnTIlxXm3du4sderU5R1Bqi5fvizLli2Vffv2yk03tZfGjW/gaCFHnDt3Thb9/ZecOnVK7r33PilTtmyay//910LZsWNHomkBAQHS+6GHs3lPYaVzISHyz8p/5NTJk+JfvLi0a9su3fceuJ5sNpusX79Odu7YIbGxsVK5cmVp2+4m8fb25o0AcN1QyYAsWbJksQwfPkwKFyokZcuVk+++myyTJk1MdflChQpLs+bNE928vLxk1aqV4ufnz7uBVG3evElefOF5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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "report(\"Phone line\")" + ] + }, + { + "cell_type": "markdown", + "id": "1223-phone-line", + "metadata": {}, + "source": [ + "**The phone line**\n", + "\n", + "- Our pick: Opus 5.5 at `low` with fast mode, with a p90 TTFT of 0.65 seconds at 98.8% accuracy and $0.069 per task.\n", + "- If cost is a constraint: Sonnet 5.5 at `medium` with bigger pages is just as fast at about a quarter of the price and 95.9% accuracy. Its p90 TTLT is 5.1 seconds longer, though, so a caller waits longer for the full answer.\n", + "- For the phone line, the first token comes down to whether the first call thinks. Anything that makes it think, like prefetching the claim or choosing Haiku 5.5, pushes TTFT back. Model size and effort barely matter, and bigger pages don't seem to impact TTFT much." + ] + }, + { + "cell_type": "markdown", + "id": "1300-takeaways", + "metadata": {}, + "source": [ + "\n", + "## Takeaways and next steps\n", + "\n", + "Our two products ended up on the same model, effort, and speed, Opus 5.5 at `low` with fast mode, but on different loops, because one is judged on its first token and the other on the whole task. The key lessons to apply to your own latency experimentation are:\n", + "\n", + "1. **Start with an eval and a quality bar.** Some of the fastest settings fail on accuracy, so build an eval on your own tasks, decide the lowest quality you'll accept up front, and rerun it on every change.\n", + "\n", + "2. **Design for perceived latency.** Optimize for the wait your users actually feel, depending on your product shape. Some notice how long it takes for anything to appear, while others notice how long the full answer takes, and speeding up one can slow down the other.\n", + "\n", + "3. **Fix the loop before the model.** Fewer round trips save time without touching the model's reasoning, and they usually cut cost too. A smaller model or lower effort trades some accuracy for its speed.\n", + "\n", + "4. **Output is usually where the time goes.** Ask for less of it, since a shorter answer often means shorter thinking too, and when a task needs deep reasoning but only a brief answer, use structured outputs and set effort separately. Fast mode or a smaller model writes output faster, but a model that writes faster can still finish later if it has to write more.\n", + "\n", + "The table below starts from the outcome you want and lists the levers that move it. Use this as a quick cheat sheet when deciding which levers to pull first for reducing latency in your application.\n", + "\n", + "| If you want… | Try |\n", + "|---|---|\n", + "| A faster first token | [Send fewer input tokens](#sending-fewer-tokens), cache a static prefix with [prompt caching](#prompt-caching), [pre-warm](#pre-warming) it for bursty traffic, and use [message threads](#message-threads) on long or image-heavy conversations; keep the first call from thinking with [lower effort](#effort), [`between_tools`](#thinking-off) on Sonnet 5.5, or [thinking off](#thinking-off) on Haiku 5.5 |\n", + "| Fewer calls to wait through | [Prefetch](#prefetch-and-bigger-pages) the lookup every task starts with and return [bigger pages](#prefetch-and-bigger-pages) for long results; use [programmatic tool calling](#programmatic-tool-calling) when a run of calls ends in a sum, a filter, or a count, and [subagents](#subagents) on a smaller model for independent lookups |\n", + "| Less output to wait for | Ask for a [short output shape](#prompting-for-shorter-answers) or use [structured outputs](#structured-outputs), and lower [effort](#effort) overall or [on routine turns](#per-turn-effort); ask for [no commentary](#no-commentary) if your agent writes text between tool calls |\n", + "| Faster output once it starts | Turn on [fast mode](#fast-mode) for Opus 5.5, or move jobs that need little reasoning to a [smaller model](#model) as long as it doesn't result in the model writing more |\n", + "| A shorter worst case | Cap the loop with a timeout and a turn cap and each call with `max_tokens`, and give the model a task budget or the elapsed time, per [§Limiting the longest task](#limiting-the-longest-task) |\n", + "| A wait that feels shorter | [Stream](#streaming) replies and show a thinking summary, progress updates, or the running tool [while the model works](#ui-during-thinking-state); [compact in the background](#background-compaction) so long conversations don't stall on a summary |" + ] + }, + { + "cell_type": "markdown", + "id": "1400-limitations", + "metadata": {}, + "source": [ + "\n", + "### Limitations\n", + "\n", + "A few caveats apply before you carry our results over to your own agent:\n", + "\n", + "- **The best levers depend on your specific use case.** Our workload is synthetic, and its tools answer instantly, so real lookups add waits that our figures leave out and expose a different set of opportunities for latency optimization.\n", + "\n", + "- **Latency is nondeterministic.** Most demos report the median of a few runs, and results between models moved from round to round. Whether a lever helped or hurt is more reliable than exactly how much. Running more trials helps reduce noise but can become cost-prohibitive.\n", + "\n", + "- **We focused testing on 5.5 models and the Messages API.** Output speed, thinking, and settings like fast mode can change between model generations, and the API levers in this cookbook may change as the platform evolves. The Agent SDK, Claude Code, and other frameworks also have their own levers that we don't cover here.\n", + "\n", + "- **There are other factors that could be impacting your latency.** Latency also depends on things no lever here changes, like traffic load, time of day, rate limits, and your network and client. It also depends on whether you call the Claude API directly or through a cloud platform, and in which region." + ] + }, + { + "cell_type": "markdown", + "id": "1450-conclusion", + "metadata": {}, + "source": [ + "\n", + "### Conclusion\n", + "\n", + "There's no fastest universal configuration. Acme's phone line and chat agent started from the same agent and the same levers, and they still landed on different configurations because their users feel different waits. Your numbers will most likely differ from ours, but the method and best practices carry over. Set a quality bar and build an eval that holds you to it. Find which terms of the latency equation matter most to your users. Then test combinations of levers that could help, and ship the fastest setting that clears the bar.\n", + "\n", + "Optimizing latency is also never finished. Your traffic and tasks will change, and new models and API features will open up levers this cookbook doesn't cover. Rerun your eval frequently and check whether today's pick is still the fastest." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/content/github/claude-cookbooks/latency_optimization/results/README.md b/content/github/claude-cookbooks/latency_optimization/results/README.md new file mode 100644 index 0000000000..f44b93f11e --- /dev/null +++ b/content/github/claude-cookbooks/latency_optimization/results/README.md @@ -0,0 +1,34 @@ +# What is in sweep.jsonl + +Every line ran with prompt caching on (its caching field says "on"). + +15,172 task attempts count, of 15,246 run, in 3 rounds and 33 settings. + +The file is about 8.4 MB. + +Left out, by rule: + +- cold cache on the first request: 67 +- a request was tried again: 7 + +## What is in baseline.jsonl + +No request behind these lines carried cache_control (their caching field says "off"). + +462 task attempts count, of 462 run, in 3 rounds and 1 setting. + +Left out, by rule: none + +## Fields in both files + +Each line is one task attempt. The fields that latency_stats.py's Sweep reads are: round; the six Config fields (model, effort, thinking, speed, loop, commentary) and caching ("on" in sweep.jsonl, "off" in baseline.jsonl), which the notebook's [Prompt caching](../latency_optimization.ipynb#prompt-caching) section uses to compare the baseline with and without caching; task, type, level, and cluster (a task's id, its job, its level, and the group of tasks redrawn together, which is the task's own id when tasks are independent); correct; secs; the four token counts priced in PRICE (input_tokens, cache_write, cache_read, output_tokens); and call_secs, call_first_token_secs, call_output_tokens, and call_thinking_tokens, with one entry per model call. secs and call_secs are the service's own timing of each request, less a step that only our test harness adds, plus a fixed 0.13 seconds a call to stand for the network. call_first_token_secs is each model call's first-token seconds: the service's own time to its first generated token (thinking included), plus the same fixed 0.13 seconds. Like call_secs, it is the service's own timing. When a call thinks before it writes, its first token is a thinking token, so nothing readable reaches the client at that moment; the notebook estimates a task's first visible token by adding the first call's thinking at that call's own rate of output. call_thinking_tokens is the part of each call's output tokens that was thinking. + +## What is in race.jsonl + +The final run behind the notebook's [Putting it all together](../latency_optimization.ipynb#putting-it-all-together) section: 9 shortlisted model settings (Haiku 5.5 and Sonnet 5.5 at every effort, Opus 5.5 with fast mode at every effort), each with prefetch and bigger pages on or off. + +16,632 task attempts count, of 16,632 run, in 3 rounds and 36 settings. The notebook leaves out Haiku 5.5 at `low`, which fell short of its 95% bar on the baseline loop, and ranks the other 32. Every line ran with prompt caching on, and each setting's cache was written before its tasks started, so no counted attempt found it cold. + +The run had no time limit, and 49 attempts ran past the notebook's 60-second `TIME_LIMIT`, all on Haiku 5.5 at `high`. The file keeps them as they ran. The notebook reads it with `stop=TIME_LIMIT`, which scores each one as `run_task()` would have left it: stopped at 60 seconds, with nothing recorded, so wrong. + +The fields are those of sweep.jsonl, plus call_first_visible_secs, each model call's seconds to its first text or tool call, measured directly, and first_cache_read, the first call's cache read. Seconds in this file are timed by the client that ran the loop, from the start of each request to its last event, so they include the network. diff --git a/content/github/claude-cookbooks/managed_agents/CMA_plan_big_execute_small.ipynb b/content/github/claude-cookbooks/managed_agents/CMA_plan_big_execute_small.ipynb index 54e1cb964e..bd932f1238 100644 --- a/content/github/claude-cookbooks/managed_agents/CMA_plan_big_execute_small.ipynb +++ b/content/github/claude-cookbooks/managed_agents/CMA_plan_big_execute_small.ipynb @@ -68,7 +68,7 @@ "outputs": [], "source": [ "%%capture\n", - "%pip install -qU \"anthropic>=1.13.0\" python-dotenv" + "%pip install -qU \"anthropic>=2.0.0\" python-dotenv" ] }, { diff --git a/content/github/claude-cookbooks/managed_agents/CMA_prompt_versioning_and_rollback.ipynb b/content/github/claude-cookbooks/managed_agents/CMA_prompt_versioning_and_rollback.ipynb index 80ba489ddd..b70ebe4874 100644 --- a/content/github/claude-cookbooks/managed_agents/CMA_prompt_versioning_and_rollback.ipynb +++ b/content/github/claude-cookbooks/managed_agents/CMA_prompt_versioning_and_rollback.ipynb @@ -21,7 +21,7 @@ "\n", "**Required:**\n", "- Python 3.11+\n", - "- `anthropic>=0.91.0`\n", + "- `anthropic>=2.0.0`\n", "- An Anthropic API key\n", "- The `example_data/prompt_versioning_and_rollback/support_tickets.jsonl` fixture in this directory\n" ] @@ -42,7 +42,7 @@ "outputs": [], "source": [ "%%capture\n", - "%pip install -q \"anthropic>=0.91.0\" python-dotenv" + "%pip install -q \"anthropic>=2.0.0\" python-dotenv" ] }, { diff --git a/content/github/claude-cookbooks/managed_agents/CMA_remember_user_preferences.ipynb b/content/github/claude-cookbooks/managed_agents/CMA_remember_user_preferences.ipynb index 0661158860..558b302f1e 100644 --- a/content/github/claude-cookbooks/managed_agents/CMA_remember_user_preferences.ipynb +++ b/content/github/claude-cookbooks/managed_agents/CMA_remember_user_preferences.ipynb @@ -60,7 +60,7 @@ "outputs": [], "source": [ "%%capture\n", - "%pip install -q \"anthropic>=0.91.0\"" + "%pip install -q \"anthropic>=2.0.0\"" ] }, { diff --git a/content/github/claude-cookbooks/managed_agents/CMA_use_skills_from_a_repo.ipynb b/content/github/claude-cookbooks/managed_agents/CMA_use_skills_from_a_repo.ipynb index 03101032d5..172ba33ada 100644 --- a/content/github/claude-cookbooks/managed_agents/CMA_use_skills_from_a_repo.ipynb +++ b/content/github/claude-cookbooks/managed_agents/CMA_use_skills_from_a_repo.ipynb @@ -37,7 +37,7 @@ "outputs": [], "source": [ "%%capture\n", - "%pip install -qU \"anthropic>=0.121.0\" python-dotenv" + "%pip install -qU \"anthropic>=2.0.0\" python-dotenv" ] }, { diff --git a/content/github/claude-cookbooks/managed_agents/CMA_watch_subagents_live.ipynb b/content/github/claude-cookbooks/managed_agents/CMA_watch_subagents_live.ipynb index 68172dc877..3ba7aca589 100644 --- a/content/github/claude-cookbooks/managed_agents/CMA_watch_subagents_live.ipynb +++ b/content/github/claude-cookbooks/managed_agents/CMA_watch_subagents_live.ipynb @@ -20,7 +20,7 @@ "outputs": [], "source": [ "%%capture\n", - "%pip install -qU \"anthropic>=0.118.0\" python-dotenv" + "%pip install -qU \"anthropic>=2.0.0\" python-dotenv" ] }, { diff --git a/content/github/claude-cookbooks/managed_agents/CMA_with_mongodb_atlas.ipynb b/content/github/claude-cookbooks/managed_agents/CMA_with_mongodb_atlas.ipynb index 2df8fc2850..72c2c36737 100644 --- a/content/github/claude-cookbooks/managed_agents/CMA_with_mongodb_atlas.ipynb +++ b/content/github/claude-cookbooks/managed_agents/CMA_with_mongodb_atlas.ipynb @@ -64,7 +64,7 @@ "# pymongo (the host-side data path), python-dotenv, and cryptography + pyjwt (sign/verify the\n", "# AP2 mandates). This installs the PyPI packages only — the notebook also imports the adjacent\n", "# `mongodb_on_cma/` package and `utilities.py`, so run it from a clone of this repo (see Setup).\n", - "%pip install -q \"anthropic>=0.109.0\" pymongo python-dotenv cryptography pyjwt" + "%pip install -q \"anthropic>=2.0.0\" pymongo python-dotenv cryptography pyjwt" ] }, { diff --git a/content/github/claude-cookbooks/managed_agents/README.md b/content/github/claude-cookbooks/managed_agents/README.md index 19a9380ee6..c79225c717 100644 --- a/content/github/claude-cookbooks/managed_agents/README.md +++ b/content/github/claude-cookbooks/managed_agents/README.md @@ -30,6 +30,11 @@ record and audit backbone. the agent investigates and opens a PR, then pauses for human approval before merging. You'll wire the alert webhook, attach a Skill and custom tools, and review the full run in the Console. +- **[CMA_agent_security_review.ipynb](CMA_agent_security_review.ipynb)** + builds a review system for finished agent sessions. You'll describe + each agent's limits, turn Managed Agents, Messages API or Agent SDK + logs into transcripts, have Claude review each session in a dynamic workflow, + and get a ranked report with quoted evidence. ## Guided tutorials diff --git a/content/github/claude-cookbooks/managed_agents/data_analyst_agent.ipynb b/content/github/claude-cookbooks/managed_agents/data_analyst_agent.ipynb index f5fe9ae992..9441fea781 100644 --- a/content/github/claude-cookbooks/managed_agents/data_analyst_agent.ipynb +++ b/content/github/claude-cookbooks/managed_agents/data_analyst_agent.ipynb @@ -47,7 +47,7 @@ "outputs": [], "source": [ "%%capture\n", - "%pip install -q \"anthropic>=0.91.0\" python-dotenv" + "%pip install -q \"anthropic>=2.0.0\" python-dotenv" ] }, { diff --git a/content/github/claude-cookbooks/managed_agents/slack_data_bot.ipynb b/content/github/claude-cookbooks/managed_agents/slack_data_bot.ipynb index 9ece0e31bc..294cb9e92b 100644 --- a/content/github/claude-cookbooks/managed_agents/slack_data_bot.ipynb +++ b/content/github/claude-cookbooks/managed_agents/slack_data_bot.ipynb @@ -55,7 +55,7 @@ "outputs": [], "source": [ "%%capture\n", - "%pip install -q \"anthropic>=0.91.0\" python-dotenv slack_bolt requests markdown-to-mrkdwn" + "%pip install -q \"anthropic>=2.0.0\" python-dotenv slack_bolt requests markdown-to-mrkdwn" ] }, { diff --git a/content/github/claude-cookbooks/managed_agents/sre_incident_responder.ipynb b/content/github/claude-cookbooks/managed_agents/sre_incident_responder.ipynb index bcb419dd87..78be5f04ee 100644 --- a/content/github/claude-cookbooks/managed_agents/sre_incident_responder.ipynb +++ b/content/github/claude-cookbooks/managed_agents/sre_incident_responder.ipynb @@ -48,7 +48,7 @@ }, "outputs": [], "source": [ - "%pip install -q \"anthropic>=0.91.0\" python-dotenv" + "%pip install -q \"anthropic>=2.0.0\" python-dotenv" ] }, { @@ -139,10 +139,10 @@ "\"\"\"\n", "\n", "skill = client.beta.skills.create(\n", - " display_title=\"incident-runbooks\",\n", + " display_name=\"incident-runbooks\",\n", " files=[(\"incident-runbooks/SKILL.md\", RUNBOOK_SKILL.encode(), \"text/markdown\")],\n", ")\n", - "print(f\"skill: {skill.id} (version {skill.latest_version})\")" + "print(f\"skill: {skill.id} (version {skill.latest_version_id})\")" ] }, { @@ -211,7 +211,7 @@ " metadata={\"anthropic_cookbook\": \"claude-cookbooks/sre-incident-responder\"},\n", " model=MODEL,\n", " system=SRE_SYSTEM_PROMPT,\n", - " skills=[{\"type\": \"custom\", \"skill_id\": skill.id, \"version\": skill.latest_version}],\n", + " skills=[{\"type\": \"custom\", \"skill_id\": skill.id, \"version\": skill.latest_version_id}],\n", " tools=[\n", " {\n", " \"type\": \"agent_toolset_20260401\",\n", @@ -752,8 +752,7 @@ "client.beta.sessions.archive(session_id)\n", "client.beta.environments.archive(env.id)\n", "client.beta.agents.archive(agent.id)\n", - "client.beta.skills.versions.delete(skill.latest_version, skill_id=skill.id)\n", - "client.beta.skills.delete(skill.id)\n", + "client.beta.skills.delete(skill.id) # deleting a skill also deletes its versions\n", "print(\"archived\")" ] }, diff --git a/content/github/claude-cookbooks/misc/admin_api.ipynb b/content/github/claude-cookbooks/misc/admin_api.ipynb index 81767f7a52..2dfcbc3cce 100644 --- a/content/github/claude-cookbooks/misc/admin_api.ipynb +++ b/content/github/claude-cookbooks/misc/admin_api.ipynb @@ -661,9 +661,9 @@ ], "source": [ "for rl in client.beta.organization.rate_limits.list():\n", - " if rl.group_type == \"model_group\" and MODEL not in (rl.models or []):\n", + " if rl.group.type == \"model_group\" and MODEL not in (rl.models or []):\n", " continue\n", - " label = MODEL if rl.group_type == \"model_group\" else rl.group_type\n", + " label = MODEL if rl.group.type == \"model_group\" else rl.group.type\n", " limits = \", \".join(f\"{limit.type}={limit.value:,}\" for limit in rl.limits)\n", " print(f\"{label:<18} {limits}\")" ] @@ -702,7 +702,7 @@ "if not overrides:\n", " print(f\"{workspace.name} has no overrides and inherits the organization limits\")\n", "for rl in overrides:\n", - " print(rl.group_type, rl.models, [(limit.type, limit.value) for limit in rl.limits])" + " print(rl.group.type, rl.models, [(limit.type, limit.value) for limit in rl.limits])" ] }, { diff --git a/content/github/claude-cookbooks/misc/generate_test_cases.ipynb b/content/github/claude-cookbooks/misc/generate_test_cases.ipynb index ce12eee118..59cc39e5ea 100644 --- a/content/github/claude-cookbooks/misc/generate_test_cases.ipynb +++ b/content/github/claude-cookbooks/misc/generate_test_cases.ipynb @@ -33,17 +33,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "a480851e", "metadata": {}, "outputs": [], "source": [ - "% pip install anthropic IPython" + "%pip install -q anthropic IPython python-dotenv" ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "id": "36537f92-33ca-4e6c-9f3c-e439fd103965", "metadata": {}, "outputs": [], @@ -51,10 +51,11 @@ "import re\n", "\n", "import anthropic\n", + "from dotenv import load_dotenv\n", "\n", - "# Enter your API key here\n", - "api_key = \"\"\n", - "CLIENT = anthropic.Anthropic(api_key=api_key)\n", + "load_dotenv() # reads ANTHROPIC_API_KEY from .env if present\n", + "\n", + "CLIENT = anthropic.Anthropic()\n", "MODEL_NAME = \"claude-sonnet-5-5\"" ] }, @@ -68,7 +69,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "id": "a3cf101a-8781-4dfd-bc12-79f39e6b579c", "metadata": {}, "outputs": [], @@ -155,7 +156,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "id": "dbea4731-ba24-4854-b33c-45d699790d7b", "metadata": {}, "outputs": [], @@ -243,7 +244,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "id": "fb3d6193-51fa-469e-8e64-d860fc1657bf", "metadata": {}, "outputs": [], @@ -281,7 +282,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "id": "9b5becbd-907d-4729-a37f-c892bde3a8e0", "metadata": {}, "outputs": [], @@ -322,7 +323,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "id": "feccf7db", "metadata": {}, "outputs": [ @@ -370,7 +371,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "id": "0606eaa2", "metadata": { "scrolled": true @@ -397,7 +398,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "id": "6da69c33", "metadata": {}, "outputs": [], @@ -427,52 +428,53 @@ "Generated test case:\n", "~~~~~~~~~~~\n", "DOCUMENTS:\n", - "Return Policy\n", - "- Items may be returned within 30 days of purchase with original receipt\n", - "- Items must be unused and in original packaging\n", - "- Shipping costs are non-refundable\n", - "- Gift cards are non-returnable\n", - "\n", - "Shipping Information\n", - "- Standard shipping (5-7 business days): Free on orders over $50\n", - "- Express shipping (2-3 business days): $12.99\n", - "- Overnight shipping (next business day): $24.99\n", - "- We ship to continental US only\n", - "- Alaska and Hawaii orders incur additional $15 fee\n", - "\n", - "Payment Methods\n", - "- We accept Visa, Mastercard, American Express, and PayPal\n", - "- Payment is processed at time of order\n", - "- Gift cards cannot be used for partial payment\n", + "**Acme Corporation Customer Policies (Last updated: January 2025)**\n", + "\n", + "**1. Returns and Refunds**\n", + "- Most items may be returned within 30 days of delivery for a full refund to the original payment method, provided they are unused and in their original packaging.\n", + "- Items marked \"Final Sale\" or \"Clearance\" cannot be returned or exchanged, but are still covered by our warranty if defective (see Section 3).\n", + "- Customers are responsible for return shipping costs unless the item arrived damaged or defective, or we sent the wrong item. In those cases, Acme will provide a prepaid return label.\n", + "- Refunds are processed within 5-7 business days after we receive the returned item. Your bank may take an additional 3-5 business days to post the credit.\n", + "- Original shipping fees are non-refundable unless the return is due to an Acme error.\n", + "- Opened software, digital downloads, and gift cards are not eligible for return.\n", + "\n", + "**2. Shipping**\n", + "- Standard shipping (5-8 business days) is free on orders over $50. Orders under $50 have a flat $5.99 shipping fee.\n", + "- Expedited shipping (2-3 business days) costs $14.99. Overnight shipping costs $29.99 and must be ordered before 2:00 PM Eastern Time.\n", + "- Acme currently ships to the United States and Canada only. International orders are not available at this time.\n", + "- Once your order ships, you will receive a confirmation email with a tracking number. Orders typically ship within 1-2 business days of being placed.\n", + "- Acme is not responsible for delays caused by carriers, weather, or incorrect shipping addresses provided by the customer.\n", + "\n", + "**3. Warranty**\n", + "- All Acme-branded products include a 1-year limited warranty covering defects in materials and workmanship, starting from the date of delivery.\n", + "- The warranty does not cover damage from misuse, accidents, unauthorized modifications, or normal wear and tear.\n", + "- To make a warranty claim, contact Customer Support with your order number and a description or photo of the issue. Approved claims will be repaired or replaced at Acme's discretion.\n", + "- Extended warranties (2 additional years) can be purchased within 30 days of the original purchase for 15% of the item's price.\n", + "\n", + "**4. Order Changes and Cancellations**\n", + "- Orders can be modified or canceled within 1 hour of being placed by visiting the \"My Orders\" page in your account.\n", + "- After 1 hour, orders enter processing and can no longer be changed. If the order has not yet shipped, you may contact Customer Support to request a cancellation, but we cannot guarantee it will be successful.\n", + "- Once an order has shipped, it cannot be canceled. You may return it according to our Returns policy.\n", + "\n", + "**5. Contact Information**\n", + "- Customer Support is available Monday-Friday, 9:00 AM to 8:00 PM Eastern Time, and Saturday, 10:00 AM to 4:00 PM Eastern Time.\n", + "- Email: support@acmecorp.example | Phone: 1-800-555-0142 | Live chat available on acmecorp.example during business hours.\n", + "- Please have your order number ready when contacting us. Response time for emails is typically within 24 hours.\n", "\n", "QUESTION:\n", - "Hi, I ordered a sweater last week but it doesn't fit right. Can I return it? And will I get refunded for the shipping I paid? Thanks!\n", + "Hi, I bought a Roadrunner Blender from you guys about 3 weeks ago during the clearance sale and now the motor makes a burning smell whenever I turn it on. I'd like to send it back for a refund. Also, who pays for the shipping if I send it back? Thanks\n", "\n", "~~~~~~~~~~~\n", "Planning:\n", "~~~~~~~~~~~\n", "\n", - "1. Prompt Template Summary:\n", - "This template creates a customer service chatbot for Acme Corporation that answers customer questions based on official company policies/FAQ documents. The goal is to ensure consistent, policy-compliant responses to customer inquiries.\n", + "1. **Summary of the prompt template:** The template sets up a customer support chatbot for Acme Corporation. The bot gets an FAQ or policy document set and a customer's question. It should answer using details from those policies. The creator wants accurate, policy-grounded answers that don't invent information. The bot should handle both questions the policies cover and questions they only partly cover or don't cover.\n", "\n", - "2. Variable Analysis:\n", + "2. **Variables:**\n", "\n", - "DOCUMENTS:\n", - "- Would likely be maintained by Acme's policy/legal team\n", - "- Stored in a knowledge base or content management system\n", - "- Formatted as structured FAQ entries or policy statements\n", - "- Professional, formal tone\n", - "- Multiple paragraphs covering different topics\n", - "- Clear headers and categories\n", - "- Length: Several paragraphs (300-500 words)\n", + " - **DOCUMENTS:** In production, the company or a developer would supply this, probably pulled from a knowledge base, CMS, or database of policy pages and inserted by a retrieval system or a static config. A realistic value is a set of FAQ entries or policy sections, such as returns, shipping, warranty, and account or payment policies. It should be fairly long (several hundred words), with headings or Q&A format, concrete details (timeframes, fees, conditions, contact info), and a neutral, professional tone. Including a few edge-case details (exceptions, conditions) makes the test case more useful. Acme Corporation is a generic company, so I'll make it a consumer products seller, in the spirit of the cartoon company.\n", "\n", - "QUESTION:\n", - "- Written by end users/customers\n", - "- Informal, conversational tone\n", - "- Usually 1-2 sentences\n", - "- Often includes context about their specific situation\n", - "- May contain typos or casual language\n", - "- Length: 20-50 words\n", + " - **QUESTION:** In production, a human customer would type this into a chat widget or support form. It should be casual, perhaps with a bit of frustration or missing context, and one to a few sentences long. A good test question needs information from more than one policy section and has a wrinkle, such as an item bought on sale or a return outside the window. That checks whether the bot reads the policies carefully instead of just matching keywords. I'll write a question about returning a product that has an exception in the policy, and ask a related follow-up the documents only partly cover.\n", "\n" ] } @@ -564,53 +566,70 @@ "Generated test case:\n", "~~~~~~~~~~~\n", "DOCUMENTS:\n", - "Return Policy\n", - "- Items may be returned within 30 days of purchase with original receipt\n", - "- Items must be unused and in original packaging\n", - "- Shipping costs are non-refundable\n", - "- Store credit will be issued for items returned without receipt\n", - "\n", - "Shipping Information\n", - "- Standard shipping (5-7 business days): $5.99\n", - "- Express shipping (2-3 business days): $12.99\n", - "- Free standard shipping on orders over $50\n", - "- We currently ship only within the continental United States\n", - "- Alaska and Hawaii orders subject to additional fees\n", - "\n", - "Payment Methods\n", - "- We accept Visa, Mastercard, American Express, and PayPal\n", - "- Gift cards cannot be used for online purchases\n", - "- Payment is processed at time of order\n", - "- All prices are in USD\n", + "ACME CORPORATION CUSTOMER POLICIES (Last updated: January 2024)\n", + "\n", + "SECTION 1: RETURNS AND REFUNDS\n", + "\n", + "Q: What is Acme's standard return policy?\n", + "A: Most items purchased from Acme.com may be returned within 30 days of the delivery date for a full refund, provided they are unused, in their original packaging, and accompanied by proof of purchase. Refunds are issued to the original form of payment within 5-7 business days after we receive and inspect the returned item.\n", + "\n", + "Q: Are there items that cannot be returned?\n", + "A: Yes. The following items are final sale and cannot be returned or exchanged: items marked \"Clearance\" or \"Final Sale\" at the time of purchase, custom or personalized products, perishable goods, and any product containing explosives (including the Acme Rocket Skates and Acme Dehydrated Boulders when opened). Gift cards are also non-refundable.\n", + "\n", + "Q: Who pays for return shipping?\n", + "A: Customers are responsible for return shipping costs unless the item arrived damaged or defective, or we sent the wrong item. In those cases, Acme will email you a prepaid return label. A flat $7.95 restocking fee applies to returns of items over 50 lbs that are not defective.\n", + "\n", + "Q: Can I exchange an item instead of returning it?\n", + "A: Yes. Exchanges for a different size, color, or model can be requested within 30 days of delivery. If the new item costs more, you will be charged the difference. If it costs less, the difference will be refunded to your original payment method.\n", + "\n", + "SECTION 2: SHIPPING\n", + "\n", + "Q: What shipping options are available?\n", + "A: Standard Shipping (5-8 business days) is $5.99 on orders under $50 and free on orders of $50 or more. Expedited Shipping (2-3 business days) is $14.99. Overnight Shipping is $29.99 and must be ordered before 12:00 PM Pacific Time. We currently ship to the United States and Canada only.\n", + "\n", + "Q: How can I track my order?\n", + "A: Once your order ships, you will receive an email with a tracking number and a link to the carrier's website. You can also view tracking information by logging in to your Acme account and selecting \"Order History.\"\n", + "\n", + "Q: What if my package arrives damaged?\n", + "A: Contact Customer Support within 14 days of delivery with your order number and photos of the damaged item and packaging. We will send a replacement or issue a full refund, at your choice.\n", + "\n", + "SECTION 3: WARRANTY\n", + "\n", + "Q: Does Acme offer a warranty?\n", + "A: All Acme products come with a 90-day limited warranty covering defects in materials and workmanship. The warranty does not cover damage caused by misuse, unauthorized modifications, or normal wear and tear. It also does not cover damage resulting from use near cliffs, canyons, or desert highways. To make a warranty claim, contact Customer Support with your order number and a description of the problem.\n", + "\n", + "Q: Can I extend my warranty?\n", + "A: Yes. Acme Protect extends your warranty to 2 years and is available for purchase within 30 days of your original order. Pricing varies by product.\n", + "\n", + "SECTION 4: ACCOUNT AND PAYMENT\n", + "\n", + "Q: What payment methods does Acme accept?\n", + "A: We accept Visa, Mastercard, American Express, Discover, PayPal, and Acme Gift Cards. We do not accept checks or money orders.\n", + "\n", + "Q: How do I cancel an order?\n", + "A: Orders can be canceled within 2 hours of placement by logging in to your account and selecting \"Cancel Order.\" After that window, the order may have already entered processing, and you will need to wait for delivery and submit a return.\n", + "\n", + "SECTION 5: CONTACT INFORMATION\n", + "\n", + "Customer Support is available Monday-Friday, 8:00 AM-6:00 PM Pacific Time.\n", + "Email: support@acme-corp.example\n", + "Phone: 1-800-555-0142\n", + "Live chat: available on Acme.com during business hours.\n", "\n", "QUESTION:\n", - "Hi, I ordered a sweater last week but it doesn't fit right. Can I return it? I still have the tags on it but I threw away the receipt. Thanks!\n", + "hey, i bought a pair of Acme Rocket Skates about 3 weeks ago and they're way too fast for me lol. i already took them out of the box and tried them once. can i still return them? also i think they were on clearance when i bought them. if i can't return them can i at least get my money back some other way? and who pays for shipping if i send them back\n", "\n", "~~~~~~~~~~~\n", "Planning:\n", "~~~~~~~~~~~\n", "\n", - "1. Prompt Template Summary:\n", - "This template creates a customer service chatbot for Acme Corporation that answers customer questions based on official company policies/FAQ documents. The goal is to ensure consistent, policy-compliant responses to customer inquiries.\n", + "1. **Summary of the prompt template:** The template sets up a customer support chatbot for Acme Corporation. The bot gets an FAQ or policy document set and a customer's question. It should answer using details from those policies. The creator wants accurate, policy-grounded answers that don't invent information. The bot should handle both questions the policies cover and questions they only partly cover or don't cover.\n", "\n", - "2. Variable Analysis:\n", + "2. **Variables:**\n", "\n", - "DOCUMENTS:\n", - "- Would likely be maintained by Acme's policy/legal team\n", - "- Stored in a knowledge base or content management system\n", - "- Formatted as structured FAQ entries or policy statements\n", - "- Professional, formal tone\n", - "- Multiple paragraphs covering different topics\n", - "- Clear headers and categories\n", - "- Length: Several paragraphs (300-500 words)\n", + " - **DOCUMENTS:** In production, the company or a developer would supply this, probably pulled from a knowledge base, CMS, or database of policy pages and inserted by a retrieval system or a static config. A realistic value is a set of FAQ entries or policy sections, such as returns, shipping, warranty, and account or payment policies. It should be fairly long (several hundred words), with headings or Q&A format, concrete details (timeframes, fees, conditions, contact info), and a neutral, professional tone. Including a few edge-case details (exceptions, conditions) makes the test case more useful. Acme Corporation is a generic company, so I'll make it a consumer products seller, in the spirit of the cartoon company.\n", "\n", - "QUESTION:\n", - "- Written by end users/customers\n", - "- Informal, conversational tone\n", - "- Usually 1-2 sentences\n", - "- Often includes context about their specific situation\n", - "- May contain typos or casual language\n", - "- Length: 20-50 words\n", + " - **QUESTION:** In production, a human customer would type this into a chat widget or support form. It should be casual, perhaps with a bit of frustration or missing context, and one to a few sentences long. A good test question needs information from more than one policy section and has a wrinkle, such as an item bought on sale or a return outside the window. That checks whether the bot reads the policies carefully instead of just matching keywords. I'll write a question about returning a product that has an exception in the policy, and ask a related follow-up the documents only partly cover.\n", "\n" ] } @@ -671,54 +690,79 @@ "Generated test case:\n", "~~~~~~~~~~~\n", "DOCUMENTS:\n", - "Product Warranty\n", - "- All electronics come with a 1-year limited manufacturer warranty\n", - "- Warranty covers defects in materials and workmanship\n", - "- Warranty does not cover accidental damage or misuse\n", - "- Extended warranty available for purchase within 30 days\n", - "\n", - "Price Match Policy\n", - "- We match prices from authorized retailers\n", - "- Item must be identical model/color/specification\n", - "- Must be in stock at competitor's store\n", - "- Online retailers excluded from price matching\n", - "- Price match requests must be made at time of purchase\n", - "\n", - "Order Cancellation\n", - "- Orders can be cancelled within 2 hours of placement\n", - "- Once order is shipped, cancellation not possible\n", - "- Cancelled orders refunded to original payment method\n", - "- Processing time for refunds: 3-5 business days\n", - "- Contact customer service for cancellation requests\n", + "ACME CORPORATION CUSTOMER POLICIES (Last updated: March 2024)\n", + "\n", + "SECTION 1: ORDERS AND PAYMENT\n", + "\n", + "Q: What payment methods does Acme accept?\n", + "A: We accept Visa, Mastercard, American Express, Discover, PayPal, and Acme Gift Cards. We do not accept personal checks, money orders, or cryptocurrency. Sales tax is calculated at checkout based on your shipping address.\n", + "\n", + "Q: Can I change or cancel my order after placing it?\n", + "A: Orders can be changed or canceled within 1 hour of placement by logging in to your Acme account, opening \"Order History,\" and selecting \"Edit Order\" or \"Cancel Order.\" After 1 hour, orders enter our fulfillment process and can no longer be modified. If you no longer want the item, you may refuse delivery or return it once it arrives, subject to our return policy.\n", + "\n", + "Q: Can I use more than one promo code on an order?\n", + "A: No. Only one promotional code may be applied per order. Promo codes cannot be applied to gift cards, Acme Protect plans, or items marked \"Clearance.\"\n", + "\n", + "SECTION 2: SHIPPING AND DELIVERY\n", + "\n", + "Q: What are the shipping options and costs?\n", + "A: Standard Shipping (5-8 business days) costs $6.49 for orders under $75 and is free for orders of $75 or more. Two-Day Shipping is $15.99. Overnight Shipping is $31.99 and must be ordered by 11:00 AM Pacific Time on a business day. Orders placed after the cutoff or on weekends ship the next business day.\n", + "\n", + "Q: Do you ship internationally?\n", + "A: We currently ship to all 50 U.S. states, Puerto Rico, and Canada. We do not ship to P.O. boxes for orders containing oversized items. International shipping outside these regions is not available at this time.\n", + "\n", + "Q: My tracking says \"Delivered\" but I don't have my package. What should I do?\n", + "A: First, check around your property and with neighbors, as carriers sometimes leave packages in unexpected places. Wait 24 hours, as tracking updates can occasionally be early. If the package has still not arrived, contact Customer Support within 7 days of the \"Delivered\" date and we will open an investigation with the carrier.\n", + "\n", + "Q: What should I do if my item arrives damaged or incorrect?\n", + "A: Contact Customer Support within 10 days of delivery with your order number and photos of the item and its packaging. We will send a replacement at no cost or issue a full refund, whichever you prefer. We will email you a prepaid return label if a return is needed.\n", + "\n", + "SECTION 3: RETURNS AND REFUNDS\n", + "\n", + "Q: What is the standard return policy?\n", + "A: Most items may be returned within 45 days of the delivery date for a full refund, provided they are unused, in their original packaging, and accompanied by proof of purchase. Refunds are issued to the original form of payment within 7-10 business days after we receive and inspect the item.\n", + "\n", + "Q: Which items are not eligible for return?\n", + "A: The following are final sale: items marked \"Clearance\" or \"Final Sale\" at the time of purchase, custom-made or engraved products, perishable items, opened software or digital downloads, and gift cards. Items that have been used or damaged by the customer are also ineligible for refund.\n", + "\n", + "Q: Who pays for return shipping?\n", + "A: Customers pay return shipping unless the item was defective, damaged in transit, or sent in error. In those cases, Acme provides a prepaid return label. Items over 40 lbs that are returned for reasons other than a defect are subject to a $9.95 restocking fee, which is deducted from the refund.\n", + "\n", + "Q: Can I get store credit instead of a refund?\n", + "A: Yes. If you are within the 45-day return window, you may choose to receive Acme store credit instead of a refund to your original payment method. Store credit is issued as an Acme Gift Card by email within 3 business days of our receiving the return. Store credit does not expire.\n", + "\n", + "SECTION 4: WARRANTY AND REPAIRS\n", + "\n", + "Q: What warranty comes with Acme products?\n", + "A: All Acme products include a 1-year limited warranty against defects in materials and workmanship, starting from the delivery date. The warranty does not cover accidental damage, misuse, unauthorized repairs or modifications, commercial use, or normal wear and tear. To start a claim, contact Customer Support with your order number, a description of the problem, and photos or video if possible.\n", + "\n", + "Q: Can I extend my warranty?\n", + "A: Yes. Acme Protect extends your coverage to 3 years and also covers accidental damage from handling. It must be purchased within 30 days of your original order. Pricing depends on the product and is shown at checkout.\n", + "\n", + "Q: Do you offer repairs outside of warranty?\n", + "A: For many products, yes. Contact Customer Support with your order number to request a repair quote. Repair costs and turnaround times vary by product and are not guaranteed to be less than the cost of a replacement.\n", + "\n", + "SECTION 5: CONTACT INFORMATION\n", + "\n", + "Customer Support hours: Monday-Saturday, 7:00 AM-7:00 PM Pacific Time. Closed on Sundays and major U.S. holidays.\n", + "Email: help@acme-corp.example (responses within 1 business day)\n", + "Phone: 1-800-555-0187\n", + "Live chat: available on Acme.com during support hours.\n", "\n", "QUESTION:\n", - "Hello, I bought a laptop from your store 3 weeks ago and it keeps shutting down randomly. It's still under warranty, right? What do I need to do to get it fixed? Thanks in advance!\n", + "Hi, I ordered a pair of Acme Anvil Boots (the heavy ones, they're like 45 lbs I think??) about 5 weeks ago and I've worn them around the house a few times. They're not defective, I just realized I don't like how they feel. I know there's a return window but I'm not sure if I'm still in it. Also if I can return them, would I have to pay for shipping, and is there anything else that'd be taken out of my refund? Last thing, could I get a gift card instead of the money back?\n", "\n", "~~~~~~~~~~~\n", "Planning:\n", "~~~~~~~~~~~\n", "\n", - "1. Prompt Template Summary:\n", - "This template creates a customer service chatbot for Acme Corporation that answers customer questions based on official company policies/FAQ documents. The goal is to ensure consistent, policy-compliant responses to customer inquiries.\n", + "1. **Summary of the prompt template:** The template sets up a customer support chatbot for Acme Corporation. The bot gets an FAQ or policy document set and a customer's question. It should answer using details from those policies. The creator wants accurate, policy-grounded answers that don't invent information. The bot should handle both questions the policies cover and questions they only partly cover or don't cover.\n", "\n", - "2. Variable Analysis:\n", + "2. **Variables:**\n", "\n", - "DOCUMENTS:\n", - "- Would likely be maintained by Acme's policy/legal team\n", - "- Stored in a knowledge base or content management system\n", - "- Formatted as structured FAQ entries or policy statements\n", - "- Professional, formal tone\n", - "- Multiple paragraphs covering different topics\n", - "- Clear headers and categories\n", - "- Length: Several paragraphs (300-500 words)\n", + " - **DOCUMENTS:** In production, the company or a developer would supply this, probably pulled from a knowledge base, CMS, or database of policy pages and inserted by a retrieval system or a static config. A realistic value is a set of FAQ entries or policy sections, such as returns, shipping, warranty, and account or payment policies. It should be fairly long (several hundred words), with headings or Q&A format, concrete details (timeframes, fees, conditions, contact info), and a neutral, professional tone. Including a few edge-case details (exceptions, conditions) makes the test case more useful. Acme Corporation is a generic company, so I'll make it a consumer products seller, in the spirit of the cartoon company.\n", "\n", - "QUESTION:\n", - "- Written by end users/customers\n", - "- Informal, conversational tone\n", - "- Usually 1-2 sentences\n", - "- Often includes context about their specific situation\n", - "- May contain typos or casual language\n", - "- Length: 20-50 words\n", + " - **QUESTION:** In production, a human customer would type this into a chat widget or support form. It should be casual, perhaps with a bit of frustration or missing context, and one to a few sentences long. A good test question needs information from more than one policy section and has a wrinkle, such as an item bought on sale or a return outside the window. That checks whether the bot reads the policies carefully instead of just matching keywords. I'll write a question about returning a product that has an exception in the policy, and ask a related follow-up the documents only partly cover.\n", "\n" ] } @@ -780,7 +824,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.14" + "version": "3.12.14" } }, "nbformat": 4, diff --git a/content/github/claude-cookbooks/misc/session_memory_compaction.ipynb b/content/github/claude-cookbooks/misc/session_memory_compaction.ipynb index d2df602579..f9ca473bab 100644 --- a/content/github/claude-cookbooks/misc/session_memory_compaction.ipynb +++ b/content/github/claude-cookbooks/misc/session_memory_compaction.ipynb @@ -46,7 +46,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": { "vscode": { "languageId": "python" @@ -60,7 +60,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": { "vscode": { "languageId": "python" @@ -86,24 +86,30 @@ "languageId": "python" } }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/root/.pyenv/versions/3.13.11/lib/python3.13/site-packages/coconut/compiler/util.py:676: FutureWarning: functools.partial will be a method descriptor in future Python versions; wrap it in staticmethod() if you want to preserve the old behavior\n", - " return Regex(regex, options)\n", - "/root/.pyenv/versions/3.13.11/lib/python3.13/site-packages/coconut/compiler/util.py:457: FutureWarning: functools.partial will be a method descriptor in future Python versions; wrap it in staticmethod() if you want to preserve the old behavior\n", - " result = add_action(grammar, unpack).parseWithTabs().transformString(text)\n" - ] - } - ], + "outputs": [], "source": [ "# Helper functions\n", "def response_text(response) -> str:\n", " \"\"\"Return the text of a response. Responses can start with a thinking block, so this reads\n", - " the text blocks rather than content[0].\"\"\"\n", - " return \"\".join(block.text for block in response.content if block.type == \"text\")\n", + " the text blocks rather than content[0].\n", + "\n", + " Raises instead of returning \"\" so an empty assistant turn is never stored in the history\n", + " (the API rejects empty text blocks on the next request).\"\"\"\n", + " text = \"\".join(block.text for block in response.content if block.type == \"text\")\n", + " if not text.strip():\n", + " raise ValueError(\n", + " f\"Response has no text content (stop_reason={response.stop_reason!r}). \"\n", + " \"If stop_reason is 'max_tokens', thinking used the whole budget: raise max_tokens.\"\n", + " )\n", + " return text\n", + "\n", + "\n", + "def kept_output_tokens(usage) -> int:\n", + " \"\"\"Output tokens that end up in the conversation: usage.output_tokens minus thinking tokens,\n", + " which are billed as output but never stored in the message history.\"\"\"\n", + " details = getattr(usage, \"output_tokens_details\", None)\n", + " thinking_tokens = getattr(details, \"thinking_tokens\", 0) or 0\n", + " return usage.output_tokens - thinking_tokens\n", "\n", "\n", "def truncate_response(text: str, max_lines: int = 15) -> str:\n", @@ -275,18 +281,7 @@ "languageId": "python" } }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/root/.pyenv/versions/3.13.11/lib/python3.13/site-packages/coconut/compiler/util.py:403: FutureWarning: functools.partial will be a method descriptor in future Python versions; wrap it in staticmethod() if you want to preserve the old behavior\n", - " grammar.streamline()\n", - "/root/.pyenv/versions/3.13.11/lib/python3.13/site-packages/coconut/compiler/util.py:457: FutureWarning: functools.partial will be a method descriptor in future Python versions; wrap it in staticmethod() if you want to preserve the old behavior\n", - " result = add_action(grammar, unpack).parseWithTabs().transformString(text)\n" - ] - } - ], + "outputs": [], "source": [ "import time\n", "\n", @@ -312,12 +307,15 @@ " self.messages.append({\"role\": \"user\", \"content\": user_message})\n", " print(f\"\\nUser: {user_message}\")\n", "\n", - " response = client.messages.create(\n", + " # A thinking model can spend 10K+ tokens reasoning before a long draft, so give it a large\n", + " # budget and stream the reply (the SDK requires streaming for budgets this size).\n", + " with client.messages.stream(\n", " model=MODEL,\n", - " max_tokens=3500,\n", + " max_tokens=32000,\n", " system=self.system_message,\n", " messages=add_cache_control(self.messages),\n", - " )\n", + " ) as stream:\n", + " response = stream.get_final_message()\n", " assistant_message = response_text(response)\n", " self.messages.append({\"role\": \"assistant\", \"content\": assistant_message})\n", "\n", @@ -325,8 +323,10 @@ "\n", " # approximate current token count in the conversation before the next user message\n", " cache_read = getattr(response.usage, \"cache_read_input_tokens\", 0) or 0\n", - " total_input = response.usage.input_tokens + cache_read\n", - " self.current_context_window_tokens = total_input + response.usage.output_tokens\n", + " cache_write = getattr(response.usage, \"cache_creation_input_tokens\", 0) or 0\n", + " total_input = response.usage.input_tokens + cache_read + cache_write\n", + " # thinking tokens are not stored in self.messages, so kept_output_tokens() leaves them out\n", + " self.current_context_window_tokens = total_input + kept_output_tokens(response.usage)\n", "\n", " print(\n", " f\"Input={total_input:,}, Prompt cached used= {cache_read > 0} | \"\n", @@ -338,22 +338,23 @@ " def compact(self) -> None:\n", " start_time = time.perf_counter()\n", "\n", - " response = client.messages.create(\n", + " with client.messages.stream(\n", " model=MODEL,\n", - " max_tokens=5000,\n", + " max_tokens=32000,\n", " system=self.system_message, # Same as main chat for cache sharing\n", " messages=add_cache_control(self.messages)\n", " + [{\"role\": \"user\", \"content\": SESSION_MEMORY_PROMPT}],\n", - " )\n", + " ) as stream:\n", + " response = stream.get_final_message()\n", " elapsed = time.perf_counter() - start_time\n", "\n", " # Generate new summary message\n", " self.summary, removed_text = remove_thinking_blocks(\n", " response_text(response)\n", " ) # clean up any blocks because they are not needed in the session memory\n", - " approximate_summary_tokens = response.usage.output_tokens - round(\n", + " approximate_summary_tokens = kept_output_tokens(response.usage) - round(\n", " len(removed_text) / 4\n", - " ) # rough estimate of tokens removed from summary\n", + " ) # rough estimate: text output minus the block we stripped\n", "\n", " # Replace prior messages with new summary message\n", " self.messages = [\n", @@ -448,23 +449,23 @@ "User: I want to create a story about a young detective solving a mysterious case in a small town. Generate 3 well thought out plot ideas for me to consider.\n", "\n", "Assistant: \n", - "# Three Mystery Plot Ideas\n", - "\n", - "## 1. **The Vanishing Choir**\n", + "# Three Plot Concepts: Young Detective, Small Town\n", "\n", - "**Setup:** In the sleepy town of Millbrook, the entire church choir—twelve people ranging from teenagers to retirees—disappears during their weekly Thursday night practice. The church was locked from the inside, their belongings left behind, including phones and car keys. No signs of struggle, no broken windows. Just an empty sanctuary and sheet music scattered across the floor.\n", + "## 1. The Lighthouse Keeper's Ledger\n", "\n", - "**The Twist:** Your young detective discovers the choir members didn't disappear—they're hiding. Twenty years ago, they witnessed the town's beloved mayor commit a hit-and-run that killed a drifter. They stayed silent, bound by threats and their own complicity. Now the mayor is dying and has hired someone to ensure his secret dies with him. The choir staged their own disappearance to draw attention and finally confess, but the detective must figure out who they're hiding from before the killer finds them first.\n", + "**Setting:** Harrow's End, a fading fishing town on a foggy northern coast.\n", "\n", - "**Why it works:** Small-town secrets, a ticking clock, and the moral complexity of people who aren't quite innocent or guilty. The locked-room mystery becomes a desperate act of exposure rather than concealment.\n", + "**Detective:** Nell Okafor, 24, a newly appointed deputy who returned home after failing out of a big-city police academy. She's underestimated by everyone, including herself.\n", "\n", - "---\n", + "**The Case:** The town's retired lighthouse keeper, Abel Rusk, is found dead at the base of the tower, an apparent fall. But his meticulously kept weather ledger has a page torn out, and the final entry is dated three days *after* his death.\n", "\n", - "## 2. **The Memory Thief**\n", + "**How It Unfolds:**\n", + "- Nell discovers Abel wasn't just logging weather. He was recording the nighttime comings and goings of boats that never appeared in the harbor records.\n", + "- Each lead points to a different respected townsperson: the harbormaster, the cannery owner, the beloved pastor.\n", + "- The mystery deepens when she realizes the post-death entry was written by someone who knew Abel's shorthand, which only his estranged daughter and Nell's own late father ever learned.\n", "\n", - "**Setup:** Elderly residents in Hartwood are reporting identical \"robberies\"—but nothing is actually stolen. Instead, they insist specific memories have been taken: a first kiss, a wedding day, the birth of a child. The police dismiss it as dementia until the detective notices a pattern: all victims visited the same new \"reminiscence therapist\" who uses experimental techniques to help seniors preserve their memories before they fade.\n", - "... (18 more lines)\n", - "Input=317, Prompt cached used= False | Output=852 | Messages=2\n", + "... (49 more lines)\n", + "Input=444, Prompt cached used= False | Output=1,791 | Messages=2\n", "==============================================\n", "Turn 2:\n", "\n", @@ -472,18 +473,23 @@ "User: I don't like those ideas, can you think of one plot something more unique and unexpected?\n", "\n", "Assistant: \n", - "# **The Cartographer's Grave**\n", + "# The Drought Year\n", "\n", - "**Setup:** Your young detective arrives in the mountain town of Ridgeway to investigate what seems like a prank: someone has been systematically correcting the town's street signs, storefront addresses, and property markers—changing them by just one or two numbers. The post office is going insane. Mail is being misdelivered. Emergency services are getting lost. But here's the thing: the \"corrections\" match a 150-year-old town map that was supposedly drawn incorrectly by a disgraced surveyor who was run out of town and buried in an unmarked grave.\n", + "## The Hook\n", "\n", - "**The Investigation:** The detective discovers the old surveyor wasn't wrong—he was *right*. The town founders deliberately falsified all records after his death, shifting every address, every property line, every boundary marker. Why? Because the real map would reveal that the town's most valuable land—now home to the founding families' estates, the town hall, the historic church—was actually purchased from a Native American family who were supposed to retain mineral rights and a percentage of all profits in perpetuity. \n", + "Calder Bend sits on the edge of a reservoir that has been dropping for months. Beneath the water lies Old Calder, the original town, flooded in 1978 so the new one could have a water supply. Then the doorsteps start filling up.\n", "\n", - "**The Twist:** The person \"correcting\" the signs isn't a descendant of the surveyor or the Native family. It's a twelve-year-old girl with terminal cancer who found the original map in her grandmother's attic. She's not seeking revenge or restitution—she just became obsessed with the idea that the whole town has been living a lie written into the ground itself. Before she dies, she wants the truth to physically exist in the world, even if no one acknowledges it. She's been sneaking out at night with a screwdriver and homemade signs.\n", + "Every morning, a different family in town finds a waterlogged object on their porch, arranged with care: a child's shoe, a church hymnal swollen shut, a brass house number, a barber's chair bolt. Nothing is stolen, no one is threatened, and there are no footprints. The only trace is a trail of silt and the smell of lake bed.\n", "\n", - "**The Real Mystery:** The detective must decide what to do when they realize that \"solving\" the case—stopping the girl and restoring the false addresses—means choosing comfortable order over inconvenient truth. Meanwhile, members of the founding families are getting desperate to stop the corrections before anyone looks too closely at land deeds, and the girl's nightly trips are getting increasingly dangerous.\n", + "## The Detective\n", "\n", - "**Why it works:** It subverts the detective genre by making the \"crime\" an act of radical honesty. The mystery isn't whodunit—it's what truth is worth when it would destroy an entire community's foundation. The villain isn't the child or even really the founding families—it's the town itself, built on a literal lie. And your detective can't punch or outwit their way out of a moral knot.\n", - "Input=1,191, Prompt cached used= False | Output=544 | Messages=4\n", + "**Odile \"Dilly\" Marsh, 19**, works for the county surveyor's office, measuring the dropping waterline and mapping what's newly exposed. She isn't police, but the sheriff considers the deliveries a nuisance prank and is happy to let the \"water girl\" poke around. Her access to the lake bed and old survey maps makes her the only person who can trace where the objects came from.\n", + "\n", + "## How It Unfolds\n", + "\n", + "- Dilly matches each object to a specific address in Old Calder. The deliveries aren't random. Each lands on the doorstep of the **descendant of a family that lived at that address**, and the order follows Old Calder's streets, like a procession walking toward something.\n", + "... (32 more lines)\n", + "Input=2,168, Prompt cached used= False | Output=3,425 | Messages=4\n", "==============================================\n", "Turn 3:\n", "\n", @@ -491,23 +497,23 @@ "User: Ok I like it. Can you help me develop the main character's backstory and motivations?\n", "\n", "Assistant: \n", - "# The Detective: Building Your Protagonist\n", + "# Odile \"Dilly\" Marsh: Character Development\n", "\n", - "## Core Identity\n", + "## Core Concept\n", "\n", - "Let's call her **Nora Winters** (adjust the name as you prefer). She's 26 years old, which makes her young enough to be underestimated but old enough to have scars.\n", + "Dilly is a girl who trusts records because her whole family was built on one that was forged. She doesn't know that yet. She believes maps, surveys, and measurements are the one honest thing in a town that runs on what people don't say. The story takes that belief apart.\n", "\n", "## Backstory\n", "\n", - "**The Personal Lie:** Nora grew up in a different small town where her father was the police chief—respected, beloved, the kind of man who coached Little League and knew everyone's name. When she was sixteen, she discovered he'd been planting evidence on suspects for years. Not major crimes—small-town stuff. A little weed here, stolen property there. Just enough to \"help\" cases along when he \"knew\" someone was guilty but couldn't prove it.\n", + "**Raised by Hester.** Dilly's mother, Renata, left Calder Bend at seventeen, pregnant and furious at a town that \"smiled over everything.\" She came back when Dilly was three, stayed four years, then left again for good, sending birthday cards and the occasional check. Dilly was raised by her grandparents. Her father is a blank, so she carries the Marsh name.\n", "\n", - "She confronted him. He told her the truth was \"complicated,\" that sometimes you have to bend the rules to protect people, that the town trusted him to keep them safe and he delivered results. He made her complicit with his confession—if she exposed him, she'd destroy their family, his legacy, the town's faith in law enforcement.\n", + "**Walter, the clerk.** Her grandfather Walter was the council clerk and the most important person in her childhood. He taught her to read plat maps at the kitchen table, let her use his brass ruler and embossing seal, and told her, \"A thing written down properly stays true.\" He died when she was eleven. She has kept his ruler ever since. This is the story's central irony: the man who taught her to trust paper was the man who falsified it.\n", "\n", - "She stayed silent. For two years, she carried it like a stone in her chest.\n", + "**The town under the water.** Hester kept a drawer of Old Calder maps and told Dilly its streets the way other grandmothers tell fairy tales: where the bakery stood, which block flooded in the spring of '52. Dilly grew up homesick for a place she never saw. She can walk Old Calder's streets from memory, which makes her the only person who can read the deliveries as a route.\n", "\n", - "**The Breaking Point:** At eighteen, one of her father's frame jobs went wrong. A kid he planted drugs on—a 19-year-old with priors who was actually clean this time—panicked during arrest and ran. Got hit by a car. Died in the street.\n", - "... (50 more lines)\n", - "Input=1,758, Prompt cached used= False | Output=1,193 | Messages=6\n", + "**The silences, in retrospect.** Hester never went near the reservoir. She kept the lake-side curtains drawn, wouldn't let Dilly swim, and left the room when the anniversary of the flooding was mentioned. Dilly read this as grief for a drowned hometown. It was guilt. Readers can catch this on a second read, and Dilly can recognize it in a gut-punch moment mid-story.\n", + "... (54 more lines)\n", + "Input=3,669, Prompt cached used= True | Output=3,639 | Messages=6\n", "==============================================\n", "Turn 4:\n", "\n", @@ -515,23 +521,23 @@ "User: Can you draft a detailed outline for the story, breaking it down into chapters and key events?\n", "\n", "Assistant: \n", - "# **The Cartographer's Grave: Story Outline**\n", - "\n", - "## **ACT ONE: The Map Doesn't Match the Territory**\n", - "\n", - "### **Chapter 1: Arrival**\n", - "- Nora arrives in Ridgeway on a grey October morning, six-hour drive from the city\n", - "- Establishes the town: population 3,200, nestled in mountain valley, tourism from fall foliage and \"historic charm\"\n", - "- She meets Town Manager **Gerald Vance** (55, anxious, sweating through his shirt despite the cold) at town hall\n", - "- He explains the crisis: for three weeks, someone's been changing street signs and address numbers—small changes, but creating chaos\n", - "- Mail misdelivered, ambulance went to wrong house (patient survived, barely), legal documents being contested\n", - "- Shows her examples: the church changed from 847 Oak Street to 843 Oak, the post office from 1215 Main to 1219 Main\n", - "- Gerald thinks it's vandalism, wants her to catch whoever's doing it quickly and quietly\n", - "- **Key detail:** Nora notices all the \"corrections\" subtract or add small, specific numbers—not random\n", - "\n", - "### **Chapter 2: The Town's Memory**\n", - "... (160 more lines)\n", - "Input=2,973, Prompt cached used= False | Output=3,500 | Messages=8\n", + "# The Drought Year: Story Outline\n", + "\n", + "**Structure:** 10 chapters across 9 days, with the falling water as the clock. At roughly 900-1,200 words each, that's a 9-10k-word novelette. If you want a tighter short story, I can compress it to 5-6 scenes.\n", + "\n", + "**One change from earlier:** I suggested the first shoe might land on Dilly's porch. I now think that gives away too much. The first delivery goes to a neighbor, and the Marsh house isn't visited until the midpoint.\n", + "\n", + "---\n", + "\n", + "## The Deliveries\n", + "\n", + "| Day | Object | Recipient | Its meaning to Hester |\n", + "|---|---|---|---|\n", + "| 1 | Child's shoe | Pruitt family | The council chairman's daughter, who lost it the night the whole town gathered to watch the gates close |\n", + "| 2 | Swollen hymnal | Ames family | The reverend blessed the closing |\n", + "| 3 | Brass house number | Kessler family (the sheriff's) | The constable locked Wend's door and escorted him out |\n", + "... (104 more lines)\n", + "Input=5,890, Prompt cached used= True | Output=8,912 | Messages=8\n", "==============================================\n", "Turn 5:\n", "\n", @@ -539,47 +545,56 @@ "User: Can you draft me a first chapter based on the plot and character ideas we've discussed so far? Make it around 2,000 words.\n", "\n", "Assistant: \n", - "# **Chapter 1: Arrival**\n", + "# Chapter One: Low Water\n", "\n", - "The town of Ridgeway materialized from the fog like a photograph developing in reverse—sharp edges first, then the softer details filling in around them. Church steeple. Water tower. The downtown strip with its brick facades and hand-painted signs promising antiques, locally roasted coffee, genuine mountain crafts. Nora Winters took it all in through rain-spattered windshield glass, her Honda's wipers beating a rhythm that had become hypnotic somewhere around hour five of the drive.\n", + "By six in the morning the lake had dropped another two inches, and Dilly Marsh was probably the only person in Calder Bend who cared.\n", "\n", - "Small towns always looked the same in October. Like they were apologizing for something.\n", + "She stood at the end of the county boat ramp, which no longer ended at water. The concrete ran past its last painted stripe and the rusted marker post, then down a slope of cracked gray clay before it finally met the lake. She had paced it off with the staff gauge over her shoulder, counting under her breath. Seventy-four paces and a bit. Yesterday it had been seventy-three.\n", "\n", - "She followed Main Street through the heart of downtown—two blocks of calculated charm before the road narrowed and climbed into the residential neighborhoods climbing the mountain's flank. The GPS on her phone had lost signal fifteen minutes ago, but she didn't need it. Town hall would be near the center, probably the biggest building on the main drag, probably with a flag and that particular kind of municipal architecture that tried too hard to look historic.\n", + "\"Eleven twenty-eight point one,\" she said, and wrote it down.\n", "\n", - "She was right on all counts.\n", + "Thirty-two feet below full pool. The reservoir had been shrinking since May, and the county had stopped calling it a dry spell around the time the marina closed. Now the newspaper said *drought*, and the older people in town said nothing at all, which Dilly had learned was how they said the worst things.\n", "\n", - "Ridgeway Town Hall occupied a corner lot with the self-importance of a building that had watched the world change and declined to participate. Red brick, white columns, a bronze plaque declaring it built in 1889 and placed on the National Register in 1976. The flag snapped in the wind. Rain pooled in the uneven sidewalk leading to the entrance.\n", + "She turned and looked out across what the water had given back.\n", "\n", - "Nora parked on the street, grabbed her messenger bag, and made the dash to the covered entrance. The door was heavier than it looked—solid oak, brass hardware—and opened into the particular smell of old public buildings: lemon polish, ancient radiator heat, and paper slowly yellowing in filing cabinets.\n", + "Old Calder lay below her in the early light, gray and unfinished, like a photograph left too long in a drawer. Front Street came up out of the lake in a long pale ribbon, its curbs still crisp. Beside it ran the foundations of buildings, rows of low stone rectangles, each with its doorstep still in place. A line of cottonwood stumps, silvered and bare, marked a boulevard no one had walked in forty-six years. Farther out, where the street dipped back under, a single set of church steps climbed out of the mud and led nowhere.\n", "\n", - "A woman at the reception desk looked up from her computer. Sixty-something, reading glasses on a beaded chain, cardigan against the over-aggressive heating system. Her smile was professional and tired in equal measure.\n", - "... (118 more lines)\n", - "Input=6,509, Prompt cached used= False | Output=3,073 | Messages=10\n", + "She knew every block of it. That was the strange part, and she never mentioned it at work. She had never seen Old Calder until this summer, and she could have walked it blindfolded. Hester had given it to her in pieces, over oatmeal and dishes and long evenings: *the bakery stood there, Dilly, the one with the green awning. That's where your grandfather bought me a lemon tart when he was courting.* Other children got fairy tales. Dilly got street names.\n", + "... (108 more lines)\n", + "Input=9,817, Prompt cached used= True | Output=5,840 | Messages=10\n", "==============================================\n", "Turn 6:\n", "\n", "\n", + "🧹 Context window at 13343 tokens. Limit exceeded, compacting session memory...\n", + "\n", + "------------------------------------------------------------\n", + "📝 New session memory created.\n", + "✅ Tokens reduced: 13,343 → 3227 (10,116 tokens saved, 76% reduction)\n", + "⏱️ Compaction time: 26.55s (user waiting...)\n", + " Cache used: True\n", + "------------------------------------------------------------\n", + "\n", "User: Can you draft a second chapter that builds on the first one, introducing a new twist in the mystery?\n", "\n", "Assistant: \n", - "# **Chapter 2: The Town's Memory**\n", + "# Chapter 2: The Hymnal\n", "\n", - "Nora woke at six to the sound of rain that had never really stopped, just paused to gather its strength. She'd fallen asleep at the small desk by the window, tablet still glowing with Gerald's documentation, her neck complaining about the angle she'd maintained for however many hours.\n", + "The lake had dropped another three-tenths of a foot overnight. Eleven twenty-seven point eight. Dilly wrote it in the green notebook at 6:12 a.m., standing in the same spot on the boat ramp as the day before, and felt a small, unworthy satisfaction that the number had behaved.\n", "\n", - "The numbers were still dancing behind her eyes. She'd spent half the night building spreadsheets, mapping the changes, looking for the pattern Gerald had sensed but couldn't articulate. And she'd found it—or the beginning of it. Every changed address was in the older part of town, pre-1900 construction. Every change was small but specific: sometimes adding four, sometimes subtracting two, once adding seven. Not random. Definitely not random.\n", + "The phone buzzed before she'd capped her pen.\n", "\n", - "She showered, changed into clean jeans and a sweater, and followed the smell of coffee downstairs.\n", + "\"Pell Street,\" Sheriff Kessler said. \"The Ames place. We've got another one.\"\n", "\n", - "The dining room was small and warmly lit, with four tables covered in white cloth. An older man sat alone by the window reading a newspaper—actual paper, folded precisely. A younger couple occupied another table, speaking in low voices over their phones. Tourists, Nora guessed, based on the hiking boots and Patagonia fleeces.\n", + "\"Same kids?\"\n", "\n", - "A sideboard held coffee, tea, juice, and a modest breakfast spread. Nora filled a mug and took a table in the corner where she could see the room and the street beyond.\n", + "\"Don't start.\"\n", "\n", - "Dolores appeared from what must have been the kitchen, carrying a plate of scrambled eggs and toast. She set it in front of the man with the newspaper without being asked, received a grunt of acknowledgment, and crossed to Nora's table.\n", + "The Ames house was yellow, with a deep porch and a swing that hadn't been sat in for years. Lorraine Ames stood on the top step in a quilted robe with her arms crossed, as if the porch were hers and the object on it were trespassing. It lay on the rail on a folded bath towel, which was soaked through.\n", "\n", - "\"You look like you didn't sleep much.\"\n", - "... (171 more lines)\n", - "Input=9,606, Prompt cached used= True | Output=3,241 | Messages=12\n" + "\"I put the towel down because it was dripping on the mat,\" she said. \"I don't know why I bothered. Tell me what it is, Odile, because I'm not touching it again.\"\n", + "... (165 more lines)\n", + "Input=3,530, Prompt cached used= False | Output=11,291 | Messages=3\n" ] } ], @@ -612,14 +627,16 @@ "source": [ "This is a long conversation with several turns. You'll notice a few things here:\n", "\n", - "Prompt caching: You'll notice here that the input tokens eventually grew to a point where prompt caching was used (turn 6). This helps reduce costs and speed as these conversations grow!" + "Prompt caching: You'll notice here that the input tokens quickly grew to a point where prompt caching was used (by turn 3). This helps reduce costs and speed as these conversations grow!\n", + "\n", + "Compaction: by turn 6 the conversation had crossed our 10K context window limit, so the session stopped to compact before it could answer, and the user waited the whole time." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "On the next turn, we are going to hit our 10K context window limit, which triggers compaction:" + "Whenever a turn starts above the 10K limit, the user waits for compaction before getting an answer; in the run above that happened on turn 6. The next turn carries on from the compacted session memory:" ] }, { @@ -635,36 +652,25 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", - "🧹 Context window at 12847 tokens. Limit exceeded, compacting session memory...\n", - "\n", - "------------------------------------------------------------\n", - "📝 New session memory created.\n", - "✅ Tokens reduced: 12,847 → 1526 (11,321 tokens saved, 88% reduction)\n", - "⏱️ Compaction time: 41.42s (user waiting...)\n", - " Cache used: True\n", - "------------------------------------------------------------\n", "\n", "User: Propose a title for the book\n", "\n", "Assistant: \n", - "Based on the story's core themes and imagery, here are my title proposals:\n", - "\n", - "## Primary Recommendation\n", + "# Title Proposals\n", "\n", - "**The Cartographer's Daughter**\n", + "**My top pick: *A Thing Written Down Properly***\n", + "This is Walter's line, and the story's central irony. Dilly believes a written record stays true, but the record that matters most is a forgery, and she ends up forging one herself before correcting it. The title sounds calm and bureaucratic, which suits the mystery's understated tone, and the meaning turns darker as the story goes on. It's also a quiet fit for the ending, when Dilly's notebook finally holds words instead of measurements.\n", "\n", - "This works on multiple levels:\n", - "- Emma is metaphorically Amos Frost's \"daughter\" in mission—inheriting and completing his work\n", - "- Patricia (literal descendant of Frost's assistant) becomes Emma's accomplice\n", - "- Evokes the weight of inheritance, legacy, and what we pass down\n", - "- \"Cartographer\" immediately signals the map/truth theme\n", - "- Has literary gravitas appropriate for the story's tone\n", + "**Other options**\n", "\n", - "## Alternates\n", + "- ***Dead Pool***: A real reservoir term for water that has dropped below the outlet and can no longer flow downstream. It works as both a technical term and a hint at the body in the pumphouse cellar. It's the most genre-forward choice, but a bit blunt for the prose style we've established.\n", + "- ***Full Pool***: The opposite term, for a reservoir at capacity. It suggests the town's whole history rests on a lake kept full at any cost. It's subtler, but less intriguing on a cover.\n", + "- ***Below the 1,140 Line***: Taken from the last line of Chapter 1. It's specific and atmospheric, and it makes readers wonder what lies below the line. It's a little clinical as a book title.\n", + "- ***Proceed***: One word, from Harold Pruitt's pencil note. It's sharp and ominous, and it implies the town's complicity. It might be too cryptic before the reader has context.\n", + "- ***The Water Girl***: Dilly's nickname. It puts the protagonist first, but it sounds like a different, lighter book, and it undersells the story's moral weight.\n", "\n", - "... (20 more lines)\n", - "Input=1,813, Prompt cached used= False | Output=328 | Messages=3\n" + "**My recommendation:** *A Thing Written Down Properly*, with *The Drought Year* kept as the working title in the outline. If you'd rather have something shorter and more commercial, *Dead Pool* is the strongest alternative.\n", + "Input=7,728, Prompt cached used= True | Output=1,086 | Messages=5\n" ] } ], @@ -676,9 +682,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "You'll notice here that it took **over 40 seconds** for the agent to compact the conversation. Because we used traditional compaction, the user would be waiting on Claude to compact the conversation, which is not an ideal user experience.\n", + "You'll notice above that it took **over 25 seconds** for the agent to compact the conversation. Because we used traditional compaction, the user would be waiting on Claude to compact the conversation, which is not an ideal user experience.\n", "\n", - "Below you can see the result of the compaction. It captures the key elements of conversation in less than 2K tokens." + "Below you can see the result of the compaction. It captures the key elements of the conversation in roughly 3K tokens." ] }, { @@ -695,74 +701,99 @@ "output_type": "stream", "text": [ "## User Intent\n", - "Create short story about young detective solving mysterious case in small town. Initially requested \"3 well thought out plot ideas.\" Rejected first batch as not unique enough, requested \"something more unique and unexpected.\" Accepted \"The Cartographer's Grave\" concept. Then requested: character backstory/motivations development, detailed chapter outline, and drafted chapters.\n", + "The user is developing a short story or novelette about a young detective in a small town. Original request: \"Generate 3 well thought out plot ideas.\" After rejecting those (\"I don't like those ideas, can you think of one plot something more unique and unexpected?\"), they approved \"The Drought Year\" (\"Ok I like it\"). They then requested, in order: protagonist backstory and motivations, a detailed chapter-by-chapter outline, and a Chapter 1 draft of \"around 2,000 words.\" The system role is lead writer: respectfully voice disagreements, defer to the author, and never ask for clarification (assume enough information to proceed).\n", "\n", "## Completed Work\n", - "\n", - "**Approved Plot: \"The Cartographer's Grave\"**\n", - "- Ridgeway (pop. 3,200, mountain town) experiencing systematic address changes\n", - "- 12-year-old Emma Lancaster (terminal brain cancer) changing signs at night to match 1874 surveyor Amos Frost's original map\n", - "- Frost was \"disgraced,\" replaced by Marcus Bellamy (founding family) in 1875 re-survey\n", - "- Real conspiracy: Bellamy survey deliberately shifted property lines 200-400 feet east to steal valuable land from Pequawket family (Native American), who had mineral rights + 15% revenue contract\n", - "- Emma found Frost's materials in grandmother's attic (Patricia Lancaster, granddaughter of Samuel Lancaster—Frost's assistant who bought his effects)\n", - "- Emma's motivation: not justice, but existential—wants to matter, leave truth behind before dying\n", - "- Resolution: Town acknowledges historical fraud via memorial/fund, addresses stay changed, Emma dies knowing truth survived\n", - "\n", - "**Main Character: Nora Winters**\n", - "- Age 26, private investigator for rural cases firm\n", - "- Backstory: Father was police chief who planted evidence for years. At 16 she discovered it, stayed silent 2 years. At 18, a framed kid died fleeing arrest. She exposed father to state police. Father forced into retirement but kept reputation. Family estranged, won't speak to her.\n", - "- Motivation: Prove truth always matters, atone for 2 years of silence\n", - "- Fatal flaw: Prioritizes truth over mercy, can be self-righteous\n", - "- Arc: Must learn truth and justice aren't always same thing\n", - "\n", - "**Supporting Characters**\n", - "- Gerald Vance (55, town manager, anxious)\n", - "- Dolores Chen (68, Ridgeway Inn owner, knows everything)\n", - "- Ruth Bellamy (72, historical society president, descendant of Marcus Bellamy)\n", - "- Sheriff Tom Whitlock (50, third-generation sheriff, dismissive)\n", - "- Emma Lancaster (12, dying of brain cancer, changing signs)\n", - "- Patricia Lancaster (64, Emma's grandmother, retired town clerk, Samuel Lancaster's descendant)\n", - "- James Pequawket (58, teacher, lives two towns over, descendant)\n", - "- Samuel Lancaster (Amos Frost's 1874 assistant, bought Frost's effects after death)\n", - "- Amos Frost (surveyor, accurate 1874 map, died 1889 in sanitarium, unmarked grave)\n", - "\n", - "**16-Chapter Outline with Epilogue Created**\n", - "- Act 1 (Ch 1-4): Nora arrives, discovers pattern, identifies Emma via dropped notebook\n", - "- Act 2 (Ch 5-9): Confronts Emma, discovers Frost's journal/map at Lancaster house, uncovers full conspiracy\n", - "- Act 3 (Ch 10-15): Town pressures Nora, founding families threaten charges against Emma, Nora proposes compromise (memorial + fund vs. property transfers), Emma dies December 3rd\n", - "- Epilogue (Ch 16): Six months later, Nora receives Emma's notebook showing new project mapping unmarked graves\n", - "\n", - "**Chapter 1 Drafted (~2000 words)**\n", - "- Nora arrives Ridgeway in rain, meets Gerald Vance at town hall\n", - "- Gerald explains crisis: 37 locations, professional signs, started October 2nd, systematic pattern\n", - "- Key detail: Changes are small (1-5 numbers) but precise, affecting only pre-1900 buildings\n", - "- Nora checks into Ridgeway Inn, meets Dolores Chen\n", - "- Dolores reveals her address changed October 3rd: 843 to 847 Oak Street, left new sign up to \"adapt\"\n", - "- Dolores warns: \"Be careful asking questions here. Not everyone appreciates having their complications examined.\"\n", - "\n", - "**Chapter 2 Drafted**\n", - "- Nora analyzes data overnight, identifies pattern: all changes in pre-1900 areas\n", - "- Breakfast at inn, confronted by Howard Marsh (70s, opposed to investigation)\n", - "- Visits library, meets Jess (librarian, 30, supportive)\n", - "- Discovers in basement archives: changed addresses match 1875 town plat exactly\n", - "- Jess reveals history: Amos Frost surveyed 1874, deemed \"inaccurate,\" dismissed. Marcus Bellamy (Ruth's great-great-grandfather) re-surveyed 1875 (official record). Frost's survey \"destroyed years ago.\"\n", - "- Text from Jess's partner Sarah: Frost died 1889 in sanitarium, pauper's grave. Effects purchased by Samuel Lancaster at 1847 Oak Street.\n", - "- **Chapter ends with revelation**: 1847 Oak = current \"corrected\" address of Ridgeway Inn (officially 843). Frost's materials likely still at inn. \"The question was who in that building knew they existed, and why they'd decided—after more than a century of silence—that the truth needed to be rewritten into the town's streets.\"\n", + "- **3 initial plots** (rejected, do not reuse).\n", + "- **Premise, \"The Drought Year\":** Calder Bend sits beside a reservoir that is dropping in a drought. Old Calder, flooded in 1978, is resurfacing. Each morning a waterlogged Old Calder object appears on the porch of a descendant of the family tied to it. The deliveries follow Old Calder's Front Street toward the Wend property, which will surface in about a week.\n", + "- **Twist:** The culprit is Dilly's grandmother Hester, who has early dementia. In 1978 her husband Walter, the council clerk, forged Tobias Wend's \"relocation\" papers after Wend was sealed in the pumphouse cellar so the floodgates could close on schedule. Hester sleepwalks to the lake bed and delivers objects, a confession she cannot say aloud.\n", + "- **Dilly's character document:**\n", + " - Odile \"Dilly\" Marsh, 19, technician at the county surveyor's office, locally called \"the water girl.\" She calls Hester \"Hess.\"\n", + " - Mother Renata left at 17, returned when Dilly was 3, left again after 4 years, and sends cards and checks. Father unknown.\n", + " - Walter taught her to read plat maps and told her \"A thing written down properly stays true.\" He died when she was 11. She carries his brass ruler.\n", + " - She deferred a hydrology scholarship because of Hester's lapses.\n", + " - Lie she believes: \"If I keep the record clean and the people I love close, nothing can be taken from me.\" Need: accept that love sometimes means letting someone tell a devastating truth, and that she comes from complicity.\n", + " - Flaws: over-reliance on data, protective secrecy, retreat into estimating when emotional, stubborn pride.\n", + " - Habits: paces off distances, mutters figures, sketches objects in a waterproof field notebook instead of photographing them, dry speech.\n", + " - Key arc beat: she falsifies an official waterline reading, repeating Walter's act, then corrects it.\n", + "- **10-chapter outline over 9 days:**\n", + " - Ch1 Low Water (Day 1)\n", + " - Ch2 The Hymnal (Day 2): meets Gus Ferreira, the old surveyor; the hymnal is stolen from the evidence locker.\n", + " - Ch3 The Procession (Day 3): route extrapolated, six days until the Wend property surfaces; Wend's records show no new address, tax record, or death certificate.\n", + " - Ch4 The Daughter Returns (Day 4): Renata arrives and researches memory-care facilities; Gus says Walter's records \"never quite added up\"; Hester hums the hymn.\n", + " - Ch5 The Seal (Day 5, midpoint): the W.M. embossing seal appears on the Marsh porch; Dilly follows sleepwalking Hester at 2 a.m.\n", + " - Ch6 The Paper (Day 6): the relocation form is dated Oct 12, but the gates closed Oct 9.\n", + " - Ch7 The Falsified Reading (Days 6-7, low point): Dilly changes \"three days\" to \"three weeks\"; she fights with Renata.\n", + " - Ch8 Hess (Day 8): Hester is lucid, then asks \"Who are you?\" and answers to \"Hess\"; Renata reconciles; the sheriff arrives with a warrant.\n", + " - Ch9 The Water Drops (Days 8-9): the pumphouse surfaces early; Dilly corrects the record; Gus co-signs.\n", + " - Ch10 The Key (Day 9): Hester, Dilly, and Renata walk through the town; Hester places a small iron key on the Wend doorstep; Dilly writes non-measurement words in her notebook.\n", + " - Optional coda: Hester forgets it all.\n", + "\n", + "**Delivery table:**\n", + "\n", + "| Day | Object | Recipient | Meaning |\n", + "|---|---|---|---|\n", + "| 1 | Child's shoe | Pruitt family | The council chairman's daughter lost it the night the gates closed |\n", + "| 2 | Swollen hymnal | Ames family | The reverend blessed the closing |\n", + "| 3 | Brass house number | Kessler (sheriff) | The constable locked Wend's door |\n", + "| 4 | Barber's chair bolt | Dutton family | The council voted in his shop |\n", + "| 5 | Embossing seal \"W.M.\" | Marsh house | Walter forged the papers |\n", + "| 7 | Pump valve wheel | Ibsen family | The pumphouse operator sealed the cellar |\n", + "| 9 | Wend's front-door key | Wend doorstep | Hester kept it for over 40 years |\n", + "\n", + "- **Chapter 1 draft (\"Low Water\"), roughly 2,300 words:**\n", + " - Dilly paces the boat ramp and records the lake at \"Eleven twenty-eight point one,\" 32 ft below full pool.\n", + " - She describes Old Calder's Front Street, the stumps, and the church steps. She learned the town through Hester's stories.\n", + " - She carries Walter's ruler (\"W. MARSH\" stamped) in her vest.\n", + " - At home on Alder Lane: damp slippers by the door, silt in the hallway (Dilly assumes her own boots), the lake-facing curtain always drawn, thriving geraniums despite watering restrictions, and Hester confusing Wednesday and Thursday.\n", + " - At the Pruitt porch, Sheriff Dale Kessler (50s, gray mustache) calls it kids.\n", + " - Edna Pruitt (81-82) is unsurprised and says \"I couldn't say.\"\n", + " - Dilly sketches the shoe, measures it with the ruler at 4⅛ inches, and identifies fine deep-lake silt.\n", + " - Ends with the line: \"That's from below the 1,140 line.\"\n", "\n", "## Errors & Corrections\n", - "User explicitly rejected first 3 plot ideas: \"The Vanishing Choir,\" \"The Memory Thief,\" \"The Lighthouse Keeper's Daughter\"—deemed not unique/unexpected enough.\n", + "- First 3 plots were rejected; the user wanted something more unique and unexpected.\n", + "- The assistant changed its own earlier idea that the first shoe would land on Dilly's porch, so the Marsh house is not visited until the midpoint.\n", + "- No other user corrections so far.\n", "\n", "## Active Work\n", - "Chapter 2 completed. Story ready to continue with Chapter 3, which per outline should cover \"The Pattern\" where Nora stakes out locations and first spots Emma changing a sign.\n", + "Chapter 1 was just delivered. The assistant is awaiting user feedback. No partial or unfinished text exists.\n", "\n", "## Pending Tasks\n", - "Draft chapters 3-16 and epilogue per approved outline.\n", + "- Explicitly requested: none outstanding.\n", + "- Implied or offered:\n", + " - Revise Chapter 1 per feedback.\n", + " - Draft Chapters 2-10.\n", + " - Compress to 5-6 scenes if the user wants a short story.\n", + "- Open decisions for the user:\n", + " 1. Daylight ending, coda, or both.\n", + " 2. Show Wend's remains or leave them implied.\n", + " 3. Renata as reconciled ally (Ch8) vs. continued conflict.\n", + " 4. Does Dilly learn who her father is?\n", + " 5. How much does Renata know?\n", + " 6. Is one delivered object Dilly's family's?\n", "\n", "## Key References\n", - "**Critical addresses**: 843 Oak Street (official) / 847 Oak Street (corrected) = Ridgeway Inn location, Samuel Lancaster's 1874 address\n", - "**Timeline**: October 2nd changes start, story current timeframe October, Emma dies December 3rd, epilogue six months later\n", - "**The fraud mechanics**: Bellamy survey shifted all property lines 200-400 feet east, making Pequawket parcel appear worthless hillside while valuable land (now Bellamy estate, town hall, church) became \"legitimately\" owned by founding families\n", - "**Pequawket contract terms**: Mineral rights in perpetuity + 15% of all property values/business revenues from specified parcel\n" + "- **Characters:**\n", + " - Dilly Marsh (19)\n", + " - Hester Marsh (78, grandmother, white hair in a coil, blue cardigan, makes brown-sugar oatmeal)\n", + " - Walter Marsh (grandfather, council clerk, d. when Dilly was 11)\n", + " - Renata (mother)\n", + " - Sheriff Dale Kessler (keep him human, protecting his father's name and the town's peace)\n", + " - Gus Ferreira (old surveyor and mentor)\n", + " - Edna Pruitt\n", + " - Tobias Wend (last Old Calder holdout, \"relocated\" Oct 1978)\n", + " - Families: Pruitt, Ames, Dutton, Ibsen\n", + "- **Setting:** Calder Bend, Alder Lane (the Marsh home, 3 blocks from shore), Old Calder's Front Street. The flooding was in 1978, and the story is set about 46 years later. The gates closed Oct 9, 1978.\n", + "- **Motifs:**\n", + " - Walter's brass ruler: used in Ch1, abandoned in Ch6, retrieved at the end.\n", + " - \"Hess.\"\n", + " - The green field notebook: sketches, then words at the end.\n", + " - The altered record.\n", + " - Damp slippers, silt, and the drawn curtain (planted clues).\n", + " - The geranium watering (Hester out with the hose) may be a minor added clue.\n", + "- **Style:** Close third person, past tense, understated and atmospheric. Dilly is dry, factual, and counts things.\n", + "- **Continuity note:** In Ch1 the lake is at 1,128.1 ft, and the \"1,140 line\" silt was exposed about six weeks earlier. Keep elevations consistent.\n" ] } ], @@ -830,18 +861,7 @@ "languageId": "python" } }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/root/.pyenv/versions/3.13.11/lib/python3.13/site-packages/coconut/compiler/util.py:403: FutureWarning: functools.partial will be a method descriptor in future Python versions; wrap it in staticmethod() if you want to preserve the old behavior\n", - " grammar.streamline()\n", - "/root/.pyenv/versions/3.13.11/lib/python3.13/site-packages/coconut/compiler/util.py:457: FutureWarning: functools.partial will be a method descriptor in future Python versions; wrap it in staticmethod() if you want to preserve the old behavior\n", - " result = add_action(grammar, unpack).parseWithTabs().transformString(text)\n" - ] - } - ], + "outputs": [], "source": [ "import threading\n", "import time\n", @@ -881,6 +901,7 @@ "\n", " # Background update tracking\n", " self._update_thread: threading.Thread | None = None\n", + " self._compactions = 0 # bumped by compact(); lets an in-flight update notice it went stale\n", " self.last_update_time = None\n", " self._lock = threading.Lock()\n", "\n", @@ -892,28 +913,32 @@ "\n", " self.messages.append({\"role\": \"user\", \"content\": user_message})\n", "\n", - " response = client.messages.create(\n", + " # Large budget + streaming, as in the traditional session: thinking can run 10K+ tokens\n", + " with client.messages.stream(\n", " model=MODEL,\n", - " max_tokens=3500,\n", + " max_tokens=32000,\n", " system=self.system_message,\n", " messages=add_cache_control(self.messages),\n", - " )\n", + " ) as stream:\n", + " response = stream.get_final_message()\n", "\n", " assistant_message = response_text(response)\n", " self.messages.append({\"role\": \"assistant\", \"content\": assistant_message})\n", "\n", " # Calculate token usage including cache\n", " cache_read = getattr(response.usage, \"cache_read_input_tokens\", 0) or 0\n", - " total_input = response.usage.input_tokens + cache_read\n", + " cache_write = getattr(response.usage, \"cache_creation_input_tokens\", 0) or 0\n", + " total_input = response.usage.input_tokens + cache_read + cache_write\n", "\n", - " # Update context window tokens (includes cached tokens since they still count toward context)\n", - " self.current_context_window_tokens = total_input + response.usage.output_tokens\n", + " # Update context window tokens (includes cached tokens since they still count toward context;\n", + " # thinking tokens are not stored in self.messages, so kept_output_tokens() leaves them out)\n", + " self.current_context_window_tokens = total_input + kept_output_tokens(response.usage)\n", "\n", " # KEY DIFFERENCE: Trigger background memory update if needed proactively, before compaction is needed\n", " background_status = None\n", " if self._should_init_memory() or self._should_update_memory():\n", - " self._trigger_background_update()\n", - " background_status = \"initializing\" if self.session_memory is None else \"updating\"\n", + " if self._trigger_background_update():\n", + " background_status = \"initializing\" if self.session_memory is None else \"updating\"\n", "\n", " # Return usage info with cache stats\n", " return assistant_message, response.usage, background_status\n", @@ -937,12 +962,13 @@ " \"\"\"Generate initial session memory from messages.\"\"\"\n", " # Put compaction instructions in user message to share cache with main chat\n", " compaction_messages = [{\"role\": \"user\", \"content\": SESSION_MEMORY_PROMPT}]\n", - " response = client.messages.create(\n", + " with client.messages.stream(\n", " model=MODEL,\n", - " max_tokens=5000,\n", + " max_tokens=32000,\n", " system=self.system_message, # Same as main chat for cache sharing\n", " messages=add_cache_control(messages) + compaction_messages,\n", - " )\n", + " ) as stream:\n", + " response = stream.get_final_message()\n", " summary, _ = remove_thinking_blocks(\n", " response_text(response)\n", " ) # clean up any blocks because they are not needed in the session memory\n", @@ -961,13 +987,14 @@ " + f\"\"\"There is an existing session memory: {self.session_memory}. Return the entire session memory with updates to reflect new messages.\"\"\",\n", " }\n", " ]\n", - " response = client.messages.create(\n", + " with client.messages.stream(\n", " model=MODEL,\n", - " max_tokens=5000,\n", + " max_tokens=32000,\n", " system=self.system_message,\n", " messages=new_messages\n", " + compaction_update_messages, # you may want to use prompt caching instead, in which case you'd use add_cache_control(self.messages) here\n", - " )\n", + " ) as stream:\n", + " response = stream.get_final_message()\n", " updated_summary, _ = remove_thinking_blocks(\n", " response_text(response)\n", " ) # clean up any blocks because they are not needed in the session memory\n", @@ -976,7 +1003,11 @@ "\n", " # Background memory update methods\n", " def _background_memory_update(\n", - " self, messages_snapshot: list[dict], snapshot_index: int, current_tokens: int\n", + " self,\n", + " messages_snapshot: list[dict],\n", + " snapshot_index: int,\n", + " current_tokens: int,\n", + " generation: int,\n", " ) -> None:\n", " \"\"\"Run session memory update in a background thread.\"\"\"\n", " try:\n", @@ -995,6 +1026,14 @@ "\n", " # Update state (thread-safe)\n", " with self._lock:\n", + " if generation != self._compactions:\n", + " if generation + 1 != self._compactions:\n", + " return # compacted more than once since the snapshot: drop this result\n", + " # compact() ran once while this update was in flight. It kept the turns this\n", + " # update covers verbatim right after the summary message, so re-base the index\n", + " # onto the compacted list and keep the token baseline compact() set.\n", + " snapshot_index = 1 + (snapshot_index - last_index)\n", + " current_tokens = self.tokens_at_last_update\n", " self.session_memory = new_memory\n", " self.last_summarized_index = snapshot_index\n", " self.tokens_at_last_update = current_tokens\n", @@ -1004,10 +1043,10 @@ " print(f\" [Background] Error updating memory: {e}\")\n", "\n", " # This makes sure only one background update runs at a time. If one is already running, we skip starting another. If not, we start a new thread to do the update.\n", - " def _trigger_background_update(self):\n", - " \"\"\"Trigger a background session memory update.\"\"\"\n", + " def _trigger_background_update(self) -> bool:\n", + " \"\"\"Trigger a background session memory update. Returns False if one is already running.\"\"\"\n", " if self._update_thread is not None and self._update_thread.is_alive():\n", - " return\n", + " return False\n", "\n", " messages_snapshot = self.messages.copy()\n", " snapshot_index = len(messages_snapshot)\n", @@ -1015,10 +1054,16 @@ "\n", " self._update_thread = threading.Thread(\n", " target=self._background_memory_update,\n", - " args=(messages_snapshot, snapshot_index, current_tokens),\n", + " args=(messages_snapshot, snapshot_index, current_tokens, self._compactions),\n", " daemon=True,\n", " )\n", " self._update_thread.start()\n", + " return True\n", + "\n", + " def wait_for_background_update(self, timeout: float = 120.0) -> None:\n", + " \"\"\"Block until any in-flight background memory update finishes.\"\"\"\n", + " if self._update_thread is not None and self._update_thread.is_alive():\n", + " self._update_thread.join(timeout=timeout)\n", "\n", " # Function to compact\n", " def compact(self) -> None:\n", @@ -1029,7 +1074,7 @@ " if self.session_memory is None:\n", " if self._update_thread is not None and self._update_thread.is_alive():\n", " print(\" ⏳ Waiting for background memory update...\")\n", - " self._update_thread.join(timeout=30.0)\n", + " self.wait_for_background_update()\n", "\n", " if self.session_memory is None:\n", " print(\" ⚠️ No pre-built memory, creating synchronously...\")\n", @@ -1038,6 +1083,7 @@ " elapsed = time.perf_counter() - start\n", " print(f\" ⏱️ Took {elapsed:.2f}s (but should be instant normally!)\")\n", " self.last_summarized_index = len(self.messages)\n", + " self._compactions += 1 # an update still in flight predates this memory: drop it\n", "\n", " with self._lock:\n", " unsummarized = self.messages[self.last_summarized_index :]\n", @@ -1049,6 +1095,15 @@ " ]\n", " self.messages = summary_message + unsummarized\n", " self.last_summarized_index = 1\n", + " self._compactions += 1\n", + "\n", + " # Re-base the token bookkeeping on the compacted context (the next response replaces\n", + " # this estimate with real usage) so a background update can fire again before the\n", + " # limit is reached.\n", + " self.current_context_window_tokens = estimate_tokens(self.system_message) + sum(\n", + " estimate_tokens(m[\"content\"]) for m in self.messages\n", + " )\n", + " self.tokens_at_last_update = self.current_context_window_tokens\n", "\n", " print(f\"\\n{'=' * 60}\")\n", " print(f\"⚡ INSTANT COMPACTION! Messages: {prev_msg_count} → {len(self.messages)}\")\n", @@ -1065,7 +1120,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 11, "metadata": { "vscode": { "languageId": "python" @@ -1084,14 +1139,14 @@ "User: I want to create a story about a young detective solving a mysterious case in a small town. Generate 3 well thought out plot ideas for me to consider.\n", "\n", "Assistant: \n", - "# Three Mystery Plot Ideas\n", + "# Three Plot Concepts: Young Detective in a Small Town\n", "\n", - "## 1. **The Vanishing Choir**\n", - "... (36 more lines)\n", + "## 1. **The Lighthouse Keeper's Ledger**\n", + "... (54 more lines)\n", "\n", "Token Usage:\n", - " Input: 317 (new: 317, cached: 0)\n", - " Output: 902\n", + " Input: 444 (new: 444, cached: 0, cache write: 0)\n", + " Output: 1,768\n", " Messages: 2 | Memory: not yet\n", "\n", "============================================================\n", @@ -1100,14 +1155,14 @@ "User: I don't like those ideas, can you think of one plot something more unique and unexpected?\n", "\n", "Assistant: \n", - "# **The Forgetting House**\n", + "# **The Missing Tuesday**\n", "\n", - "**Setup:** Your young detective arrives in Ember Falls to investigate a string of burglaries—except the victims don't realize they've been robbed until weeks later. A woman discovers her wedding ring gone and insists she lost it yesterday, but security footage shows she hasn't worn it in a month. A man reports his grandfather's watch stolen, then his sister shows him photos proving he sold it himself at a pawn shop—which he has no memory of doing.\n", - "... (16 more lines)\n", + "**Setting:** Little Marrow, a town of 412 people, tucked in a valley with one road in and one road out\n", + "... (29 more lines)\n", "\n", "Token Usage:\n", - " Input: 1,241 (new: 1,241, cached: 0)\n", - " Output: 592\n", + " Input: 2,143 (new: 4, cached: 0, cache write: 2,139)\n", + " Output: 2,955\n", " Messages: 4 | Memory: not yet\n", "\n", "============================================================\n", @@ -1116,15 +1171,16 @@ "User: Ok I like it. Can you help me develop the main character's backstory and motivations?\n", "\n", "Assistant: \n", - "# Your Detective: Building From The Inside Out\n", + "# Wren Okafor: Character Development\n", "\n", - "## Core Identity\n", - "... (79 more lines)\n", + "## Snapshot\n", + "... (98 more lines)\n", "\n", "Token Usage:\n", - " Input: 1,856 (new: 1,856, cached: 0)\n", - " Output: 1,329\n", + " Input: 3,251 (new: 4, cached: 2,139, cache write: 1,108)\n", + " Output: 3,774\n", " Messages: 6 | Memory: not yet\n", + " ✓ Cache hit! 66% of input from cache\n", "\n", "============================================================\n", "Turn 4:\n", @@ -1132,55 +1188,65 @@ "User: Can you draft a detailed outline for the story, breaking it down into chapters and key events?\n", "\n", "Assistant: \n", - "# **The Forgetting House: Chapter Outline**\n", + "# The Missing Tuesday: Story Outline\n", "\n", - "---\n", - "... (272 more lines)\n", + "## Two Continuity Fixes First\n", + "... (105 more lines)\n", "\n", "Token Usage:\n", - " Input: 3,207 (new: 3,207, cached: 0)\n", - " Output: 3,500\n", + " Input: 5,646 (new: 4, cached: 3,247, cache write: 2,395)\n", + " Output: 11,304\n", " Messages: 8 | Memory: not yet\n", + " ✓ Cache hit! 58% of input from cache\n", + "\n", + " [Background] Proactively initializing session memory...\n", + " Context window: 8,843 tokens\n", "\n", + " [Background] Initial session memory created. Cache hit=True\n", "============================================================\n", "Turn 5:\n", "\n", "User: Can you draft me a first chapter based on the plot and character ideas we've discussed so far? Make it around 2,000 words.\n", "\n", "Assistant: \n", - "# **Chapter One: The Impossible Theft**\n", + "# Chapter 1: Tuesday, Allegedly\n", "\n", - "The apartment smelled like burnt coffee and old paper.\n", - "... (196 more lines)\n", + "Wren Okafor woke with her mouth tasting of pennies.\n", + "... (151 more lines)\n", "\n", "Token Usage:\n", - " Input: 6,743 (new: 6,743, cached: 0)\n", - " Output: 3,155\n", - " Messages: 10 | Memory: not yet\n", + " Input: 8,885 (new: 4, cached: 5,642, cache write: 3,239)\n", + " Output: 7,883\n", + " Messages: 10 | Memory: ready\n", + " ✓ Cache hit! 64% of input from cache\n", "\n", - " [Background] Proactively initializing session memory...\n", - " Context window: 9,898 tokens\n", + " [Background] Proactively updating session memory...\n", + " Context window: 12,877 tokens\n", "\n", - " [Background] Initial session memory created. Cache hit=True\n", + "\n", + "============================================================\n", + "⚡ INSTANT COMPACTION! Messages: 10 → 3\n", + " Session memory was pre-built (no wait time!)\n", + "============================================================\n", + " [Background] Session memory updated.\n", "============================================================\n", "Turn 6:\n", "\n", "User: Can you draft a second chapter that builds on the first one?\n", "\n", "Assistant: \n", - "# **Chapter Two: Rosemont Manor**\n", + "# Chapter 2: The Stranger in the Square\n", "\n", - "The house appeared through the trees like something from a postcard.\n", - "... (190 more lines)\n", + "St. Brendan's stood at the head of the square with its doors flung open, the way they were for funerals and the Christmas pageant, and it was from those doors that the noise was coming.\n", + "... (140 more lines)\n", "\n", "Token Usage:\n", - " Input: 9,914 (new: 5,818, cached: 4,096)\n", - " Output: 3,500\n", - " Messages: 12 | Memory: ready\n", - " ✓ Cache hit! 41% of input from cache\n", + " Input: 7,238 (new: 4, cached: 0, cache write: 7,234)\n", + " Output: 9,139\n", + " Messages: 5 | Memory: ready\n", "\n", " [Background] Proactively updating session memory...\n", - " Context window: 13,414 tokens\n", + " Context window: 10,961 tokens\n", "\n" ] } @@ -1209,14 +1275,17 @@ " # Calculate cache stats\n", " cache_read = getattr(usage, \"cache_read_input_tokens\", 0) or 0\n", " cache_created = getattr(usage, \"cache_creation_input_tokens\", 0) or 0\n", - " total_input = usage.input_tokens + cache_read\n", + " total_input = usage.input_tokens + cache_read + cache_created\n", "\n", " print(f\"{'=' * 60}\")\n", " print(f\"Turn {turn_count}:\")\n", " print(f\"\\nUser: {message}\")\n", " print(f\"\\nAssistant: \\n{truncate_response(response, max_lines=3)}\")\n", " print(\"\\nToken Usage:\")\n", - " print(f\" Input: {total_input:,} (new: {usage.input_tokens:,}, cached: {cache_read:,})\")\n", + " print(\n", + " f\" Input: {total_input:,} (new: {usage.input_tokens:,}, cached: {cache_read:,}, \"\n", + " f\"cache write: {cache_created:,})\"\n", + " )\n", " print(f\" Output: {usage.output_tokens:,}\")\n", " print(\n", " f\" Messages: {len(session.messages)} | Memory: {'ready' if session.session_memory else 'not yet'}\"\n", @@ -1235,7 +1304,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 12, "metadata": { "vscode": { "languageId": "python" @@ -1246,21 +1315,18 @@ "name": "stdout", "output_type": "stream", "text": [ - "\n", - "============================================================\n", - "⚡ INSTANT COMPACTION! Messages: 12 → 3\n", - " Session memory was pre-built (no wait time!)\n", - "============================================================\n", "\n", "User: What did we just talk about? Give me one sentence\n", "\n", "Assistant: \n", - "I drafted Chapter 2 where Casey arrives at Rosemont Manor, interviews Iris (who deflects questions about her past and shows moments of disorientation), and realizes through comparing photos that Iris Hale is definitely their missing grandmother Iris Whitmore.\n", + "We drafted Chapters 1 and 2 of *The Missing Tuesday*: Wren Okafor wakes to a \"Tuesday\" that is really Wednesday, with an unexplained wrist mark and an unread notebook page, then finds a bound stranger's body in the church, as Deputy Hal Brewer deflects and the silent townspeople watch, with notes on the clues planted along the way and an offer to move on to Chapter 3.\n", "\n", "Token Usage:\n", - " Input: 5,490 (new: 5,490, cached: 0)\n", - " Output: 60\n", - " Messages: 5 | Memory: ready\n" + " Input: 10,978 (new: 4, cached: 7,234, cache write: 3,740)\n", + " Output: 408\n", + " Messages: 7 | Memory: ready\n", + " ✓ Cache hit! 66% of input from cache\n", + " [Background] Session memory updated.\n" ] } ], @@ -1270,12 +1336,16 @@ "\n", "# Calculate cache stats\n", "cache_read = getattr(usage, \"cache_read_input_tokens\", 0) or 0\n", - "total_input = usage.input_tokens + cache_read\n", + "cache_created = getattr(usage, \"cache_creation_input_tokens\", 0) or 0\n", + "total_input = usage.input_tokens + cache_read + cache_created\n", "\n", "print(f\"\\nUser: {message}\")\n", "print(f\"\\nAssistant: \\n{truncate_response(response, max_lines=3)}\")\n", "print(\"\\nToken Usage:\")\n", - "print(f\" Input: {total_input:,} (new: {usage.input_tokens:,}, cached: {cache_read:,})\")\n", + "print(\n", + " f\" Input: {total_input:,} (new: {usage.input_tokens:,}, cached: {cache_read:,}, \"\n", + " f\"cache write: {cache_created:,})\"\n", + ")\n", "print(f\" Output: {usage.output_tokens:,}\")\n", "print(\n", " f\" Messages: {len(session.messages)} | Memory: {'ready' if session.session_memory else 'not yet'}\"\n", @@ -1283,14 +1353,18 @@ "\n", "if cache_read > 0:\n", " cache_pct = (cache_read / total_input) * 100\n", - " print(f\" ✓ Cache hit! {cache_pct:.0f}% of input from cache\")" + " print(f\" ✓ Cache hit! {cache_pct:.0f}% of input from cache\")\n", + "\n", + "# The last turn may have kicked off another background memory update. Wait for it so the\n", + "# notebook doesn't finish with the daemon thread still mid-request.\n", + "session.wait_for_background_update()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "You'll notice here that once we hit the context limit, the session memory was instantaly swapped in, meaning the user had zero waiting time for a response!" + "You'll notice that once the conversation hit the context limit (turn 6 above), the pre-built session memory was swapped in instantly, meaning the user had zero waiting time for a response! The background updates then kept the memory current for the turns that followed." ] }, { @@ -1459,20 +1533,21 @@ ], "metadata": { "kernelspec": { - "display_name": "Coconut", - "language": "coconut", - "name": "coconut" + "display_name": "Python 3", + "language": "python", + "name": "python3" }, "language_info": { "codemirror_mode": { - "name": "python", + "name": "ipython", "version": 3 }, - "file_extension": ".coco", - "mimetype": "text/x-python3", - "name": "coconut", - "pygments_lexer": "coconut", - "version": "3.0.2" + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.0" } }, "nbformat": 4, diff --git a/content/github/claude-cookbooks/misc/using_citations.ipynb b/content/github/claude-cookbooks/misc/using_citations.ipynb index 50b37cb838..400a6e386f 100644 --- a/content/github/claude-cookbooks/misc/using_citations.ipynb +++ b/content/github/claude-cookbooks/misc/using_citations.ipynb @@ -33,7 +33,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install anthropic --quiet" + "%pip install anthropic pymupdf --quiet" ] }, { diff --git a/content/github/claude-cookbooks/multimodal/getting_started_with_vision.ipynb b/content/github/claude-cookbooks/multimodal/getting_started_with_vision.ipynb index 0dc62a566f..6d2e2c3251 100644 --- a/content/github/claude-cookbooks/multimodal/getting_started_with_vision.ipynb +++ b/content/github/claude-cookbooks/multimodal/getting_started_with_vision.ipynb @@ -11,16 +11,16 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ - "%pip install anthropic IPython" + "%pip install anthropic httpx IPython" ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": {}, "outputs": [ { @@ -30,7 +30,7 @@ "" ] }, - "execution_count": 1, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -43,30 +43,29 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Upon the rocky shore, a beacon bright,\n", - "Its steadfast light a guide through darkest night.\n", - "While sun descends in hues of pink and red,\n", - "The lighthouse stands, a stalwart figure head.\n", + "**Lighthouse at Dusk**\n", "\n", - "The waves crash 'gainst the weathered stone below,\n", - "A ceaseless rhythm, ancient ebb and flow.\n", - "Yet still the tower remains, resolute,\n", - "A guardian watching, ever vigilant mute.\n", - "\n", - "The vast expanse of sea and sky surround,\n", - "Horizon's line where heaven meets the ground.\n", - "This timeless scene, a testament to might,\n", - "Of nature's power and the human fight.\n", - "\n", - "The lighthouse, proud amid the fading day,\n", - "Eternal symbol, showing safe the way.\n" + "The sun has slipped below the ocean's rim\n", + "And left a band of ember on the sea;\n", + "Above, the blue grows deep, the light grows dim,\n", + "Where one thin moon hangs pale and silently.\n", + "The water, hushed to silk, forgets its spray,\n", + "And lies like mist against the pitted stone,\n", + "Whose ancient face, worn hollow day by day,\n", + "Has borne the tide's long argument alone.\n", + "Upon the point, a striped and slender tower\n", + "Ignites its lamp against the coming night,\n", + "And holds through every slow and darkened hour\n", + "A promise kept in one small spark of light.\n", + " So when my own horizon dims to blue,\n", + " May some small light stand watch and guide me through.\n" ] } ], @@ -112,45 +111,47 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" ] }, - "execution_count": 3, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "IMAGE_URL = \"https://upload.wikimedia.org/wikipedia/commons/thumb/c/ca/Machu_Picchu%2C_Peru_%282018%29.jpg/2560px-Machu_Picchu%2C_Peru_%282018%29.jpg\"\n", + "IMAGE_URL = \"https://upload.wikimedia.org/wikipedia/commons/thumb/c/ca/Machu_Picchu%2C_Peru_%282018%29.jpg/1920px-Machu_Picchu%2C_Peru_%282018%29.jpg\"\n", "Image(url=IMAGE_URL)" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "The image depicts the ancient Inca city of Machu Picchu, perched high in the Andes Mountains of Peru. The well-preserved stone ruins, including terraces, plazas, and buildings, are set against a stunning backdrop of steep, verdant mountains under a partly cloudy sky.\n" + "This image shows the ancient Inca citadel of Machu Picchu in Peru, with its weathered stone buildings, terraced fields, and bright green central plaza perched on a mountain ridge. Behind the ruins rises the steep, vegetation-covered peak of Huayna Picchu, framed by lush Andean mountains under a vivid blue sky with scattered white clouds.\n" ] } ], "source": [ "import httpx\n", "\n", - "IMAGE_DATA = base64.b64encode(httpx.get(IMAGE_URL).content).decode(\"utf-8\")\n", + "image_response = httpx.get(IMAGE_URL, follow_redirects=True)\n", + "image_response.raise_for_status() # fail loudly instead of base64-encoding an error page\n", + "IMAGE_DATA = base64.b64encode(image_response.content).decode(\"utf-8\")\n", "\n", "message_list = [\n", " {\n", @@ -186,7 +187,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.12.14" } }, "nbformat": 4, diff --git a/content/github/claude-cookbooks/multimodal/reading_charts_graphs_powerpoints.ipynb b/content/github/claude-cookbooks/multimodal/reading_charts_graphs_powerpoints.ipynb index 3a2e6be93f..a146ff84ec 100644 --- a/content/github/claude-cookbooks/multimodal/reading_charts_graphs_powerpoints.ipynb +++ b/content/github/claude-cookbooks/multimodal/reading_charts_graphs_powerpoints.ipynb @@ -362,8 +362,13 @@ " }\n", "]\n", "\n", - "# Now we use our prompt to narrate the entire deck. Note that this may take a few minutes to run (often up to 10).\n", - "completion = get_completion(messages)" + "# Now we use our prompt to narrate the entire deck. A full narration of this 27-page deck runs well\n", + "# past 20K output tokens, so this call gets a much larger max_tokens budget than our helper and\n", + "# streams the response (the SDK requires streaming for requests this long). We keep the final\n", + "# message so we can check stop_reason below. Note that this may take a few minutes to run.\n", + "with client.messages.stream(model=MODEL_NAME, max_tokens=32000, messages=messages) as stream:\n", + " narration_response = stream.get_final_message()\n", + "completion = \"\".join(block.text for block in narration_response.content if block.type == \"text\")" ] }, { @@ -382,7 +387,10 @@ "if match:\n", " narration = match.group(1)\n", "else:\n", - " raise ValueError(\"No narration available. Likely due to the model response being truncated.\")" + " raise ValueError(\n", + " f\"No complete block found (stop_reason={narration_response.stop_reason!r}). \"\n", + " \"If stop_reason is 'max_tokens', the response was truncated: raise max_tokens above.\"\n", + " )" ] }, { diff --git a/content/github/claude-cookbooks/multimodal/using_sub_agents.ipynb b/content/github/claude-cookbooks/multimodal/using_sub_agents.ipynb index c1b58a9646..1a3c941538 100644 --- a/content/github/claude-cookbooks/multimodal/using_sub_agents.ipynb +++ b/content/github/claude-cookbooks/multimodal/using_sub_agents.ipynb @@ -19,7 +19,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -28,7 +28,7 @@ }, { "cell_type": "code", - "execution_count": 89, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -58,7 +58,7 @@ }, { "cell_type": "code", - "execution_count": 90, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -86,10 +86,72 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, "outputs": [], - "source": "# Function to download a PDF file from a URL and save it to a specified folder\ndef download_pdf(url, folder):\n response = requests.get(url, timeout=60)\n if response.status_code == 200:\n file_name = os.path.join(folder, url.split(\"/\")[-1])\n with open(file_name, \"wb\") as file:\n file.write(response.content)\n return file_name\n else:\n print(f\"Failed to download PDF from {url}\")\n return None\n\n\n# Define the function to convert a PDF to a list of base64-encoded PNG images\ndef pdf_to_base64_pngs(pdf_path, quality=75, max_size=(1024, 1024)):\n # Open the PDF file\n doc = fitz.open(pdf_path)\n\n base64_encoded_pngs = []\n\n # Iterate through each page of the PDF\n for page_num in range(doc.page_count):\n # Load the page\n page = doc.load_page(page_num)\n\n # Render the page as a PNG image\n pix = page.get_pixmap(matrix=fitz.Matrix(300 / 72, 300 / 72))\n\n # Convert the pixmap to a PIL Image\n image = Image.frombytes(\"RGB\", [pix.width, pix.height], pix.samples)\n\n # Resize the image if it exceeds the maximum size\n if image.size[0] > max_size[0] or image.size[1] > max_size[1]:\n image.thumbnail(max_size, Image.Resampling.LANCZOS)\n\n # Convert the PIL Image to base64-encoded PNG\n image_data = io.BytesIO()\n image.save(image_data, format=\"PNG\", optimize=True, quality=quality)\n image_data.seek(0)\n base64_encoded = base64.b64encode(image_data.getvalue()).decode(\"utf-8\")\n base64_encoded_pngs.append(base64_encoded)\n\n # Close the PDF document\n doc.close()\n\n return base64_encoded_pngs\n\n\n# Folder to save the downloaded PDFs\nfolder = \"../images/using_sub_agents\"\n\n\n# Create the directory if it doesn't exist\nos.makedirs(folder)\n\n# Download the PDFs concurrently\nwith ThreadPoolExecutor() as executor:\n pdf_paths = list(executor.map(download_pdf, pdf_urls, [folder] * len(pdf_urls)))\n\n# Remove any None values (failed downloads) from pdf_paths\npdf_paths = [path for path in pdf_paths if path is not None]" + "source": [ + "# Function to download a PDF file from a URL and save it to a specified folder\n", + "def download_pdf(url, folder):\n", + " response = requests.get(url, timeout=60)\n", + " if response.status_code == 200:\n", + " file_name = os.path.join(folder, url.split(\"/\")[-1])\n", + " with open(file_name, \"wb\") as file:\n", + " file.write(response.content)\n", + " return file_name\n", + " else:\n", + " print(f\"Failed to download PDF from {url}\")\n", + " return None\n", + "\n", + "\n", + "# Define the function to convert a PDF to a list of base64-encoded PNG images\n", + "def pdf_to_base64_pngs(pdf_path, quality=75, max_size=(1024, 1024)):\n", + " # Open the PDF file\n", + " doc = fitz.open(pdf_path)\n", + "\n", + " base64_encoded_pngs = []\n", + "\n", + " # Iterate through each page of the PDF\n", + " for page_num in range(doc.page_count):\n", + " # Load the page\n", + " page = doc.load_page(page_num)\n", + "\n", + " # Render the page as a PNG image\n", + " pix = page.get_pixmap(matrix=fitz.Matrix(300 / 72, 300 / 72))\n", + "\n", + " # Convert the pixmap to a PIL Image\n", + " image = Image.frombytes(\"RGB\", [pix.width, pix.height], pix.samples)\n", + "\n", + " # Resize the image if it exceeds the maximum size\n", + " if image.size[0] > max_size[0] or image.size[1] > max_size[1]:\n", + " image.thumbnail(max_size, Image.Resampling.LANCZOS)\n", + "\n", + " # Convert the PIL Image to base64-encoded PNG\n", + " image_data = io.BytesIO()\n", + " image.save(image_data, format=\"PNG\", optimize=True, quality=quality)\n", + " image_data.seek(0)\n", + " base64_encoded = base64.b64encode(image_data.getvalue()).decode(\"utf-8\")\n", + " base64_encoded_pngs.append(base64_encoded)\n", + "\n", + " # Close the PDF document\n", + " doc.close()\n", + "\n", + " return base64_encoded_pngs\n", + "\n", + "\n", + "# Folder to save the downloaded PDFs\n", + "folder = \"../images/using_sub_agents\"\n", + "\n", + "\n", + "# Create the directory if it doesn't exist\n", + "os.makedirs(folder, exist_ok=True)\n", + "\n", + "# Download the PDFs concurrently\n", + "with ThreadPoolExecutor() as executor:\n", + " pdf_paths = list(executor.map(download_pdf, pdf_urls, [folder] * len(pdf_urls)))\n", + "\n", + "# Remove any None values (failed downloads) from pdf_paths\n", + "pdf_paths = [path for path in pdf_paths if path is not None]" + ] }, { "cell_type": "markdown", @@ -108,20 +170,71 @@ }, { "cell_type": "code", - "execution_count": 102, + "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Extract the following information from the Apple earnings report PDF for the quarter:\n", - "1. Apple's net sales for the quarter\n", - "2. Quarter-over-quarter change in net sales\n", - "3. Key product categories, services, or regions that contributed significantly to the change in net sales\n", - "4. Any explanations provided for the changes in net sales\n", + "You are analyzing a single Apple Inc. earnings document, such as a Form 10-Q, a Form 10-K, or a quarterly earnings press release. Your output will be combined with other agents' extractions from the other quarters of Apple's fiscal year 2023 to answer this question: \"How did Apple's net sales change quarter to quarter in the 2023 financial year and what were the key contributors to the changes?\"\n", + "\n", + "Apple's fiscal year 2023 ran from September 25, 2022 to September 30, 2023:\n", + "- Q1 FY23 ended December 31, 2022\n", + "- Q2 FY23 ended April 1, 2023\n", + "- Q3 FY23 ended July 1, 2023\n", + "- Q4 FY23 ended September 30, 2023 (usually reported in the Form 10-K or the Q4 press release)\n", + "\n", + "Extract only information stated in your document. Do not estimate or use outside knowledge. If something is missing, write \"Not reported in this document.\"\n", "\n", - "Organize the extracted information in a clear, concise format focusing on the key data points and insights related to the change in net sales for the quarter.\n" + "**1. Document identification**\n", + "- Document type (10-Q, 10-K, or press release) and filing or release date.\n", + "- The fiscal quarter covered and its exact period-end date.\n", + "- If the document covers the full year (e.g., a 10-K), note this. Extract any Q4-specific figures stated. If only annual and year-to-date figures appear, report them and clearly label them as such. Do not derive Q4 values yourself.\n", + "\n", + "**2. Total net sales for the quarter**\n", + "- Total net sales for the current quarter, with units (e.g., millions of USD).\n", + "- Total net sales for the same quarter of the prior year.\n", + "- Dollar change and percentage change, exactly as reported.\n", + "- Any year-to-date totals, labeled as year-to-date.\n", + "\n", + "**3. Net sales by category (current quarter vs. prior-year quarter, with % change)**\n", + "- iPhone\n", + "- Mac\n", + "- iPad\n", + "- Wearables, Home and Accessories\n", + "- Services\n", + "- Total Products vs. total Services, if reported separately\n", + "\n", + "**4. Net sales by reportable segment (current quarter vs. prior-year quarter, with % change)**\n", + "- Americas\n", + "- Europe\n", + "- Greater China\n", + "- Japan\n", + "- Rest of Asia Pacific\n", + "\n", + "**5. Key contributors to changes in net sales**\n", + "Extract management's stated explanations, quoting or closely paraphrasing the text from MD&A, segment discussion, or press release commentary. Include:\n", + "- Drivers of increases or decreases for each product category and Services, such as product launches, product mix, demand, pricing, or growth in advertising, cloud, App Store, or payment services.\n", + "- Drivers for each geographic segment.\n", + "- Foreign currency impacts, including any quantified effect or constant-currency figures.\n", + "- Supply chain disruptions, production constraints, or COVID-related effects (e.g., iPhone 14 Pro production issues in China).\n", + "- Macroeconomic factors, such as inflation, interest rates, or consumer spending.\n", + "- Comparisons that are difficult because of timing differences (e.g., a 14-week vs. 13-week quarter, or the timing of product launches).\n", + "- Any other factor management cites as material to net sales performance.\n", + "\n", + "**6. Supplementary context (if available)**\n", + "- Gross margin for Products, Services, and in total, with percentages.\n", + "- Any forward-looking commentary or guidance about upcoming net sales.\n", + "- Notable product or service launches during the quarter.\n", + "- Any sequential (quarter-over-quarter) comparisons the document itself states.\n", + "\n", + "**Output format**\n", + "- Use clear headings matching the sections above.\n", + "- Present numerical data in tables with the columns: Metric | Current Quarter | Prior-Year Quarter | $ Change | % Change.\n", + "- Keep all figures exactly as reported, with units and period labels.\n", + "- Include page or section references for key figures and explanations where possible.\n", + "- End with a 3–5 sentence summary of the most important net sales drivers for this quarter, based only on the document.\n" ] } ], @@ -158,55 +271,431 @@ }, { "cell_type": "code", - "execution_count": 107, + "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "According to the condensed consolidated statements of operations, Apple's net sales changed as follows in the 2023 financial year:\n", + "# Apple Inc. Earnings Analysis: Q4 FY23 (Three Months Ended September 30, 2023)\n", + "\n", + "## 1. Document Identification\n", + "\n", + "**Document Type:** Condensed Consolidated Statements of Operations and Balance Sheets (Unaudited) and Condensed Consolidated Statements of Cash Flows (Unaudited)\n", + "\n", + "**Filing/Release Date:** Not explicitly stated in the provided document pages. The document shows financial data as of and for periods ended September 30, 2023 and September 24, 2022.\n", + "\n", + "**Fiscal Quarter Covered:** Q4 FY23 (Three Months Ended September 30, 2023)\n", + "\n", + "**Period-End Date:** September 30, 2023\n", + "\n", + "**Full-Year Data:** The document also presents twelve-month data ended September 30, 2023 and September 24, 2022, representing the full fiscal year 2023.\n", + "\n", + "**Note:** This appears to be extracted from a Form 10-K or earnings release, as it presents both quarterly and full-year financial statements.\n", + "\n", + "---\n", + "\n", + "## 2. Total Net Sales for the Quarter\n", + "\n", + "| Metric | Q4 FY23 (Sept 30, 2023) | Q4 FY22 (Sept 24, 2022) | $ Change | % Change |\n", + "|--------|-------------------------|-------------------------|-----------|-----------|\n", + "| **Total Net Sales** | $89,498 million | $90,146 million | $(648) million | (0.7%) |\n", + "\n", + "**Year-to-Date (Full Fiscal Year 2023):**\n", + "\n", + "| Metric | FY 2023 (12 months ended Sept 30, 2023) | FY 2022 (12 months ended Sept 24, 2022) | $ Change | % Change |\n", + "|--------|------------------------------------------|------------------------------------------|-----------|-----------|\n", + "| **Total Net Sales** | $383,285 million | $394,328 million | $(11,043) million | (2.8%) |\n", + "\n", + "---\n", + "\n", + "## 3. Net Sales by Category (Current Quarter vs. Prior-Year Quarter)\n", + "\n", + "### Q4 FY23 vs. Q4 FY22 (Three Months Ended September 30, 2023 vs. September 24, 2022)\n", + "\n", + "| Product Category | Q4 FY23 | Q4 FY22 | $ Change | % Change |\n", + "|------------------|---------|---------|-----------|-----------|\n", + "| **iPhone** | $43,805 million | $42,626 million | $1,179 million | 2.8% |\n", + "| **Mac** | $7,614 million | $11,508 million | $(3,894) million | (33.8%) |\n", + "| **iPad** | $6,443 million | $7,174 million | $(731) million | (10.2%) |\n", + "| **Wearables, Home and Accessories** | $9,322 million | $9,650 million | $(328) million | (3.4%) |\n", + "| **Services** | $22,314 million | $19,188 million | $3,126 million | 16.3% |\n", + "| **Total Net Sales** | $89,498 million | $90,146 million | $(648) million | (0.7%) |\n", + "\n", + "### Products vs. Services Breakdown (Q4 FY23 vs. Q4 FY22)\n", + "\n", + "| Category | Q4 FY23 | Q4 FY22 | $ Change | % Change |\n", + "|----------|---------|---------|-----------|-----------|\n", + "| **Total Products** | $67,184 million | $70,958 million | $(3,774) million | (5.3%) |\n", + "| **Total Services** | $22,314 million | $19,188 million | $3,126 million | 16.3% |\n", + "\n", + "### Full Fiscal Year 2023 by Category (12 Months Ended Sept 30, 2023 vs. Sept 24, 2022)\n", + "\n", + "| Product Category | FY 2023 | FY 2022 | $ Change | % Change |\n", + "|------------------|---------|---------|-----------|-----------|\n", + "| **iPhone** | $200,583 million | $205,489 million | $(4,906) million | (2.4%) |\n", + "| **Mac** | $29,357 million | $40,177 million | $(10,820) million | (26.9%) |\n", + "| **iPad** | $28,300 million | $29,292 million | $(992) million | (3.4%) |\n", + "| **Wearables, Home and Accessories** | $39,845 million | $41,241 million | $(1,396) million | (3.4%) |\n", + "| **Services** | $85,200 million | $78,129 million | $7,071 million | 9.1% |\n", + "| **Total Net Sales** | $383,285 million | $394,328 million | $(11,043) million | (2.8%) |\n", + "\n", + "### Products vs. Services Breakdown (Full Year FY 2023 vs. FY 2022)\n", + "\n", + "| Category | FY 2023 | FY 2022 | $ Change | % Change |\n", + "|----------|---------|---------|-----------|-----------|\n", + "| **Total Products** | $298,085 million | $316,199 million | $(18,114) million | (5.7%) |\n", + "| **Total Services** | $85,200 million | $78,129 million | $7,071 million | 9.1% |\n", + "\n", + "---\n", + "\n", + "## 4. Net Sales by Reportable Segment (Current Quarter vs. Prior-Year Quarter)\n", + "\n", + "### Q4 FY23 vs. Q4 FY22 (Three Months Ended September 30, 2023 vs. September 24, 2022)\n", + "\n", + "| Geographic Segment | Q4 FY23 | Q4 FY22 | $ Change | % Change |\n", + "|--------------------|---------|---------|-----------|-----------|\n", + "| **Americas** | $40,115 million | $39,808 million | $307 million | 0.8% |\n", + "| **Europe** | $22,463 million | $22,795 million | $(332) million | (1.5%) |\n", + "| **Greater China** | $15,084 million | $15,470 million | $(386) million | (2.5%) |\n", + "| **Japan** | $5,505 million | $5,700 million | $(195) million | (3.4%) |\n", + "| **Rest of Asia Pacific** | $6,331 million | $6,373 million | $(42) million | (0.7%) |\n", + "| **Total Net Sales** | $89,498 million | $90,146 million | $(648) million | (0.7%) |\n", + "\n", + "### Full Fiscal Year 2023 by Segment (12 Months Ended Sept 30, 2023 vs. Sept 24, 2022)\n", + "\n", + "| Geographic Segment | FY 2023 | FY 2022 | $ Change | % Change |\n", + "|--------------------|---------|---------|-----------|-----------|\n", + "| **Americas** | $162,560 million | $169,658 million | $(7,098) million | (4.2%) |\n", + "| **Europe** | $94,294 million | $95,118 million | $(824) million | (0.9%) |\n", + "| **Greater China** | $72,559 million | $74,200 million | $(1,641) million | (2.2%) |\n", + "| **Japan** | $24,257 million | $25,977 million | $(1,720) million | (6.6%) |\n", + "| **Rest of Asia Pacific** | $29,615 million | $29,375 million | $240 million | 0.8% |\n", + "| **Total Net Sales** | $383,285 million | $394,328 million | $(11,043) million | (2.8%) |\n", + "\n", + "---\n", + "\n", + "## 5. Key Contributors to Changes in Net Sales\n", + "\n", + "**Not reported in this document.**\n", + "\n", + "The extracted pages contain only the condensed consolidated financial statements (Statement of Operations, Balance Sheet, and Cash Flows). These pages do not include Management's Discussion and Analysis (MD&A), segment commentary, or management's narrative explanations of the drivers behind the changes in net sales. \n", + "\n", + "To obtain the key contributors and drivers for Q4 FY23 and the full fiscal year 2023, the MD&A section of the Form 10-K or the earnings press release would need to be reviewed.\n", + "\n", + "---\n", + "\n", + "## 6. Supplementary Context\n", + "\n", + "### Gross Margin Analysis\n", + "\n", + "**Q4 FY23 vs. Q4 FY22 (Three Months\n", + "# Apple Inc. Earnings Analysis – Q3 FY2023\n", + "\n", + "## 1. Document Identification\n", + "\n", + "**Document Type:** Condensed Consolidated Statements (10-Q excerpt) \n", + "**Filing/Release Date:** Not explicitly stated in the provided document excerpt \n", + "**Fiscal Quarter Covered:** Q3 FY2023 \n", + "**Period-End Date:** July 1, 2023 \n", + "**Document Scope:** Quarterly statements (unaudited); also includes nine-month year-to-date comparisons\n", + "\n", + "---\n", + "\n", + "## 2. Total Net Sales for the Quarter\n", + "\n", + "| Metric | Q3 FY2023 (Jul 1, 2023) | Q3 FY2022 (Jun 25, 2022) | $ Change | % Change |\n", + "|--------|------------------------|------------------------|----------|----------|\n", + "| **Total Net Sales** | $81,797 million | $82,959 million | $(1,162) million | (1.4%) |\n", + "\n", + "**Year-to-Date (Nine Months Ended):**\n", + "\n", + "| Metric | 9M FY2023 (Jul 1, 2023) | 9M FY2022 (Jun 25, 2022) | $ Change | % Change |\n", + "|--------|------------------------|------------------------|----------|----------|\n", + "| **Total Net Sales** | $293,787 million | $304,182 million | $(10,395) million | (3.4%) |\n", + "\n", + "**Key Observation:** Q3 FY2023 net sales declined slightly year-over-year, with nine-month sales also down compared to the prior-year period.\n", + "\n", + "---\n", + "\n", + "## 3. Net Sales by Category (Current Quarter vs. Prior-Year Quarter)\n", + "\n", + "| Category | Q3 FY2023 (Jul 1, 2023) | Q3 FY2022 (Jun 25, 2022) | $ Change | % Change |\n", + "|----------|------------------------|------------------------|----------|----------|\n", + "| **iPhone** | $39,669 million | $40,665 million | $(996) million | (2.4%) |\n", + "| **Mac** | $6,840 million | $7,382 million | $(542) million | (7.3%) |\n", + "| **iPad** | $5,791 million | $7,224 million | $(1,433) million | (19.8%) |\n", + "| **Wearables, Home and Accessories** | $8,284 million | $8,084 million | $200 million | 2.5% |\n", + "| **Services** | $21,213 million | $19,604 million | $1,609 million | 8.2% |\n", + "| **Total Products** | $60,584 million | $63,355 million | $(2,771) million | (4.4%) |\n", + "\n", + "**Year-to-Date (Nine Months Ended):**\n", + "\n", + "| Category | 9M FY2023 (Jul 1, 2023) | 9M FY2022 (Jun 25, 2022) | $ Change | % Change |\n", + "|----------|------------------------|------------------------|----------|----------|\n", + "| **iPhone** | $156,778 million | $162,863 million | $(6,085) million | (3.7%) |\n", + "| **Mac** | $21,743 million | $28,669 million | $(6,926) million | (24.2%) |\n", + "| **iPad** | $21,857 million | $22,118 million | $(261) million | (1.2%) |\n", + "| **Wearables, Home and Accessories** | $30,523 million | $31,591 million | $(1,068) million | (3.4%) |\n", + "| **Services** | $62,886 million | $58,941 million | $3,945 million | 6.7% |\n", + "| **Total Products** | $230,901 million | $245,241 million | $(14,340) million | (5.9%) |\n", + "\n", + "---\n", + "\n", + "## 4. Net Sales by Reportable Segment (Current Quarter vs. Prior-Year Quarter)\n", + "\n", + "| Segment | Q3 FY2023 (Jul 1, 2023) | Q3 FY2022 (Jun 25, 2022) | $ Change | % Change |\n", + "|---------|------------------------|------------------------|----------|----------|\n", + "| **Americas** | $35,383 million | $37,472 million | $(2,089) million | (5.6%) |\n", + "| **Europe** | $20,205 million | $19,287 million | $918 million | 4.8% |\n", + "| **Greater China** | $15,758 million | $14,604 million | $1,154 million | 7.9% |\n", + "| **Japan** | $4,821 million | $5,446 million | $(625) million | (11.5%) |\n", + "| **Rest of Asia Pacific** | $5,630 million | $6,150 million | $(520) million | (8.5%) |\n", + "| **Total Net Sales** | $81,797 million | $82,959 million | $(1,162) million | (1.4%) |\n", + "\n", + "**Year-to-Date (Nine Months Ended):**\n", + "\n", + "| Segment | 9M FY2023 (Jul 1, 2023) | 9M FY2022 (Jun 25, 2022) | $ Change | % Change |\n", + "|---------|------------------------|------------------------|----------|----------|\n", + "| **Americas** | $122,445 million | $129,850 million | $(7,405) million | (5.7%) |\n", + "| **Europe** | $71,831 million | $72,323 million | $(492) million | (0.7%) |\n", + "| **Greater China** | $57,475 million | $58,730 million | $(1,255) million | (2.1%) |\n", + "| **Japan** | $18,752 million | $20,277 million | $(1,525) million | (7.5%) |\n", + "| **Rest of Asia Pacific** | $23,284 million | $23,002 million | $282 million | 1.2% |\n", + "| **Total Net Sales** | $293,787 million | $304,182 million | $(10,395) million | (3.4%) |\n", + "\n", + "---\n", + "\n", + "## 5. Key Contributors to Changes in Net Sales\n", "\n", - "Quarter Ended September 30, 2023:\n", - "- Total net sales were $89,498 million, up from $90,146 million in the prior year quarter.\n", - "- Product sales were $67,184 million and services sales were $22,314 million.\n", + "**Not reported in this document.**\n", "\n", - "Key contributors to the changes:\n", - "- Product sales decreased from $70,958 million in the prior year quarter.\n", - "- Services sales increased from $19,188 million in the prior year quarter.\n", + "The provided excerpts contain only the Condensed Consolidated Statements of Operations, Balance Sheets, and Cash Flows. They do not include the Management's Discussion and Analysis (MD&A) section, segment commentary, or press release narrative where management typically explains the drivers of changes in net sales by category and geography.\n", "\n", - "Overall, Apple's total net sales decreased slightly compared to the same quarter in the prior year, driven by a decline in product sales which was partially offset by growth in services sales.\n", - "Based on the financial statements provided, Apple's net sales changed as follows between the quarters in the 2023 financial year:\n", + "To identify the specific factors contributing to the year-over-year declines in iPhone, Mac, iPad, and the overall product category—as well as the 8.2% growth in Services and the mixed geographic performance—reference to the full Form 10-Q or earnings release commentary would be required.\n", "\n", - "- Net sales increased from $81,797 million in the three months ended July 1, 2023 to $82,959 million in the three months ended June 25, 2022. This represents a quarter-over-quarter increase of around $1,162 million.\n", + "---\n", "\n", - "The key contributors to this increase appear to be:\n", + "## 6. Supplementary Context\n", "\n", - "- Products sales increased from $60,584 million to $63,355 million, an increase of around $2,771 million.\n", - "- Services sales increased from $21,213 million to $19,604 million, an increase of around $1,609 million.\n", + "### Gross Margin\n", "\n", - "So the growth in both product sales and services sales contributed to the overall increase in Apple's net sales between these two quarters in the 2023 fiscal year.\n", - "According to the financial statements, Apple's net sales changed significantly between the quarters in the 2023 financial year:\n", + "| Metric | Q3 FY2023 | Q3 FY2022 | 9M FY2023 | 9M FY2022 |\n", + "|--------|-----------|-----------|----------|-----------|\n", + "| **Total Gross Margin (%)** | 44.5% | 43.3% | 43.9% | 43.6% |\n", "\n", - "- For the three months ended April 1, 2023, net sales were $94,836 million.\n", - "- For the six months ended March 26, 2022, net sales were $97,278 million.\n", + "**Calculation:** Gross margin = (Total net sales − Total cost of sales) / Total net sales\n", "\n", - "This shows that net sales decreased by around $2,442 million from the prior six-month period to the most recent three-month period.\n", + "- Q3 FY2023: ($81,797 − $45,384) / $81,797 = 44.5%\n", + "- Q3 FY2022: ($82,959 − $47,074) / $82,959 = 43.3%\n", "\n", - "The key contributors to this change in net sales appear to be:\n", + "**Forward-Looking Commentary, Product Launches, or Guidance:**\n", "\n", - "1. Products sales decreased from $107,560 million in the prior six-month period to $73,929 million in the recent three-month period.\n", - "2. Services sales increased from $41,673 million in the prior six-month period to $20,907 million in the recent three-month period.\n", + "**Not reported in this document.**\n", "\n", - "So the decrease in product sales was the primary driver behind the overall decline in net sales from the prior period to the most recent quarter.\n", - "According to the condensed consolidated statements of operations, Apple's net sales increased from $117,154 million in the three months ended December 31, 2022 to $123,945 million in the three months ended December 25, 2021. This represents a quarter-over-quarter increase in net sales.\n", + "The provided statements do not contain MD&A commentary, forward guidance, or product launch information.\n", "\n", - "The key contributors to this change were:\n", + "---\n", "\n", - "1. Increase in product sales revenue from $96,388 million to $104,429 million.\n", - "2. Increase in services revenue from $20,766 million to $19,516 million.\n", + "## Summary\n", "\n", - "So the overall increase in net sales was driven primarily by higher product sales, with services revenue also showing a smaller increase quarter-over-quarter.\n", + "In Q3 FY2023 (ended July 1, 2023), Apple's total net sales declined 1.4% year-over-year to $81,797 million, driven primarily by weakness in Products (down 4.4%), particularly iPad (−19.8%), Mac (−7.3%), and iPhone (−2.4%), which were only partially offset by strong Services growth of 8.2%. Geographically, the Americas and Japan declined significantly (−5.6% and −11.5%, respectively), while Greater China and Europe showed growth (7.9% and 4.8%, respectively). Gross margin expanded to 44.5% from 43.3% in the prior-year quarter. The nine-month year\n", + "# Apple Inc. – Q2 FY2023 Earnings Document Analysis\n", + "\n", + "## 1. Document Identification\n", + "\n", + "**Document Type:** Form 10-Q (Condensed Consolidated Financial Statements and related disclosures)\n", + "\n", + "**Filing Date:** The document is dated as of April 1, 2023 (quarter end)\n", + "\n", + "**Fiscal Quarter Covered:** Q2 FY2023, ended April 1, 2023\n", + "- Apple's fiscal year 2023 runs from September 25, 2022 to September 30, 2023\n", + "- This quarter covers the period from January 1, 2023 (or the end of Q1 FY23 on December 31, 2022) through April 1, 2023\n", + "\n", + "**Full-Year Note:** This document contains only six-month (year-to-date) and quarterly data; it is not a full-year 10-K. Q4 FY2023 figures are not available in this document.\n", + "\n", + "---\n", + "\n", + "## 2. Total Net Sales for the Quarter\n", + "\n", + "| Metric | Q2 FY2023 (Apr 1, 2023) | Q2 FY2022 (Mar 26, 2022) | $ Change | % Change |\n", + "|--------|-------------------------|-------------------------|----------|----------|\n", + "| **Total Net Sales** | $94,836 million | $97,278 million | $(2,442) million | (2.5%) |\n", + "\n", + "**Year-to-Date (Six Months Ended):**\n", + "\n", + "| Metric | Six Months Ended Apr 1, 2023 | Six Months Ended Mar 26, 2022 | $ Change | % Change |\n", + "|--------|------------------------------|------------------------------|----------|----------|\n", + "| **Total Net Sales** | $211,990 million | $221,223 million | $(9,233) million | (4.2%) |\n", + "\n", + "---\n", + "\n", + "## 3. Net Sales by Category (Current Quarter vs. Prior-Year Quarter)\n", + "\n", + "| Category | Q2 FY2023 | Q2 FY2022 | $ Change | % Change |\n", + "|----------|-----------|-----------|----------|----------|\n", + "| **iPhone** | $51,334 million | $50,570 million | $764 million | 1.5% |\n", + "| **Mac** | $7,168 million | $10,435 million | $(3,267) million | (31.3%) |\n", + "| **iPad** | $6,670 million | $7,646 million | $(976) million | (12.8%) |\n", + "| **Wearables, Home and Accessories** | $8,757 million | $8,806 million | $(49) million | (0.6%) |\n", + "| **Services** | $20,907 million | $19,821 million | $1,086 million | 5.5% |\n", + "| **Total Net Sales** | $94,836 million | $97,278 million | $(2,442) million | (2.5%) |\n", + "\n", + "**Products vs. Services Breakdown:**\n", + "\n", + "| Category | Q2 FY2023 | Q2 FY2022 | $ Change | % Change |\n", + "|----------|-----------|-----------|----------|----------|\n", + "| **Total Products** | $73,929 million | $77,457 million | $(3,528) million | (4.6%) |\n", + "| **Total Services** | $20,907 million | $19,821 million | $1,086 million | 5.5% |\n", + "\n", + "**Year-to-Date (Six Months Ended):**\n", + "\n", + "| Category | Six Months Ended Apr 1, 2023 | Six Months Ended Mar 26, 2022 | $ Change | % Change |\n", + "|----------|------------------------------|------------------------------|----------|----------|\n", + "| **iPhone** | $117,109 million | $122,198 million | $(5,089) million | (4.2%) |\n", + "| **Mac** | $14,903 million | $21,287 million | $(6,384) million | (30.0%) |\n", + "| **iPad** | $16,066 million | $14,894 million | $1,172 million | 7.9% |\n", + "| **Wearables, Home and Accessories** | $22,239 million | $23,507 million | $(1,268) million | (5.4%) |\n", + "| **Services** | $41,673 million | $39,337 million | $2,336 million | 5.9% |\n", + "| **Total Net Sales** | $211,990 million | $221,223 million | $(9,233) million | (4.2%) |\n", + "\n", + "---\n", + "\n", + "## 4. Net Sales by Reportable Segment (Current Quarter vs. Prior-Year Quarter)\n", + "\n", + "| Segment | Q2 FY2023 | Q2 FY2022 | $ Change | % Change |\n", + "|---------|-----------|-----------|----------|----------|\n", + "| **Americas** | $37,784 million | $40,882 million | $(3,098) million | (7.6%) |\n", + "| **Europe** | $23,945 million | $23,287 million | $658 million | 2.8% |\n", + "| **Greater China** | $17,812 million | $18,343 million | $(531) million | (2.9%) |\n", + "| **Japan** | $7,176 million | $7,724 million | $(548) million | (7.1%) |\n", + "| **Rest of Asia Pacific** | $8,119 million | $7,042 million | $1,077 million | 15.3% |\n", + "| **Total Net Sales** | $94,836 million | $97,278 million | $(2,442) million | (2.5%) |\n", + "\n", + "**Year-to-Date (Six Months Ended):**\n", + "\n", + "| Segment | Six Months Ended Apr 1, 2023 | Six Months Ended Mar 26, 2022 | $ Change | % Change |\n", + "|---------|------------------------------|------------------------------|----------|----------|\n", + "| **Americas** | $87,062 million | $92,378 million | $(5,316) million | (5.8%) |\n", + "| **Europe** | $51,626 million | $53,036 million | $(1,410) million | (2.7%) |\n", + "| **Greater China** | $41,717 million | $44,126 million | $(2,409) million | (5.5%) |\n", + "| **Japan** | $13,931 million | $14,831 million | $(900) million | (6.1%) |\n", + "| **Rest of Asia Pacific** | $17,654 million | $16,852 million | $802 million | 4.8% |\n", + "| **Total Net Sales** | $211,990 million | $221,223 million | $(9,233) million | (4.2%) |\n", + "\n", + "---\n", + "\n", + "## 5. Key Contributors to Changes in Net Sales\n", + "\n", + "**Important Note:** The provided document contains **condensed consolidated financial statements** (balance sheet, income statement, and cash flow statement) but does **not include Management's Discussion and Analysis (MD&A)** section or management commentary that typically explains the drivers of sales changes. Therefore, the specific qualitative factors cited by management are **not available in this document**.\n", + "\n", + "Based on the financial data presented:\n", + "\n", + "### Product Category Performance:\n", + "- **iPhone:** Modest growth of 1.5% in Q2 FY2023 vs. Q2 FY2022 ($51.3B vs. $50.6B), despite overall net sales decline. Year-to-date, iPhone sales declined 4.2% to $117.1B.\n", + "- **Mac:** Significant decline of 31.3% in Q2 ($7.2B vs. $10.4B) and 30.0% year-to-date ($14.9B vs. $21.3B). This is the largest driver of the overall net sales decline.\n", + "- **iPad:** Declined 12.8% in Q2 ($6.7B vs. $7.6B) but showed recovery year-to-date with 7.9% growth ($16.1B vs. $14.9B).\n", + "- **Wearables, Home and Accessories:** Relatively flat in Q2 (down 0.6%) and down 5.4% year-to-date.\n", + "- **Services:** Positive growth of 5.5% in Q2 ($20.9B vs. $19.8B) and 5.9% year-to-date ($41.7B vs. $39.3B).\n", + "\n", + "### Geographic Segment Performance:\n", + "- **Americas:** Declined 7.6% in Q2 ($37.8B vs. $40.\n", + "# Apple Inc. Earnings Extract – Q1 FY2023\n", + "\n", + "## 1. Document Identification\n", + "\n", + "- **Document type:** Unaudited Condensed Consolidated Statements (quarterly earnings report)\n", + "- **Filing/release date:** Not explicitly stated in the provided documents; however, the statements are dated for the three months ended December 31, 2022\n", + "- **Fiscal quarter covered:** Q1 FY2023\n", + "- **Period-end date:** December 31, 2022\n", + "- **Prior-year comparison period:** Three months ended December 25, 2021\n", + "- **Note:** This document does not cover the full fiscal year. It presents only Q1 FY2023 results and does not include Q4 FY2023 or full-year figures.\n", + "\n", + "---\n", + "\n", + "## 2. Total Net Sales for the Quarter\n", + "\n", + "| Metric | Current Quarter (Dec 31, 2022) | Prior-Year Quarter (Dec 25, 2021) | $ Change | % Change |\n", + "|--------|--------------------------------|-----------------------------------|----------|----------|\n", + "| **Total net sales** | $117,154 million | $123,945 million | $(6,791) million | (5.5%) |\n", + "\n", + "**Source:** Condensed Consolidated Statements of Operations (Unaudited), three months ended December 31, 2022 and December 25, 2021.\n", + "\n", + "---\n", + "\n", + "## 3. Net Sales by Category (Current Quarter vs. Prior-Year Quarter)\n", + "\n", + "| Product/Service Category | Current Quarter (Dec 31, 2022) | Prior-Year Quarter (Dec 25, 2021) | $ Change | % Change |\n", + "|--------------------------|--------------------------------|-----------------------------------|----------|----------|\n", + "| **iPhone** | $65,775 million | $71,628 million | $(5,853) million | (8.2%) |\n", + "| **Mac** | $7,735 million | $10,852 million | $(3,117) million | (28.7%) |\n", + "| **iPad** | $9,396 million | $7,248 million | $2,148 million | 29.6% |\n", + "| **Wearables, Home and Accessories** | $13,482 million | $14,701 million | $(1,219) million | (8.3%) |\n", + "| **Services** | $20,766 million | $19,516 million | $1,250 million | 6.4% |\n", + "| **Total Products** | $96,388 million | $104,429 million | $(8,041) million | (7.7%) |\n", + "| **Total Services** | $20,766 million | $19,516 million | $1,250 million | 6.4% |\n", + "| **Total net sales** | $117,154 million | $123,945 million | $(6,791) million | (5.5%) |\n", + "\n", + "**Source:** Net sales by category, Condensed Consolidated Statements of Operations (Unaudited).\n", + "\n", + "---\n", + "\n", + "## 4. Net Sales by Reportable Segment (Current Quarter vs. Prior-Year Quarter)\n", + "\n", + "| Geographic Segment | Current Quarter (Dec 31, 2022) | Prior-Year Quarter (Dec 25, 2021) | $ Change | % Change |\n", + "|--------------------|--------------------------------|-----------------------------------|----------|----------|\n", + "| **Americas** | $49,278 million | $51,496 million | $(2,218) million | (4.3%) |\n", + "| **Europe** | $27,681 million | $29,749 million | $(2,068) million | (6.9%) |\n", + "| **Greater China** | $23,905 million | $25,783 million | $(1,878) million | (7.3%) |\n", + "| **Japan** | $6,755 million | $7,107 million | $(352) million | (5.0%) |\n", + "| **Rest of Asia Pacific** | $9,535 million | $9,810 million | $(275) million | (2.8%) |\n", + "| **Total net sales** | $117,154 million | $123,945 million | $(6,791) million | (5.5%) |\n", + "\n", + "**Source:** Net sales by reportable segment, Condensed Consolidated Statements of Operations (Unaudited).\n", + "\n", + "---\n", + "\n", + "## 5. Key Contributors to Changes in Net Sales\n", + "\n", + "**Not reported in this document.**\n", + "\n", + "The provided financial statements contain only the condensed consolidated statements of operations, balance sheet, and cash flows. They do not include management discussion and analysis (MD&A) commentary, segment discussion, or explanations of the drivers behind net sales changes. The statements present the financial data but do not provide qualitative explanations for the year-over-year declines or category-specific performance drivers.\n", + "\n", + "---\n", + "\n", + "## 6. Supplementary Context\n", + "\n", + "### Gross Margin\n", + "\n", + "| Margin Category | Current Quarter (Dec 31, 2022) | Prior-Year Quarter (Dec 25, 2021) |\n", + "|-----------------|--------------------------------|-----------------------------------|\n", + "| **Total gross margin** | $50,332 million (42.9% of net sales) | $54,243 million (43.8% of net sales) |\n", + "\n", + "**Calculation:** Gross margin = Total net sales minus Total cost of sales ($117,154 − $66,822 = $50,332 for current quarter; $123,945 − $69,702 = $54,243 for prior-year quarter).\n", + "\n", + "### Operating Income and Net Income\n", + "\n", + "| Metric | Current Quarter (Dec 31, 2022) | Prior-Year Quarter (Dec 25, 2021) |\n", + "|--------|--------------------------------|-----------------------------------|\n", + "| **Operating income** | $36,016 million | $41,488 million |\n", + "| **Net income** | $29,998 million | $34,630 million |\n", + "| **Diluted EPS** | $1.88 | $2.10 |\n", + "\n", + "**Source:** Condensed Consolidated Statements of Operations (Unaudited).\n", + "\n", + "### Notable Observations from Financial Statements\n", + "\n", + "- **Earnings per share:** Diluted EPS declined from $2.10 in the prior-year quarter to $1.88 in the current quarter, a decrease of $0.22 or 10.5%.\n", + "- **Share count:** Diluted shares outstanding decreased from 16,519,291 thousand to 15,955,718 thousand, reflecting share repurchases.\n", + "- **No forward-looking guidance or commentary** is provided in the financial statements presented.\n", + "- **No product launches or strategic initiatives** are mentioned in these financial statement pages.\n", + "\n", + "---\n", + "\n", + "## Summary\n", + "\n", + "Apple's Q1 FY2023 (ended December 31, 2022) total net sales declined 5.5% year-over-year to $117.2 billion, driven primarily by declines in iPhone (down 8.2%) and Mac (down 28.7%), partially offset by growth in iPad (up 29.6%) and Services (up 6.4%). All five geographic segments experienced sales declines, with Europe and Greater China showing the largest percentage drops at 6.9% and 7.3%, respectively. The financial statements alone do not provide management's explanations for these changes; such commentary would be found in accompanying MD&A sections not included in this document extract.\n", "\n" ] } @@ -274,7 +763,7 @@ }, { "cell_type": "code", - "execution_count": 108, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -282,40 +771,38 @@ "output_type": "stream", "text": [ "Generated Response:\n", - "Based on the extracted information from Apple's earnings releases, Apple's net sales changed as follows in the 2023 financial year:\n", - "\n", - "In Q1, net sales increased from $117,154 million in the previous quarter to $123,945 million, driven by increases in both product sales and services revenue.\n", - "\n", - "In Q2, net sales decreased by around $2,442 million compared to the prior six-month period, primarily due to a decrease in product sales, which was partially offset by an increase in services sales.\n", + "# Apple's Quarter-to-Quarter Net Sales Changes in Fiscal 2023\n", "\n", - "In Q3, net sales increased by approximately $1,162 million compared to the previous quarter, with growth in both product sales and services sales contributing to the overall increase.\n", + "## Summary\n", "\n", - "In Q4, total net sales decreased slightly compared to the same quarter in the prior year, driven by a decline in product sales, which was partially offset by growth in services sales.\n", + "Apple's net sales fell for two quarters in a row and then recovered partly in Q4:\n", "\n", - "Here's a Python code snippet using the matplotlib library to visualize the quarterly net sales data:\n", + "| Quarter (period end) | Net Sales | QoQ $ Change | QoQ % Change | YoY % Change |\n", + "|---|---|---|---|---|\n", + "| Q1 FY23 (Dec 31, 2022) | $117,154M | n/a | n/a | (5.5%) |\n", + "| Q2 FY23 (Apr 1, 2023) | $94,836M | $(22,318)M | (19.1%) | (2.5%) |\n", + "| Q3 FY23 (Jul 1, 2023) | $81,797M | $(13,039)M | (13.7%) | (1.4%) |\n", + "| Q4 FY23 (Sep 30, 2023) | $89,498M | +$7,701M | +9.4% | (0.7%) |\n", + "| **FY23 Total** | **$383,285M** | | | **(2.8%)** |\n", "\n", - "\n", - "import matplotlib.pyplot as plt\n", + "The four quarters add up exactly to the reported full-year total of $383,285M.\n", "\n", - "quarters = ['Q1', 'Q2', 'Q3', 'Q4']\n", - "net_sales = [123945, 94836, 82959, 89498]\n", + "**Key takeaways:**\n", + "- **Seasonality drives the pattern.** Q1 is the holiday quarter and the peak. Sales then fell through Q3 and rebounded in Q4.\n", + "- **Year-over-year declines narrowed every quarter**, from −5.5% to −2.5% to −1.4% to −0.7%. Even as the business shrank versus FY22, the trend was improving.\n", + "- **Q1 had an extra week.** Based on the period dates (Sept 25 to Dec 31, 2022), Q1 FY23 covered about 14 weeks versus 13 in the other quarters. Q1 sales still declined 5.5% year over year despite this.\n", "\n", - "plt.figure(figsize=(8, 6))\n", - "plt.bar(quarters, net_sales, color='skyblue', width=0.6)\n", - "plt.xlabel('Quarter')\n", - "plt.ylabel('Net Sales (in millions)')\n", - "plt.title('Apple Net Sales by Quarter - FY 2023')\n", - "plt.xticks(quarters)\n", - "plt.yticks([0, 20000, 40000, 60000, 80000, 100000, 120000])\n", - "plt.grid(True, linestyle='--', alpha=0.5)\n", + "> **Important caveat:** All four source documents say management's explanations (MD&A / press release commentary) are **not included**. The \"contributors\" below are therefore derived from the reported category and segment figures, not from management's stated reasons.\n", "\n", - "for i, v in enumerate(net_sales):\n", - " plt.text(i, v + 1000, f'${v:,.0f}', ha='center', fontsize=10)\n", + "---\n", "\n", - "plt.show()\n", - "\n", + "## Contributors by Product Category ($ millions)\n", "\n", - "This code creates a bar chart showing Apple's net sales for each quarter in the 2023 financial year. The x-axis represents the quarters, and the y-axis represents the net sales in millions of dollars. The chart also includes data labels showing the exact net sales values for each quarter.\n" + "| Category | Q1 | Q2 | Q3 | Q4 | Q1→Q2 | Q2→Q3 | Q3→Q4 |\n", + "|---|---|---|---|---|---|---|---|\n", + "| iPhone | 65,775 | 51,334 | 39,669 | 43,805 | (14,441) / −22.0% | (11,665) / −22.7% | +4,136 / +10.4% |\n", + "| Mac | 7,735 | 7,168 | 6,840 | 7,614 | (567) / −7.3% | (328) / −4.6% | +774 / +11.3% |\n", + "| iPad | 9,396 | 6,670 | 5,791 | 6,443 | (2,726) / −29.0% | (879) / −13.2% | +652 / +\n" ] } ], @@ -355,10 +842,76 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, - "outputs": [], - "source": "# Extract the matplotlib code from the response\n# Function to extract the code and non-code parts from the response\ndef extract_code_and_response(response):\n start_tag = \"\"\n end_tag = \"\"\n start_index = response.find(start_tag)\n end_index = response.find(end_tag)\n if start_index != -1 and end_index != -1:\n code = response[start_index + len(start_tag) : end_index].strip()\n non_code_response = response[:start_index].strip()\n return code, non_code_response\n else:\n return None, response.strip()\n\n\nmatplotlib_code, non_code_response = extract_code_and_response(generated_response)\n\nprint(non_code_response)\nif matplotlib_code:\n # Execute the extracted matplotlib code\n # Note: exec is used here for demonstration purposes to run model-generated visualization code.\n # In production, use a sandboxed environment for executing untrusted code.\n exec(matplotlib_code) # noqa: S102\nelse:\n print(\"No matplotlib code found in the response.\")" + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "# Apple's Quarter-to-Quarter Net Sales Changes in Fiscal 2023\n", + "\n", + "## Summary\n", + "\n", + "Apple's net sales fell for two quarters in a row and then recovered partly in Q4:\n", + "\n", + "| Quarter (period end) | Net Sales | QoQ $ Change | QoQ % Change | YoY % Change |\n", + "|---|---|---|---|---|\n", + "| Q1 FY23 (Dec 31, 2022) | $117,154M | n/a | n/a | (5.5%) |\n", + "| Q2 FY23 (Apr 1, 2023) | $94,836M | $(22,318)M | (19.1%) | (2.5%) |\n", + "| Q3 FY23 (Jul 1, 2023) | $81,797M | $(13,039)M | (13.7%) | (1.4%) |\n", + "| Q4 FY23 (Sep 30, 2023) | $89,498M | +$7,701M | +9.4% | (0.7%) |\n", + "| **FY23 Total** | **$383,285M** | | | **(2.8%)** |\n", + "\n", + "The four quarters add up exactly to the reported full-year total of $383,285M.\n", + "\n", + "**Key takeaways:**\n", + "- **Seasonality drives the pattern.** Q1 is the holiday quarter and the peak. Sales then fell through Q3 and rebounded in Q4.\n", + "- **Year-over-year declines narrowed every quarter**, from −5.5% to −2.5% to −1.4% to −0.7%. Even as the business shrank versus FY22, the trend was improving.\n", + "- **Q1 had an extra week.** Based on the period dates (Sept 25 to Dec 31, 2022), Q1 FY23 covered about 14 weeks versus 13 in the other quarters. Q1 sales still declined 5.5% year over year despite this.\n", + "\n", + "> **Important caveat:** All four source documents say management's explanations (MD&A / press release commentary) are **not included**. The \"contributors\" below are therefore derived from the reported category and segment figures, not from management's stated reasons.\n", + "\n", + "---\n", + "\n", + "## Contributors by Product Category ($ millions)\n", + "\n", + "| Category | Q1 | Q2 | Q3 | Q4 | Q1→Q2 | Q2→Q3 | Q3→Q4 |\n", + "|---|---|---|---|---|---|---|---|\n", + "| iPhone | 65,775 | 51,334 | 39,669 | 43,805 | (14,441) / −22.0% | (11,665) / −22.7% | +4,136 / +10.4% |\n", + "| Mac | 7,735 | 7,168 | 6,840 | 7,614 | (567) / −7.3% | (328) / −4.6% | +774 / +11.3% |\n", + "| iPad | 9,396 | 6,670 | 5,791 | 6,443 | (2,726) / −29.0% | (879) / −13.2% | +652 / +\n", + "No matplotlib code found in the response.\n" + ] + } + ], + "source": [ + "# Extract the matplotlib code from the response\n", + "# Function to extract the code and non-code parts from the response\n", + "def extract_code_and_response(response):\n", + " start_tag = \"\"\n", + " end_tag = \"\"\n", + " start_index = response.find(start_tag)\n", + " end_index = response.find(end_tag)\n", + " if start_index != -1 and end_index != -1:\n", + " code = response[start_index + len(start_tag) : end_index].strip()\n", + " non_code_response = response[:start_index].strip()\n", + " return code, non_code_response\n", + " else:\n", + " return None, response.strip()\n", + "\n", + "\n", + "matplotlib_code, non_code_response = extract_code_and_response(generated_response)\n", + "\n", + "print(non_code_response)\n", + "if matplotlib_code:\n", + " # Execute the extracted matplotlib code\n", + " # Note: exec is used here for demonstration purposes to run model-generated visualization code.\n", + " # In production, use a sandboxed environment for executing untrusted code.\n", + " exec(matplotlib_code) # noqa: S102\n", + "else:\n", + " print(\"No matplotlib code found in the response.\")" + ] } ], "metadata": { @@ -377,9 +930,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.4" + "version": "3.12.14" } }, "nbformat": 4, "nbformat_minor": 2 -} \ No newline at end of file +} diff --git a/content/github/claude-cookbooks/skills/CLAUDE.md b/content/github/claude-cookbooks/skills/CLAUDE.md index 4ebc5f2fb9..6cdcdc8f82 100644 --- a/content/github/claude-cookbooks/skills/CLAUDE.md +++ b/content/github/claude-cookbooks/skills/CLAUDE.md @@ -65,8 +65,8 @@ skills/ **Files API Integration:** - Skills generate files and return `file_id` attributes -- Must use `client.beta.files.download()` to download files -- Must use `client.beta.files.retrieve_metadata()` to get file info +- Use `client.files.download()` to download files (GA in SDK 2.x; `client.beta.files` still works) +- Use `client.files.retrieve_metadata()` to get file info - Helper functions in `file_utils.py` handle extraction and download **Built-in Skills:** @@ -78,23 +78,23 @@ skills/ ## Development Gotchas ### 1. SDK Version -**Important**: Ensure you have the Anthropic SDK version 0.71.0 or later with Skills support +**Important**: Ensure you have the Anthropic SDK version 2.0.0 or later. In 2.x the Skills and Files APIs are GA (`client.skills`, `client.files`); skill objects expose `display_name` / `latest_version_id` and skill versions are addressed by `id`. ```bash -pip install anthropic>=0.71.0 +pip install "anthropic>=2.0.0" # Restart Jupyter kernel after installation if upgrading! ``` -### 2. Beta Namespace Required -**Problem**: `container` parameter not recognized, files API fails -**Solution**: Use `client.beta.messages.create()` and `client.beta.files.*` +### 2. Beta Namespace for Skills Messages +**Problem**: `betas` parameter not recognized +**Solution**: Use `client.beta.messages.create()` for requests that pass `betas=[...]`; download files with `client.files.download()` ```python # ❌ Wrong -response = client.messages.create(container={...}) +response = client.messages.create(container={...}, betas=[...]) content = client.files.content(file_id) # ✅ Correct -response = client.beta.messages.create(container={...}) -content = client.beta.files.content(file_id) +response = client.beta.messages.create(container={...}, betas=[...]) +content = client.files.download(file_id) ``` ### 3. Beta Headers Placement @@ -125,17 +125,17 @@ file_ids = extract_file_ids(response) **Solution**: Use `.read()` for file content and `.size_bytes` for file size ```python # ❌ Wrong -file_content = client.beta.files.download(file_id) +file_content = client.files.download(file_id) with open(path, 'wb') as f: f.write(file_content.content) # No .content attribute! # ✅ Correct -file_content = client.beta.files.download(file_id) +file_content = client.files.download(file_id) with open(path, 'wb') as f: f.write(file_content.read()) # Use .read() -# FileMetadata fields: id, filename, size_bytes (not size), mime_type, created_at, type, downloadable -metadata = client.beta.files.retrieve_metadata(file_id) +# FileMetadata fields: id, filename, size_bytes (not size), mime_type, created_at, type, downloadable, expires_at +metadata = client.files.retrieve_metadata(file_id) print(f"Size: {metadata.size_bytes} bytes") # Use size_bytes, not size ``` @@ -193,7 +193,7 @@ Be patient - the cell will show [*] while running! **Note**: Files are overwritten by default. You'll see `[overwritten]` in the download summary when a file already existed. Set `overwrite=False` to prevent this. ### Debugging API Errors -1. Check SDK version: `anthropic.__version__` should be `0.69.0` +1. Check SDK version: `anthropic.__version__` should be `2.0.0` or later 2. Verify beta headers are passed per-request 3. Ensure code_execution tool is included 4. Check response structure with `print(response)` diff --git a/content/github/claude-cookbooks/skills/README.md b/content/github/claude-cookbooks/skills/README.md index 145bca5f0f..67f42111a6 100644 --- a/content/github/claude-cookbooks/skills/README.md +++ b/content/github/claude-cookbooks/skills/README.md @@ -197,7 +197,7 @@ for block in response.content: # Step 3: Download the file using Files API if file_id: - file_content = client.beta.files.download(file_id=file_id) + file_content = client.files.download(file_id=file_id) # Step 4: Save to disk with open("outputs/budget.xlsx", "wb") as f: @@ -208,23 +208,25 @@ if file_id: ### Files API Methods +The Files API is GA in the Anthropic SDK 2.x, so these calls live on `client.files` (the older `client.beta.files` namespace still works). + ```python # Download file content (binary) -content = client.beta.files.download(file_id="file_abc123...") +content = client.files.download(file_id="file_abc123...") with open("output.xlsx", "wb") as f: f.write(content.read()) # Use .read() not .content # Get file metadata -info = client.beta.files.retrieve_metadata(file_id="file_abc123...") +info = client.files.retrieve_metadata(file_id="file_abc123...") print(f"Filename: {info.filename}, Size: {info.size_bytes} bytes") # Use size_bytes not size # List all files -files = client.beta.files.list() +files = client.files.list() for file in files.data: print(f"{file.filename} - {file.created_at}") # Delete a file -client.beta.files.delete(file_id="file_abc123...") +client.files.delete(file_id="file_abc123...") ``` **Important Notes:** diff --git a/content/github/claude-cookbooks/skills/notebooks/01_skills_introduction.ipynb b/content/github/claude-cookbooks/skills/notebooks/01_skills_introduction.ipynb index 6c77b2d780..3ea900b175 100644 --- a/content/github/claude-cookbooks/skills/notebooks/01_skills_introduction.ipynb +++ b/content/github/claude-cookbooks/skills/notebooks/01_skills_introduction.ipynb @@ -28,7 +28,7 @@ { "cell_type": "markdown", "metadata": {}, - "source": "**If you see any ❌ or ⚠️ warnings above**, please complete the setup steps before continuing.\n\n**If anthropic SDK version is too old (needs 0.71.0 or later):**\n```bash\npip install anthropic>=0.71.0\n```\nThen **restart the Jupyter kernel** to pick up the new version.\n\n---\n\n### API Configuration\n\nNow let's load the API key and configure the client:" + "source": "**If you see any ❌ or ⚠️ warnings above**, please complete the setup steps before continuing.\n\n**If anthropic SDK version is too old (needs 2.0.0 or later):**\n```bash\npip install \"anthropic>=2.0.0\"\n```\nThen **restart the Jupyter kernel** to pick up the new version.\n\n---\n\n### API Configuration\n\nNow let's load the API key and configure the client:" }, { "cell_type": "markdown", @@ -252,26 +252,22 @@ "outputs": [], "source": [ "# List all available Anthropic skills\n", - "# Note: Skills API requires the skills beta header\n", - "client_with_skills_beta = Anthropic(\n", - " api_key=API_KEY, default_headers={\"anthropic-beta\": \"skills-2025-10-02\"}\n", - ")\n", - "\n", - "skills_response = client_with_skills_beta.beta.skills.list(source=\"anthropic\")\n", + "# Note: the Skills API is GA in SDK 2.x (client.skills), no beta header needed\n", + "skills_response = client.skills.list(source=\"anthropic\")\n", "\n", "print(\"Available Anthropic-Managed Skills:\")\n", "print(\"=\" * 80)\n", "\n", "for skill in skills_response.data:\n", " print(f\"\\n📦 Skill ID: {skill.id}\")\n", - " print(f\" Title: {skill.display_title}\")\n", - " print(f\" Latest Version: {skill.latest_version}\")\n", + " print(f\" Name: {skill.display_name}\")\n", + " print(f\" Latest Version: {skill.latest_version_id}\")\n", " print(f\" Created: {skill.created_at}\")\n", "\n", " # Get version details\n", " try:\n", - " version_info = client_with_skills_beta.beta.skills.versions.retrieve(\n", - " skill_id=skill.id, version=skill.latest_version\n", + " version_info = client.skills.versions.retrieve(\n", + " skill_id=skill.id, version=skill.latest_version_id\n", " )\n", " print(f\" Name: {version_info.name}\")\n", " print(f\" Description: {version_info.description}\")\n", diff --git a/content/github/claude-cookbooks/skills/notebooks/02_skills_financial_applications.ipynb b/content/github/claude-cookbooks/skills/notebooks/02_skills_financial_applications.ipynb index ee4e3c7f9b..9c89bf2c01 100644 --- a/content/github/claude-cookbooks/skills/notebooks/02_skills_financial_applications.ipynb +++ b/content/github/claude-cookbooks/skills/notebooks/02_skills_financial_applications.ipynb @@ -37,7 +37,7 @@ "\n", "**Required:**\n", "- Anthropic API key configured\n", - "- SDK version 0.69.0 installed from whl\n", + "- Anthropic SDK 2.0.0 or later (`pip install -r requirements.txt`)\n", "- Virtual environment activated" ] }, diff --git a/content/github/claude-cookbooks/skills/notebooks/03_skills_custom_development.ipynb b/content/github/claude-cookbooks/skills/notebooks/03_skills_custom_development.ipynb index 9cb2146836..1e31a0df7b 100644 --- a/content/github/claude-cookbooks/skills/notebooks/03_skills_custom_development.ipynb +++ b/content/github/claude-cookbooks/skills/notebooks/03_skills_custom_development.ipynb @@ -53,8 +53,8 @@ "\n", "Before starting, ensure you have:\n", "- Completed [Notebook 1: Introduction to Skills](01_skills_introduction.ipynb)\n", - "- An Anthropic API key with Skills beta access\n", - "- Python environment with the local SDK installed" + "- An Anthropic API key with Skills access\n", + "- Python environment with the Anthropic SDK 2.0.0 or later installed" ] }, { @@ -110,8 +110,8 @@ " \"ANTHROPIC_API_KEY not found. Copy ../.env.example to ../.env and add your API key.\"\n", " )\n", "\n", - "# Initialize client with Skills beta\n", - "client = Anthropic(api_key=API_KEY, default_headers={\"anthropic-beta\": \"skills-2025-10-02\"})\n", + "# Initialize client (the Skills API is GA in SDK 2.x: client.skills needs no beta header)\n", + "client = Anthropic(api_key=API_KEY)\n", "\n", "# Setup directories\n", "SKILLS_DIR = Path.cwd().parent / \"custom_skills\"\n", @@ -122,13 +122,13 @@ "print(f\"✓ Using model: {MODEL}\")\n", "print(f\"✓ Custom skills directory: {SKILLS_DIR}\")\n", "print(f\"✓ Output directory: {OUTPUT_DIR}\")\n", - "print(\"\\n📝 Skills beta header configured for skill management\")" + "print(\"\\n📝 Skills API ready for skill management\")" ] }, { "cell_type": "markdown", "metadata": {}, - "source": "## 2. Understanding Custom Skills Architecture {#architecture}\n\n### Skill Structure\n\nEvery custom skill follows this directory structure:\n\n```\nskill_name/\n├── SKILL.md # REQUIRED: Instructions with YAML frontmatter\n├── *.md # Optional: Any additional .md files (documentation, guides)\n├── scripts/ # Optional: Executable code\n│ ├── process.py\n│ └── utils.js\n└── resources/ # Optional: Templates, data files\n └── template.xlsx\n```\n\n**Important:** \n- **SKILL.md is the ONLY required file** - everything else is optional\n- **Multiple .md files allowed** - You can have any number of markdown files in the top-level folder\n- **All .md files are loaded** - Not just SKILL.md and REFERENCE.md, but any .md file you include\n- **Organize as needed** - Use multiple .md files to structure complex documentation\n\n📖 Read our engineering blog post on [Equipping agents for the real world with Skills](https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills)\n\n### Skills Are Not Just Markdown\n\n![Skills Can Include Scripts and Files](../assets/not-just-markdown.png)\n\nSkills can bundle various file types:\n- **Markdown files**: Instructions and documentation (SKILL.md, REFERENCE.md, etc.)\n- **Scripts**: Python, JavaScript, or other executable code for complex operations\n- **Templates**: Pre-built files that can be customized (Excel templates, document templates)\n- **Resources**: Supporting data files, configuration, or assets\n\n### SKILL.md Requirements\n\nThe `SKILL.md` file must include:\n\n1. **YAML Frontmatter** (name: 64 chars, description: 1024 chars)\n - `name`: Lowercase alphanumeric with hyphens (required)\n - `description`: Brief description of what the skill does (required)\n\n2. **Instructions** (markdown format)\n - Clear guidance for Claude\n - Examples of usage\n - Any constraints or rules\n - Recommended: Keep under 5,000 tokens\n\n### Additional Documentation Files\n\nYou can include multiple markdown files for better organization:\n\n```\nskill_name/\n├── SKILL.md # Main instructions (required)\n├── REFERENCE.md # API reference (optional)\n├── EXAMPLES.md # Usage examples (optional)\n├── TROUBLESHOOTING.md # Common issues (optional)\n└── CHANGELOG.md # Version history (optional)\n```\n\nAll `.md` files in the root directory will be available to Claude when the skill is loaded.\n\n### Bundled Files Example\n\n![Bundled Files in Skills](../assets/skills-bundled-files.png)\n\nThis example shows how Skills can bundle multiple files:\n- **SKILL.md**: Contains the main instructions with colors, typography, and sections\n- **slide-decks.md**: Additional documentation for specific use cases\n- **Scripts and resources**: Can be referenced and used during skill execution\n\n### Progressive Disclosure\n\nSkills load in three stages to optimize token usage:\n\n| Stage | Content | Token Cost | When Loaded |\n|-------|---------|------------|-------------|\n| **1. Metadata** | Name & description | name: 64 chars, description: 1024 chars | Always visible |\n| **2. Instructions** | All .md files | <5,000 tokens recommended | When relevant |\n| **3. Resources** | Scripts & files | As needed | During execution |\n\n### API Workflow\n\n```python\n# 1. Create skill\nskill = client.beta.skills.create(\n display_title=\"My Skill\",\n files=files_from_dir(\"path/to/skill\")\n)\n\n# 2. Use in messages\nresponse = client.beta.messages.create(\n container={\n \"skills\": [{\n \"type\": \"custom\",\n \"skill_id\": skill.id,\n \"version\": \"latest\"\n }]\n },\n # ... rest of message parameters\n)\n```\n\n### Best Practices\n\nFor detailed guidance on skill creation and best practices, see:\n- [Claude Skills Best Practices](https://docs.claude.com/en/docs/agents-and-tools/agent-skills/best-practices)\n- [Skills Documentation](https://docs.claude.com/en/docs/agents-and-tools/agent-skills/overview)" + "source": "## 2. Understanding Custom Skills Architecture {#architecture}\n\n### Skill Structure\n\nEvery custom skill follows this directory structure:\n\n```\nskill_name/\n├── SKILL.md # REQUIRED: Instructions with YAML frontmatter\n├── *.md # Optional: Any additional .md files (documentation, guides)\n├── scripts/ # Optional: Executable code\n│ ├── process.py\n│ └── utils.js\n└── resources/ # Optional: Templates, data files\n └── template.xlsx\n```\n\n**Important:** \n- **SKILL.md is the ONLY required file** - everything else is optional\n- **Multiple .md files allowed** - You can have any number of markdown files in the top-level folder\n- **All .md files are loaded** - Not just SKILL.md and REFERENCE.md, but any .md file you include\n- **Organize as needed** - Use multiple .md files to structure complex documentation\n\n📖 Read our engineering blog post on [Equipping agents for the real world with Skills](https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills)\n\n### Skills Are Not Just Markdown\n\n![Skills Can Include Scripts and Files](../assets/not-just-markdown.png)\n\nSkills can bundle various file types:\n- **Markdown files**: Instructions and documentation (SKILL.md, REFERENCE.md, etc.)\n- **Scripts**: Python, JavaScript, or other executable code for complex operations\n- **Templates**: Pre-built files that can be customized (Excel templates, document templates)\n- **Resources**: Supporting data files, configuration, or assets\n\n### SKILL.md Requirements\n\nThe `SKILL.md` file must include:\n\n1. **YAML Frontmatter** (name: 64 chars, description: 1024 chars)\n - `name`: Lowercase alphanumeric with hyphens (required)\n - `description`: Brief description of what the skill does (required)\n\n2. **Instructions** (markdown format)\n - Clear guidance for Claude\n - Examples of usage\n - Any constraints or rules\n - Recommended: Keep under 5,000 tokens\n\n### Additional Documentation Files\n\nYou can include multiple markdown files for better organization:\n\n```\nskill_name/\n├── SKILL.md # Main instructions (required)\n├── REFERENCE.md # API reference (optional)\n├── EXAMPLES.md # Usage examples (optional)\n├── TROUBLESHOOTING.md # Common issues (optional)\n└── CHANGELOG.md # Version history (optional)\n```\n\nAll `.md` files in the root directory will be available to Claude when the skill is loaded.\n\n### Bundled Files Example\n\n![Bundled Files in Skills](../assets/skills-bundled-files.png)\n\nThis example shows how Skills can bundle multiple files:\n- **SKILL.md**: Contains the main instructions with colors, typography, and sections\n- **slide-decks.md**: Additional documentation for specific use cases\n- **Scripts and resources**: Can be referenced and used during skill execution\n\n### Progressive Disclosure\n\nSkills load in three stages to optimize token usage:\n\n| Stage | Content | Token Cost | When Loaded |\n|-------|---------|------------|-------------|\n| **1. Metadata** | Name & description | name: 64 chars, description: 1024 chars | Always visible |\n| **2. Instructions** | All .md files | <5,000 tokens recommended | When relevant |\n| **3. Resources** | Scripts & files | As needed | During execution |\n\n### API Workflow\n\n```python\n# 1. Create skill\nskill = client.skills.create(\n display_name=\"My Skill\",\n files=files_from_dir(\"path/to/skill\")\n)\n\n# 2. Use in messages\nresponse = client.beta.messages.create(\n container={\n \"skills\": [{\n \"type\": \"custom\",\n \"skill_id\": skill.id,\n \"version\": \"latest\"\n }]\n },\n # ... rest of message parameters\n)\n```\n\n### Best Practices\n\nFor detailed guidance on skill creation and best practices, see:\n- [Claude Skills Best Practices](https://docs.claude.com/en/docs/agents-and-tools/agent-skills/best-practices)\n- [Skills Documentation](https://docs.claude.com/en/docs/agents-and-tools/agent-skills/overview)" }, { "cell_type": "markdown", @@ -145,29 +145,27 @@ "metadata": {}, "outputs": [], "source": [ - "def create_skill(client: Anthropic, skill_path: str, display_title: str) -> dict[str, Any]:\n", + "def create_skill(client: Anthropic, skill_path: str, display_name: str) -> dict[str, Any]:\n", " \"\"\"\n", " Create a new custom skill from a directory.\n", "\n", " Args:\n", " client: Anthropic client instance\n", " skill_path: Path to skill directory\n", - " display_title: Human-readable skill name\n", + " display_name: Human-readable skill name\n", "\n", " Returns:\n", " Dictionary with skill_id, version, and metadata\n", " \"\"\"\n", " try:\n", " # Create skill using files_from_dir\n", - " skill = client.beta.skills.create(\n", - " display_title=display_title, files=files_from_dir(skill_path)\n", - " )\n", + " skill = client.skills.create(display_name=display_name, files=files_from_dir(skill_path))\n", "\n", " return {\n", " \"success\": True,\n", " \"skill_id\": skill.id,\n", - " \"display_title\": skill.display_title,\n", - " \"latest_version\": skill.latest_version,\n", + " \"display_name\": skill.display_name,\n", + " \"latest_version_id\": skill.latest_version_id,\n", " \"created_at\": skill.created_at,\n", " \"source\": skill.source,\n", " }\n", @@ -183,15 +181,15 @@ " List of skill dictionaries\n", " \"\"\"\n", " try:\n", - " skills_response = client.beta.skills.list(source=\"custom\")\n", + " skills_response = client.skills.list(source=\"custom\")\n", "\n", " skills = []\n", " for skill in skills_response.data:\n", " skills.append(\n", " {\n", " \"skill_id\": skill.id,\n", - " \"display_title\": skill.display_title,\n", - " \"latest_version\": skill.latest_version,\n", + " \"display_name\": skill.display_name,\n", + " \"latest_version_id\": skill.latest_version_id,\n", " \"created_at\": skill.created_at,\n", " \"updated_at\": skill.updated_at,\n", " }\n", @@ -215,14 +213,8 @@ " True if successful, False otherwise\n", " \"\"\"\n", " try:\n", - " # First delete all versions\n", - " versions = client.beta.skills.versions.list(skill_id=skill_id)\n", - "\n", - " for version in versions.data:\n", - " client.beta.skills.versions.delete(skill_id=skill_id, version=version.version)\n", - "\n", - " # Then delete the skill itself\n", - " client.beta.skills.delete(skill_id)\n", + " # Deleting a skill also deletes all of its versions\n", + " client.skills.delete(skill_id)\n", " return True\n", "\n", " except Exception as e:\n", @@ -313,8 +305,8 @@ "if existing_skills:\n", " print(f\"Found {len(existing_skills)} existing custom skill(s):\")\n", " for skill in existing_skills:\n", - " print(f\" - {skill['display_title']} (ID: {skill['skill_id']})\")\n", - " if skill[\"display_title\"] in skill_titles_to_create:\n", + " print(f\" - {skill['display_name']} (ID: {skill['skill_id']})\")\n", + " if skill[\"display_name\"] in skill_titles_to_create:\n", " conflicting_skills.append(skill)\n", "\n", " if conflicting_skills:\n", @@ -322,7 +314,7 @@ " f\"\\n⚠️ Found {len(conflicting_skills)} skill(s) that will conflict with this notebook:\"\n", " )\n", " for skill in conflicting_skills:\n", - " print(f\" - {skill['display_title']} (ID: {skill['skill_id']})\")\n", + " print(f\" - {skill['display_name']} (ID: {skill['skill_id']})\")\n", "\n", " print(\"\\n\" + \"=\" * 70)\n", " print(\"To clean up these skills and start fresh, uncomment and run:\")\n", @@ -330,15 +322,15 @@ " print(\"\\n# UNCOMMENT THE LINES BELOW TO DELETE CONFLICTING SKILLS:\")\n", " print(\"# for skill in conflicting_skills:\")\n", " print(\"# if delete_skill(client, skill['skill_id']):\")\n", - " print(\"# print(f\\\"✅ Deleted: {skill['display_title']}\\\")\")\n", + " print(\"# print(f\\\"✅ Deleted: {skill['display_name']}\\\")\")\n", " print(\"# else:\")\n", - " print(\"# print(f\\\"❌ Failed to delete: {skill['display_title']}\\\")\")\n", + " print(\"# print(f\\\"❌ Failed to delete: {skill['display_name']}\\\")\")\n", "\n", " # for skill in conflicting_skills:\n", " # if delete_skill(client, skill['skill_id']):\n", - " # print(f\"✅ Deleted: {skill['display_title']}\")\n", + " # print(f\"✅ Deleted: {skill['display_name']}\")\n", " # else:\n", - " # print(f\"❌ Failed to delete: {skill['display_title']}\")\n", + " # print(f\"❌ Failed to delete: {skill['display_name']}\")\n", " else:\n", " print(\"\\n✅ No conflicting skills found. Ready to proceed!\")\n", "else:\n", @@ -388,14 +380,14 @@ " financial_skill_id = result[\"skill_id\"]\n", " print(\"✅ Skill uploaded successfully!\")\n", " print(f\" Skill ID: {financial_skill_id}\")\n", - " print(f\" Version: {result['latest_version']}\")\n", + " print(f\" Version: {result['latest_version_id']}\")\n", " print(f\" Created: {result['created_at']}\")\n", " else:\n", " print(f\"❌ Upload failed: {result['error']}\")\n", - " if \"cannot reuse an existing display_title\" in str(result[\"error\"]):\n", + " if \"already exists\" in str(result[\"error\"]) or \"cannot reuse\" in str(result[\"error\"]):\n", " print(\"\\n💡 Solution: A skill with this name already exists.\")\n", " print(\" Run the 'Clean Up Existing Skills' cell above to delete it first,\")\n", - " print(\" or change the display_title to something unique.\")\n", + " print(\" or change the display_name to something unique.\")\n", "else:\n", " print(f\"⚠️ Skill directory not found: {financial_skill_path}\")\n", " print(\n", @@ -487,13 +479,13 @@ " brand_skill_id = result[\"skill_id\"]\n", " print(\"✅ Skill uploaded successfully!\")\n", " print(f\" Skill ID: {brand_skill_id}\")\n", - " print(f\" Version: {result['latest_version']}\")\n", + " print(f\" Version: {result['latest_version_id']}\")\n", " else:\n", " print(f\"❌ Upload failed: {result['error']}\")\n", - " if \"cannot reuse an existing display_title\" in str(result[\"error\"]):\n", + " if \"already exists\" in str(result[\"error\"]) or \"cannot reuse\" in str(result[\"error\"]):\n", " print(\"\\n💡 Solution: A skill with this name already exists.\")\n", " print(\" Run the 'Clean Up Existing Skills' cell above to delete it first,\")\n", - " print(\" or change the display_title to something unique.\")\n", + " print(\" or change the display_name to something unique.\")\n", "else:\n", " print(f\"⚠️ Skill directory not found: {brand_skill_path}\")" ] @@ -607,7 +599,7 @@ " modeling_skill_id = result[\"skill_id\"]\n", " print(\"✅ Skill uploaded successfully!\")\n", " print(f\" Skill ID: {modeling_skill_id}\")\n", - " print(f\" Version: {result['latest_version']}\")\n", + " print(f\" Version: {result['latest_version_id']}\")\n", " print(\"\\nThis skill includes:\")\n", " print(\" - DCF valuation model (dcf_model.py)\")\n", " print(\" - Sensitivity analysis framework (sensitivity_analysis.py)\")\n", @@ -740,9 +732,9 @@ " print(f\"You have {len(my_skills)} custom skill(s):\\n\")\n", " print(\"=\" * 70)\n", " for i, skill in enumerate(my_skills, 1):\n", - " print(f\"\\n{i}. {skill['display_title']}\")\n", + " print(f\"\\n{i}. {skill['display_name']}\")\n", " print(f\" Skill ID: {skill['skill_id']}\")\n", - " print(f\" Current Version: {skill['latest_version']}\")\n", + " print(f\" Current Version: {skill['latest_version_id']}\")\n", " print(f\" Created: {skill['created_at']}\")\n", " if skill.get(\"updated_at\"):\n", " print(f\" Last Updated: {skill['updated_at']}\")\n", @@ -837,12 +829,10 @@ "def create_skill_version(client: Anthropic, skill_id: str, skill_path: str):\n", " \"\"\"Create a new version of an existing skill.\"\"\"\n", " try:\n", - " version = client.beta.skills.versions.create(\n", - " skill_id=skill_id, files=files_from_dir(skill_path)\n", - " )\n", + " version = client.skills.versions.create(skill_id=skill_id, files=files_from_dir(skill_path))\n", " return {\n", " \"success\": True,\n", - " \"version\": version.version,\n", + " \"version_id\": version.id,\n", " \"created_at\": version.created_at,\n", " }\n", " except Exception as e:\n", @@ -859,11 +849,11 @@ "\n", " if result[\"success\"]:\n", " print(\"✅ New version created successfully!\")\n", - " print(f\" Version: {result['version']}\")\n", + " print(f\" Version ID: {result['version_id']}\")\n", " print(f\" Created: {result['created_at']}\")\n", " print(\"\\n📊 Version History:\")\n", - " print(\" v1: Original skill with tech, retail, financial, manufacturing\")\n", - " print(f\" v{result['version']}: Enhanced with healthcare industry benchmarks\")\n", + " print(\" Initial version: Original skill with tech, retail, financial, manufacturing\")\n", + " print(f\" {result['version_id']}: Enhanced with healthcare industry benchmarks\")\n", " else:\n", " print(f\"❌ Version creation failed: {result['error']}\")\n", "else:\n", @@ -972,7 +962,7 @@ " other_skills = []\n", "\n", " for skill in all_skills:\n", - " if skill[\"display_title\"] in notebook_skill_names:\n", + " if skill[\"display_name\"] in notebook_skill_names:\n", " notebook_skills.append(skill)\n", " else:\n", " other_skills.append(skill)\n", @@ -986,9 +976,9 @@ " if notebook_skills:\n", " print(f\"\\n📚 Skills created by this notebook ({len(notebook_skills)}):\")\n", " for skill in notebook_skills:\n", - " print(f\" • {skill['display_title']}\")\n", + " print(f\" • {skill['display_name']}\")\n", " print(f\" ID: {skill['skill_id']}\")\n", - " print(f\" Version: {skill['latest_version']}\")\n", + " print(f\" Version: {skill['latest_version_id']}\")\n", " print(f\" Created: {skill['created_at']}\")\n", " else:\n", " print(\"\\n✅ No skills from this notebook found\")\n", @@ -996,7 +986,7 @@ " if other_skills:\n", " print(f\"\\n🔧 Other skills in workspace ({len(other_skills)}):\")\n", " for skill in other_skills:\n", - " print(f\" • {skill['display_title']} (v{skill['latest_version']})\")\n", + " print(f\" • {skill['display_name']} ({skill['latest_version_id']})\")\n", "\n", " # Cleanup options\n", " if notebook_skills:\n", @@ -1013,7 +1003,7 @@ "\n", " print(\"\\nThis would delete:\")\n", " for skill in notebook_skills:\n", - " print(f\" • {skill['display_title']}\")\n", + " print(f\" • {skill['display_name']}\")\n", " else:\n", " print(\"\\n⚠️ DELETION MODE - Skills will be permanently removed\")\n", " print(\"\\nDeleting notebook skills...\")\n", @@ -1021,10 +1011,10 @@ " success_count = 0\n", " for skill in notebook_skills:\n", " if delete_skill(client, skill[\"skill_id\"]):\n", - " print(f\" ✅ Deleted: {skill['display_title']}\")\n", + " print(f\" ✅ Deleted: {skill['display_name']}\")\n", " success_count += 1\n", " else:\n", - " print(f\" ❌ Failed to delete: {skill['display_title']}\")\n", + " print(f\" ❌ Failed to delete: {skill['display_name']}\")\n", "\n", " print(f\"\\n📊 Cleanup complete: {success_count}/{len(notebook_skills)} skills deleted\")\n", "\n", diff --git a/content/github/claude-cookbooks/tool_evaluation/tool_evaluation.ipynb b/content/github/claude-cookbooks/tool_evaluation/tool_evaluation.ipynb index 92e2416901..8b0088163f 100644 --- a/content/github/claude-cookbooks/tool_evaluation/tool_evaluation.ipynb +++ b/content/github/claude-cookbooks/tool_evaluation/tool_evaluation.ipynb @@ -11,10 +11,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 1, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:51:35.651982Z", + "iopub.status.busy": "2026-10-21T16:51:35.651854Z", + "iopub.status.idle": "2026-10-21T16:51:36.437821Z", + "shell.execute_reply": "2026-10-21T16:51:36.437403Z" + } + }, "outputs": [], - "source": "import json\nimport re\nimport time\nimport traceback\nimport xml.etree.ElementTree as ET # noqa: S314\nfrom pathlib import Path\nfrom typing import Any\n\nfrom anthropic import Anthropic" + "source": [ + "import json\n", + "import re\n", + "import time\n", + "import traceback\n", + "import xml.etree.ElementTree as ET # noqa: S314\n", + "from pathlib import Path\n", + "from typing import Any\n", + "\n", + "from anthropic import Anthropic" + ] }, { "cell_type": "markdown", @@ -26,7 +43,14 @@ { "cell_type": "code", "execution_count": 2, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:51:36.443552Z", + "iopub.status.busy": "2026-10-21T16:51:36.443337Z", + "iopub.status.idle": "2026-10-21T16:51:36.446410Z", + "shell.execute_reply": "2026-10-21T16:51:36.445507Z" + } + }, "outputs": [], "source": [ "# Embedded evaluator prompt\n", @@ -74,10 +98,88 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 3, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:51:36.447700Z", + "iopub.status.busy": "2026-10-21T16:51:36.447586Z", + "iopub.status.idle": "2026-10-21T16:51:36.473024Z", + "shell.execute_reply": "2026-10-21T16:51:36.472368Z" + } + }, "outputs": [], - "source": "client = Anthropic()\nmodel = \"claude-sonnet-5-5\"\n\n\ndef agent_loop(prompt: str, tools: list[dict[str, Any]] = None) -> tuple[str, dict[str, Any]]:\n \"\"\"Simplified agent class for tool evaluation\"\"\"\n messages = [{\"role\": \"user\", \"content\": prompt}]\n\n response = client.messages.create(\n model=model,\n max_tokens=4096,\n system=EVALUATION_PROMPT,\n messages=messages,\n tools=tools,\n )\n\n messages.append({\"role\": \"assistant\", \"content\": response.content})\n\n # Track tool calls with timing\n tool_metrics = {} # {tool_name: {\"count\": N, \"durations\": [X1, X2, ...]}}\n\n def _prepare_tool_result(tool_use_id, tool_result):\n return {\n \"role\": \"user\",\n \"content\": [\n {\n \"type\": \"tool_result\",\n \"tool_use_id\": tool_use_id,\n \"content\": tool_result,\n }\n ],\n }\n\n while response.stop_reason == \"tool_use\":\n tool_use = next(block for block in response.content if block.type == \"tool_use\")\n tool_name = tool_use.name\n\n tool_start_ts = time.time()\n try:\n # Note: eval is used here for demonstration purposes to dynamically call tool functions.\n # In production, use a safer dispatch mechanism like a dictionary of functions.\n tool_response = eval( # noqa: S307\n f\"{tool_name}(**tool_use.input)\"\n ) # Call the tool function with its input\n except Exception as e:\n tool_response = f\"Error executing tool {tool_name}: {str(e)}\\n\"\n tool_response += traceback.format_exc()\n tool_duration = time.time() - tool_start_ts\n\n # Update tool metrics\n if tool_name not in tool_metrics:\n tool_metrics[tool_name] = {\"count\": 0, \"durations\": []}\n tool_metrics[tool_name][\"count\"] += 1\n tool_metrics[tool_name][\"durations\"].append(tool_duration)\n\n # Prepare tool result and append to messages\n messages.append(_prepare_tool_result(tool_use.id, tool_response))\n response = client.messages.create(\n model=model,\n max_tokens=4096,\n system=EVALUATION_PROMPT,\n messages=messages,\n tools=tools,\n )\n messages.append({\"role\": \"assistant\", \"content\": response.content})\n\n response = next(\n (block.text for block in response.content if hasattr(block, \"text\")),\n None,\n )\n return response, tool_metrics" + "source": [ + "client = Anthropic()\n", + "model = \"claude-sonnet-5-5\"\n", + "\n", + "\n", + "def agent_loop(prompt: str, tools: list[dict[str, Any]] = None) -> tuple[str, dict[str, Any]]:\n", + " \"\"\"Simplified agent class for tool evaluation\"\"\"\n", + " messages = [{\"role\": \"user\", \"content\": prompt}]\n", + "\n", + " response = client.messages.create(\n", + " model=model,\n", + " max_tokens=4096,\n", + " system=EVALUATION_PROMPT,\n", + " messages=messages,\n", + " tools=tools,\n", + " )\n", + "\n", + " messages.append({\"role\": \"assistant\", \"content\": response.content})\n", + "\n", + " # Track tool calls with timing\n", + " tool_metrics = {} # {tool_name: {\"count\": N, \"durations\": [X1, X2, ...]}}\n", + "\n", + " def _prepare_tool_result(tool_use_id, tool_result):\n", + " return {\n", + " \"type\": \"tool_result\",\n", + " \"tool_use_id\": tool_use_id,\n", + " \"content\": tool_result,\n", + " }\n", + "\n", + " while response.stop_reason == \"tool_use\":\n", + " # The model may call several tools in one turn; every tool_use needs a tool_result\n", + " tool_results = []\n", + " for tool_use in (block for block in response.content if block.type == \"tool_use\"):\n", + " tool_name = tool_use.name\n", + "\n", + " tool_start_ts = time.time()\n", + " try:\n", + " # Note: eval is used here for demonstration purposes to dynamically call tool functions.\n", + " # In production, use a safer dispatch mechanism like a dictionary of functions.\n", + " tool_response = eval( # noqa: S307\n", + " f\"{tool_name}(**tool_use.input)\"\n", + " ) # Call the tool function with its input\n", + " except Exception as e:\n", + " tool_response = f\"Error executing tool {tool_name}: {str(e)}\\n\"\n", + " tool_response += traceback.format_exc()\n", + " tool_duration = time.time() - tool_start_ts\n", + "\n", + " # Update tool metrics\n", + " if tool_name not in tool_metrics:\n", + " tool_metrics[tool_name] = {\"count\": 0, \"durations\": []}\n", + " tool_metrics[tool_name][\"count\"] += 1\n", + " tool_metrics[tool_name][\"durations\"].append(tool_duration)\n", + "\n", + " tool_results.append(_prepare_tool_result(tool_use.id, tool_response))\n", + "\n", + " # Append all tool results in a single user message\n", + " messages.append({\"role\": \"user\", \"content\": tool_results})\n", + " response = client.messages.create(\n", + " model=model,\n", + " max_tokens=4096,\n", + " system=EVALUATION_PROMPT,\n", + " messages=messages,\n", + " tools=tools,\n", + " )\n", + " messages.append({\"role\": \"assistant\", \"content\": response.content})\n", + "\n", + " response = next(\n", + " (block.text for block in response.content if hasattr(block, \"text\")),\n", + " None,\n", + " )\n", + " return response, tool_metrics" + ] }, { "cell_type": "markdown", @@ -88,15 +190,55 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 4, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:51:36.474692Z", + "iopub.status.busy": "2026-10-21T16:51:36.474572Z", + "iopub.status.idle": "2026-10-21T16:51:36.478099Z", + "shell.execute_reply": "2026-10-21T16:51:36.477440Z" + } + }, "outputs": [], - "source": "def parse_evaluation_file(file_path: Path) -> list[dict[str, Any]]:\n \"\"\"Parse XML evaluation file and return list of evaluation tasks.\"\"\"\n try:\n # Parse trusted local XML evaluation file\n tree = ET.parse(file_path) # noqa: S314\n root = tree.getroot()\n evaluations = []\n\n # Check for task elements\n tasks = root.findall(\".//task\")\n for task in tasks:\n prompt_elem = task.find(\"prompt\")\n response_elem = task.find(\"response\")\n\n if prompt_elem is not None and response_elem is not None:\n eval_dict = {\n \"prompt\": (prompt_elem.text or \"\").strip(),\n \"response\": (response_elem.text or \"\").strip(),\n }\n evaluations.append(eval_dict)\n\n return evaluations\n except Exception as e:\n print(f\"Error parsing evaluation file {file_path}: {e}\")\n return []" + "source": [ + "def parse_evaluation_file(file_path: Path) -> list[dict[str, Any]]:\n", + " \"\"\"Parse XML evaluation file and return list of evaluation tasks.\"\"\"\n", + " try:\n", + " # Parse trusted local XML evaluation file\n", + " tree = ET.parse(file_path) # noqa: S314\n", + " root = tree.getroot()\n", + " evaluations = []\n", + "\n", + " # Check for task elements\n", + " tasks = root.findall(\".//task\")\n", + " for task in tasks:\n", + " prompt_elem = task.find(\"prompt\")\n", + " response_elem = task.find(\"response\")\n", + "\n", + " if prompt_elem is not None and response_elem is not None:\n", + " eval_dict = {\n", + " \"prompt\": (prompt_elem.text or \"\").strip(),\n", + " \"response\": (response_elem.text or \"\").strip(),\n", + " }\n", + " evaluations.append(eval_dict)\n", + "\n", + " return evaluations\n", + " except Exception as e:\n", + " print(f\"Error parsing evaluation file {file_path}: {e}\")\n", + " return []" + ] }, { "cell_type": "code", "execution_count": 5, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:51:36.479307Z", + "iopub.status.busy": "2026-10-21T16:51:36.479196Z", + "iopub.status.idle": "2026-10-21T16:51:36.482627Z", + "shell.execute_reply": "2026-10-21T16:51:36.482015Z" + } + }, "outputs": [], "source": [ "def evaluate_single_task(\n", @@ -143,7 +285,14 @@ { "cell_type": "code", "execution_count": 6, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:51:36.483915Z", + "iopub.status.busy": "2026-10-21T16:51:36.483800Z", + "iopub.status.idle": "2026-10-21T16:51:36.488518Z", + "shell.execute_reply": "2026-10-21T16:51:36.487872Z" + } + }, "outputs": [], "source": [ "# Report Templates\n", @@ -248,10 +397,47 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 7, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:51:36.490434Z", + "iopub.status.busy": "2026-10-21T16:51:36.490271Z", + "iopub.status.idle": "2026-10-21T16:51:36.493582Z", + "shell.execute_reply": "2026-10-21T16:51:36.492801Z" + } + }, "outputs": [], - "source": "def calculator(expression: str) -> str:\n \"\"\"A basic calculator that performs arithmetic operations.\"\"\"\n try:\n # Note: eval with restricted builtins is used here for demonstration.\n # In production, use a safer alternative like a math expression parser.\n result = eval(expression, {\"__builtins__\": {}}, {}) # noqa: S307\n return str(result)\n except Exception as e:\n return f\"Error: {str(e)}\"\n\n\n# Define the tool schema for the calculator\ncalculator_tool = {\n \"name\": \"calculator\",\n \"description\": \"\", # An unhelpful tool description.\n \"input_schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"expression\": {\n \"type\": \"string\",\n \"description\": \"\", # An unhelpful schema description.\n }\n },\n \"required\": [\"expression\"],\n },\n}\n\n# Set the tools list\ntools = [calculator_tool]" + "source": [ + "def calculator(expression: str) -> str:\n", + " \"\"\"A basic calculator that performs arithmetic operations.\"\"\"\n", + " try:\n", + " # Note: eval with restricted builtins is used here for demonstration.\n", + " # In production, use a safer alternative like a math expression parser.\n", + " result = eval(expression, {\"__builtins__\": {}}, {}) # noqa: S307\n", + " return str(result)\n", + " except Exception as e:\n", + " return f\"Error: {str(e)}\"\n", + "\n", + "\n", + "# Define the tool schema for the calculator\n", + "calculator_tool = {\n", + " \"name\": \"calculator\",\n", + " \"description\": \"\", # An unhelpful tool description.\n", + " \"input_schema\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"expression\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"\", # An unhelpful schema description.\n", + " }\n", + " },\n", + " \"required\": [\"expression\"],\n", + " },\n", + "}\n", + "\n", + "# Set the tools list\n", + "tools = [calculator_tool]" + ] }, { "cell_type": "markdown", @@ -263,7 +449,14 @@ { "cell_type": "code", "execution_count": 8, - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-10-21T16:51:36.495001Z", + "iopub.status.busy": "2026-10-21T16:51:36.494891Z", + "iopub.status.idle": "2026-10-21T16:52:27.928497Z", + "shell.execute_reply": "2026-10-21T16:52:27.927702Z" + } + }, "outputs": [ { "name": "stdout", @@ -273,30 +466,78 @@ "🚀 Starting Evaluation\n", "📋 Loaded 8 evaluation tasks\n", "Processing task 1/8\n", - "Task 1: Running task with prompt: Calculate the compound interest on $10,000 invested at 5% annual interest rate, compounded monthly for 3 years. What is the final amount in dollars (rounded to 2 decimal places)?\n", + "Task 1: Running task with prompt: Calculate the compound interest on $10,000 invested at 5% annual interest rate, compounded monthly for 3 years. What is the final amount in dollars (rounded to 2 decimal places)?\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "Processing task 2/8\n", - "Task 2: Running task with prompt: A projectile is launched at a 45-degree angle with an initial velocity of 50 m/s. Calculate the total distance (in meters) it has traveled from the launch point after 2 seconds, assuming g=9.8 m/s². Round to 2 decimal places.\n", + "Task 2: Running task with prompt: A projectile is launched at a 45-degree angle with an initial velocity of 50 m/s. Calculate the total distance (in meters) it has traveled from the launch point after 2 seconds, assuming g=9.8 m/s². Round to 2 decimal places.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "Processing task 3/8\n", - "Task 3: Running task with prompt: A sphere has a volume of 500 cubic meters. Calculate its surface area in square meters. Round to 2 decimal places.\n", + "Task 3: Running task with prompt: A sphere has a volume of 500 cubic meters. Calculate its surface area in square meters. Round to 2 decimal places.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "Processing task 4/8\n", - "Task 4: Running task with prompt: Calculate the population standard deviation of this dataset: [12, 15, 18, 22, 25, 30, 35]. Round to 2 decimal places.\n", + "Task 4: Running task with prompt: Calculate the population standard deviation of this dataset: [12, 15, 18, 22, 25, 30, 35]. Round to 2 decimal places.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "Processing task 5/8\n", - "Task 5: Running task with prompt: Calculate the pH of a solution with a hydrogen ion concentration of 3.5 × 10^-5 M. Round to 2 decimal places.\n", + "Task 5: Running task with prompt: Calculate the pH of a solution with a hydrogen ion concentration of 3.5 × 10^-5 M. Round to 2 decimal places.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "Processing task 6/8\n", - "Task 6: Running task with prompt: Calculate the monthly payment for a $200,000 mortgage at 4.5% annual interest rate for 30 years (360 months). Use the standard mortgage payment formula. Round to 2 decimal places.\n", + "Task 6: Running task with prompt: Calculate the monthly payment for a $200,000 mortgage at 4.5% annual interest rate for 30 years (360 months). Use the standard mortgage payment formula. Round to 2 decimal places.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "Processing task 7/8\n", - "Task 7: Running task with prompt: Calculate the energy in joules of a photon with wavelength 550 nanometers. Use h = 6.626 × 10^-34 J·s and c = 3 × 10^8 m/s. Express the answer in scientific notation with 2 significant figures after the decimal (e.g., 3.61e-19).\n", + "Task 7: Running task with prompt: Calculate the energy in joules of a photon with wavelength 550 nanometers. Use h = 6.626 × 10^-34 J·s and c = 3 × 10^8 m/s. Express the answer in scientific notation with 2 significant figures after the decimal (e.g., 3.61e-19).\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "Processing task 8/8\n", - "Task 8: Running task with prompt: Find the larger real root of the quadratic equation 3x² - 7x + 2 = 0. Give the exact value.\n", + "Task 8: Running task with prompt: Find the larger real root of the quadratic equation 3x² - 7x + 2 = 0. Give the exact value.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "\n", "# Evaluation Report\n", "\n", "## Summary\n", "\n", - "- **Accuracy**: 7/8 (87.5%)\n", - "- **Average Task Duration**: 22.73s\n", - "- **Average Tool Calls per Task**: 7.75\n", - "- **Total Tool Calls**: 62\n", + "- **Accuracy**: 8/8 (100.0%)\n", + "- **Average Task Duration**: 6.43s\n", + "- **Average Tool Calls per Task**: 2.75\n", + "- **Total Tool Calls**: 22\n", "\n", "---\n", "\n", @@ -304,56 +545,32 @@ "\n", "**Prompt**: Calculate the compound interest on $10,000 invested at 5% annual interest rate, compounded monthly for 3 years. What is the final amount in dollars (rounded to 2 decimal places)?\n", "**Ground Truth Response**: `11614.72`\n", - "**Actual Response**: `$11,614.72`\n", - "**Correct**: ❌\n", - "**Duration**: 18.64s\n", + "**Actual Response**: `11614.72`\n", + "**Correct**: ✅\n", + "**Duration**: 6.71s\n", "**Tool Calls**: {\n", " \"calculator\": {\n", - " \"count\": 6,\n", + " \"count\": 3,\n", " \"durations\": [\n", - " 9.560585021972656e-05,\n", - " 9.870529174804688e-05,\n", - " 8.988380432128906e-05,\n", - " 0.00011301040649414062,\n", - " 0.00010704994201660156,\n", - " 8.821487426757812e-05\n", + " 9.393692016601562e-05,\n", + " 0.00010085105895996094,\n", + " 8.034706115722656e-05\n", " ]\n", " }\n", "}\n", "\n", "**Summary**\n", - "I approached this compound interest calculation in the following steps:\n", - "\n", - "1. First, I identified the formula needed: P(1 + r/n)^(nt) where:\n", - " - P = principal ($10,000)\n", - " - r = annual interest rate (5% or 0.05)\n", - " - n = number of times compounded per year (12 for monthly)\n", - " - t = time in years (3)\n", - "\n", - "2. I initially tried using the calculator tool with the formula using ^ for exponentiation, but received an error.\n", - "\n", - "3. I corrected the syntax by using ** for exponentiation in Python, calculating 10000 * (1 + 0.05/12)**(12*3).\n", - "\n", - "4. The calculator returned 11614.722313334678.\n", - "\n", - "5. I attempted several approaches to round to 2 decimal places using functions like round() and int(), but these weren't available in the calculator environment.\n", - "\n", - "6. Since the calculator doesn't have built-in rounding functions, I had to manually round the result to 2 decimal places: $11,614.72.\n", + "1. I called the calculator with `10000 * (1 + 0.05/12)^(36)`. It returned an error because the `^` operator isn't supported for floats.\n", + "2. I called it again with `round(10000 * (1 + 0.05/12)**36, 2)`. It returned an error because `round` isn't defined.\n", + "3. I called it a third time with `10000 * (1 + 0.05/12)**36`. It returned 11614.722313334678.\n", + "4. I rounded that result to 2 decimal places by hand, which gives 11614.72.\n", "\n", "**Feedback**\n", - "The calculator tool has both strengths and areas for improvement:\n", - "\n", - "1. Tool name: \"calculator\" is clear and descriptive, immediately conveying its purpose.\n", - "\n", - "2. Input parameters: The \"expression\" parameter is simple, but lacks description of what syntax is supported. It would be helpful to specify that it uses Python syntax (particularly ** for exponentiation rather than ^).\n", - "\n", - "3. Error messaging: The error messages are helpful in identifying syntax issues, but don't provide guidance on how to fix them.\n", - "\n", - "4. Functionality limitations: The calculator doesn't support common mathematical functions like round(), int(), or the math module. It would be more useful if it included basic rounding and mathematical functions.\n", - "\n", - "5. Documentation: It would be beneficial to include a brief description of supported operations and functions, along with examples of proper syntax for common calculations.\n", - "\n", - "Overall, adding better documentation and expanding the supported functions would significantly improve the usability of this tool.\n", + "The calculator tool has a clear name, but its description is missing. It doesn't say which operators or functions it supports.\n", + "- The `^` operator fails with a confusing Python type error. `**` works. Documenting this, or treating `^` as exponentiation, would help.\n", + "- `round` is not available. Either support it or state that rounding must be done by hand.\n", + "- The `expression` parameter has no description. It should list the supported syntax, for example \"Python arithmetic expression; use ** for powers\".\n", + "- The output has many unformatted decimal places. An optional precision parameter would help.\n", "\n", "---\n", "\n", @@ -363,70 +580,33 @@ "**Ground Truth Response**: `87.25`\n", "**Actual Response**: `87.25`\n", "**Correct**: ✅\n", - "**Duration**: 31.06s\n", + "**Duration**: 6.49s\n", "**Tool Calls**: {\n", " \"calculator\": {\n", - " \"count\": 12,\n", + " \"count\": 2,\n", " \"durations\": [\n", - " 9.5367431640625e-05,\n", - " 9.465217590332031e-05,\n", - " 7.987022399902344e-05,\n", - " 8.726119995117188e-05,\n", - " 9.036064147949219e-05,\n", - " 8.606910705566406e-05,\n", - " 9.298324584960938e-05,\n", - " 9.226799011230469e-05,\n", - " 7.963180541992188e-05,\n", - " 8.96453857421875e-05,\n", - " 9.012222290039062e-05,\n", - " 7.605552673339844e-05\n", + " 0.00010132789611816406,\n", + " 9.870529174804688e-05\n", " ]\n", " }\n", "}\n", "\n", "**Summary**\n", - "To solve this projectile motion problem, I took the following steps:\n", - "\n", - "1. I first calculated the horizontal distance after 2 seconds:\n", - " - Used the formula x = v₀ × cos(θ) × t\n", - " - Since the calculator didn't accept trigonometric functions directly, I used the value 0.7071 (which is approximately cos(45°))\n", - " - Input: 50 * 2 * 0.7071\n", - " - Output: 70.71 meters\n", + "I took \"distance from the launch point\" to mean the straight-line distance between the launch point and the projectile's position at t = 2 s. This is the magnitude of the displacement, not the length of the curved path.\n", "\n", - "2. I then calculated the vertical distance after 2 seconds:\n", - " - Used the formula y = v₀ × sin(θ) × t - 0.5 × g × t²\n", - " - Since sin(45°) is also approximately 0.7071\n", - " - Input: 50 * 0.7071 * 2 - 0.5 * 9.8 * (2**2)\n", - " - Output: 51.11 meters\n", + "1. I first called the calculator with sqrt and trig functions. It returned the error \"name 'sqrt' is not defined\".\n", + "2. I called it again using `**0.5` for the square root and `2**0.5/2` for cos 45° and sin 45°.\n", + " - Input: `((50*2**0.5/2*2)**2 + (50*2**0.5/2*2 - 0.5*9.8*4)**2)**0.5`\n", + " - Output: 87.24850381381181\n", "\n", - "3. Finally, I calculated the total distance using the Pythagorean theorem:\n", - " - Used the formula d = √(x² + y²)\n", - " - Since the sqrt function wasn't available, I used the power operator with exponent 1/2\n", - " - Input: ((70.71)**2 + (51.11)**2)**(1/2)\n", - " - Output: 87.2475569858549 meters\n", + "The components at t = 2 s are:\n", + "- x = 50·cos45°·2 = 70.71 m\n", + "- y = 50·sin45°·2 − ½·9.8·2² = 70.71 − 19.6 = 51.11 m\n", "\n", - "4. I rounded the result to 2 decimal places, which gives 87.25 meters.\n", + "The distance is √(70.71² + 51.11²) ≈ 87.25 m.\n", "\n", "**Feedback**\n", - "The calculator tool has several limitations that made this problem more complex to solve:\n", - "\n", - "1. Tool name: The name \"calculator\" is clear and descriptive.\n", - "\n", - "2. Input parameters: The \"expression\" parameter is not well-documented. There's no information about what functions or operations are supported.\n", - "\n", - "3. Description: There is no description provided for the tool, which would have been helpful to understand its capabilities and limitations.\n", - "\n", - "4. Errors encountered:\n", - " - The calculator doesn't support common mathematical functions like cos(), sin(), sqrt(), round(), int(), or floor().\n", - " - There's no math library implementation or prefix to use these functions.\n", - " - There's no clear documentation on what functions are supported.\n", - "\n", - "5. Areas for improvement:\n", - " - Add documentation about supported operations and functions\n", - " - Implement common mathematical functions (trigonometric, rounding, square root)\n", - " - Include examples of valid expressions\n", - " - Provide error messages that suggest alternatives when functions aren't available\n", - " - Support a math library like Python's math module would make the calculator much more useful for scientific calculations\n", + "The calculator tool is named clearly. Its description and parameter documentation don't say which functions are supported. My first call failed because `sqrt` is undefined, and the docs gave no hint of that. Please list the supported functions and constants (sqrt, sin, cos, pi) and the syntax, for example that Python-style `**` is expected. The error message could also suggest alternatives, such as \"use **0.5\".\n", "\n", "---\n", "\n", @@ -436,43 +616,24 @@ "**Ground Truth Response**: `304.65`\n", "**Actual Response**: `304.65`\n", "**Correct**: ✅\n", - "**Duration**: 20.41s\n", + "**Duration**: 5.69s\n", "**Tool Calls**: {\n", " \"calculator\": {\n", - " \"count\": 7,\n", + " \"count\": 2,\n", " \"durations\": [\n", - " 8.916854858398438e-05,\n", - " 9.226799011230469e-05,\n", - " 8.7738037109375e-05,\n", - " 8.368492126464844e-05,\n", - " 9.083747863769531e-05,\n", - " 0.0001010894775390625,\n", - " 0.00010538101196289062\n", + " 9.560585021972656e-05,\n", + " 8.678436279296875e-05\n", " ]\n", " }\n", "}\n", "\n", "**Summary**\n", - "N/A\n", - "\n", - "**Feedback**\n", - "The calculator tool is useful but has some limitations:\n", - "\n", - "1. Function naming: The name \"calculator\" is clear and descriptive.\n", - "\n", - "2. Input parameters: The \"expression\" parameter is straightforward, but there's no documentation about which mathematical operations and functions are supported.\n", + "I first called the calculator with the expression 4*pi*(3*500/(4*pi))^(2/3). It returned the error \"name 'pi' is not defined\". I then retried with a numeric value of pi (3.141592653589793) and ** for the exponent. That call returned 304.6473892689777.\n", "\n", - "3. Supported operations: I encountered several errors with common mathematical operations:\n", - " - The caret symbol (^) for exponentiation didn't work; I had to use ** instead\n", - " - Built-in functions like 'round', 'int', and 'math' modules were not available\n", + "The calculation uses V = (4/3)πr³, so r = (3V/(4π))^(1/3). The surface area is A = 4πr² = 4π(3V/(4π))^(2/3). With V = 500, this gives about 304.65 m².\n", "\n", - "4. Improvement suggestions:\n", - " - Provide documentation on which operators are supported (**, /, *, +, -, etc.)\n", - " - Include information about available mathematical functions or implement common ones like round()\n", - " - Add examples in the description showing proper syntax for exponentiation and other operations\n", - " - Consider implementing a parameter for specifying decimal precision in the result\n", - "\n", - "These improvements would reduce trial and error and make the tool more efficient to use.\n", + "**Feedback**\n", + "The calculator tool's name is clear. The description and parameter docs are missing, though. It does not say which syntax is supported (for example, whether ^ or ** is used for powers) or which constants are defined. The `pi` constant was not recognized, which caused an error. Supporting `pi` and `e`, or listing the supported constants and functions in the description, would help. The \"expression\" parameter would also benefit from an example.\n", "\n", "---\n", "\n", @@ -482,69 +643,25 @@ "**Ground Truth Response**: `7.61`\n", "**Actual Response**: `7.61`\n", "**Correct**: ✅\n", - "**Duration**: 28.69s\n", + "**Duration**: 5.33s\n", "**Tool Calls**: {\n", " \"calculator\": {\n", - " \"count\": 10,\n", + " \"count\": 2,\n", " \"durations\": [\n", - " 8.7738037109375e-05,\n", - " 8.344650268554688e-05,\n", - " 9.584426879882812e-05,\n", - " 8.487701416015625e-05,\n", - " 0.00012683868408203125,\n", - " 8.463859558105469e-05,\n", - " 8.20159912109375e-05,\n", - " 7.62939453125e-05,\n", - " 7.939338684082031e-05,\n", - " 8.535385131835938e-05\n", + " 0.00011467933654785156,\n", + " 0.00010204315185546875\n", " ]\n", " }\n", "}\n", "\n", "**Summary**\n", - "To calculate the population standard deviation of the dataset [12, 15, 18, 22, 25, 30, 35] rounded to 2 decimal places, I took the following steps:\n", - "\n", - "1. First, I calculated the mean of the dataset:\n", - " - Input: (12 + 15 + 18 + 22 + 25 + 30 + 35) / 7\n", - " - Output: 22.428571428571427\n", - "\n", - "2. Then I calculated the variance by:\n", - " - Finding the squared deviation of each value from the mean\n", - " - Summing these squared deviations\n", - " - Dividing by the number of values (7) since this is a population standard deviation\n", - " - Input: ((12-22.428571428571427)**2 + (15-22.428571428571427)**2 + (18-22.428571428571427)**2 + (22-22.428571428571427)**2 + (25-22.428571428571427)**2 + (30-22.428571428571427)**2 + (35-22.428571428571427)**2) / 7\n", - " - Output: 57.95918367346939\n", - "\n", - "3. I then calculated the standard deviation by taking the square root of the variance:\n", - " - Input: (57.95918367346939)**0.5\n", - " - Output: 7.61309291112813\n", - "\n", - "4. Finally, I rounded to 2 decimal places: 7.61\n", - " (I had to determine this manually as the calculator tool didn't support rounding functions)\n", + "Steps: I called the calculator to compute the population standard deviation. The mean is 157/7 ≈ 22.43.\n", + "1. First call: the expression used `sqrt(...)` with the mean written as a decimal. It returned the error \"name 'sqrt' is not defined\".\n", + "2. Second call: I replaced sqrt with `**0.5` and used the exact mean 157/7. The expression was (sum of squared deviations / 7)**0.5. It returned 7.61309291112813.\n", + "Rounded to 2 decimal places, that is 7.61.\n", "\n", "**Feedback**\n", - "The calculator tool provided basic functionality but had significant limitations:\n", - "\n", - "1. Tool name: \"calculator\" is clear and descriptive, indicating its purpose well.\n", - "\n", - "2. Input parameters: The \"expression\" parameter is straightforward, but there's no description of what types of expressions are supported or the syntax to use.\n", - "\n", - "3. Description: The tool lacks a description of its capabilities and limitations. This would have been helpful to know in advance that functions like sum(), std(), round(), int(), and math library functions are not supported.\n", - "\n", - "4. Errors encountered: Several errors occurred when trying to use common mathematical functions. The calculator doesn't support:\n", - " - Statistical functions (std, sum)\n", - " - Rounding functions (round)\n", - " - Type conversion functions (int)\n", - " - Math library functions\n", - "\n", - "5. Areas for improvement:\n", - " - Add support for common mathematical and statistical functions like sum(), mean(), std(), round()\n", - " - Include a library of mathematical functions like math.floor(), math.ceil()\n", - " - Provide clear documentation on supported operations and syntax\n", - " - Allow for variable assignment and multi-line operations to simplify complex calculations\n", - " - Add specific statistical calculation tools for common operations like standard deviation\n", - "\n", - "These improvements would make the tool much more versatile and prevent the need for breaking down complex calculations into multiple basic arithmetic operations.\n", + "The tool is named clearly, but its description doesn't say which functions and syntax it supports. The `sqrt` call failed with an unhelpful error. Listing the supported functions (e.g. sqrt, pow) or the allowed syntax (`**`) would avoid that retry. Adding built-in statistical functions such as mean and stdev would also help. The `expression` parameter has no description or example.\n", "\n", "---\n", "\n", @@ -554,67 +671,36 @@ "**Ground Truth Response**: `4.46`\n", "**Actual Response**: `4.46`\n", "**Correct**: ✅\n", - "**Duration**: 38.37s\n", + "**Duration**: 14.60s\n", "**Tool Calls**: {\n", " \"calculator\": {\n", - " \"count\": 16,\n", + " \"count\": 8,\n", " \"durations\": [\n", - " 8.726119995117188e-05,\n", - " 8.940696716308594e-05,\n", - " 9.322166442871094e-05,\n", - " 8.702278137207031e-05,\n", - " 0.00015282630920410156,\n", - " 0.00010943412780761719,\n", - " 0.00011801719665527344,\n", - " 8.463859558105469e-05,\n", - " 8.225440979003906e-05,\n", - " 9.059906005859375e-05,\n", - " 8.392333984375e-05,\n", - " 8.988380432128906e-05,\n", - " 0.00010824203491210938,\n", - " 9.393692016601562e-05,\n", - " 0.00010967254638671875,\n", - " 0.000156402587890625\n", + " 6.961822509765625e-05,\n", + " 7.319450378417969e-05,\n", + " 2.4557113647460938e-05,\n", + " 8.20159912109375e-05,\n", + " 2.5272369384765625e-05,\n", + " 2.3126602172851562e-05,\n", + " 0.00012564659118652344,\n", + " 0.00013303756713867188\n", " ]\n", " }\n", "}\n", "\n", "**Summary**\n", - "I attempted to calculate the pH of a solution with a hydrogen ion concentration of 3.5 × 10^-5 M.\n", - "\n", - "Steps taken:\n", - "1. I tried various approaches to calculate pH using the calculator tool with different logarithm function notations (log10, ln, log), but encountered errors as these functions were not defined in the calculator tool.\n", - "2. I successfully verified the value of 3.5 × 10^-5 using the calculator tool.\n", - "3. Since direct logarithm calculations were not working, I switched to a manual calculation approach.\n", - "4. I used the pH formula: pH = -log10([H+])\n", - "5. I broke down the calculation: pH = -log10(3.5 × 10^-5) = -(log10(3.5) + log10(10^-5)) = -(log10(3.5) - 5)\n", - "6. I used the known approximation that log10(3.5) ≈ 0.544\n", - "7. I calculated: pH ≈ -(0.544 - 5) = 4.456\n", - "8. I rounded the result to 2 decimal places: 4.46\n", - "\n", - "The calculator tool was used multiple times with different expressions, but had limitations with logarithmic functions.\n", + "I needed pH = -log10[H⁺] with [H⁺] = 3.5 × 10⁻⁵ M.\n", + "1. I called the calculator with `-log10(3.5e-5)`. It returned an error because `log10` isn't defined.\n", + "2. I tried `math.log10`, `log(x, 10)`, `np.log10`, `ln`, and `__import__('math')`. Each one failed with a \"name not defined\" error.\n", + "3. I then rewrote the problem as pH = 5 − log10(3.5). I computed ln(3.5) with the atanh series 2·Σ x^(2k+1)/(2k+1), where x = 2.5/4.5 = 5/9. I divided by ln(10) = 2.302585093.\n", + "4. A first attempt using `sum` and `range` failed because `sum` isn't defined. Writing out the series terms explicitly worked and returned 4.45593.\n", + "5. Rounded to 2 decimal places, that is 4.46.\n", "\n", "**Feedback**\n", - "The calculator tool has several limitations:\n", - "\n", - "1. Tool name: \"calculator\" is clear and descriptive, accurately representing its basic function.\n", - "\n", - "2. Input parameters: The \"expression\" parameter is clear but lacks documentation. There's no information about what mathematical operations or functions are supported.\n", - "\n", - "3. Function support: The calculator doesn't support essential mathematical functions like logarithms (log, log10, ln), which are critical for many scientific calculations including pH. This significantly limits its utility for chemistry-related calculations.\n", - "\n", - "4. Error messages: The error messages indicate missing functions but don't provide alternatives or guidance on what syntax is supported.\n", - "\n", - "5. Documentation: There's no documentation about what mathematical libraries or syntax the calculator uses.\n", - "\n", - "Improvement suggestions:\n", - "- Include support for common mathematical functions (log, exp, sqrt, etc.)\n", - "- Add clear documentation about supported operations and functions\n", - "- Implement specialized functions for common calculations (like pH)\n", - "- Provide more helpful error messages that suggest correct syntax\n", - "- Include examples of supported expressions in the tool description\n", - "\n", - "These improvements would make the calculator much more useful for scientific calculations and reduce the need for manual calculations or workarounds.\n", + "The calculator tool has no documentation of which functions it supports. Every standard logarithm form I tried failed (`log10`, `math.log10`, `np.log10`, `log`, `ln`), and so did `sum` and `__import__`. The name \"calculator\" suggests it would handle basic scientific functions.\n", + "- Improvement: list the supported functions and syntax in the description, or add the common ones (log, log10, ln, exp, sqrt, and so on). Chemistry and science tasks need logarithms often.\n", + "- Improvement: make the error messages more helpful. For example, \"name 'log10' is not defined. Available functions: ...\" would save a lot of trial and error.\n", + "- The `expression` parameter is a bare string with no description. A note on the expected syntax would help.\n", "\n", "---\n", "\n", @@ -624,47 +710,24 @@ "**Ground Truth Response**: `1013.37`\n", "**Actual Response**: `1013.37`\n", "**Correct**: ✅\n", - "**Duration**: 19.65s\n", + "**Duration**: 4.65s\n", "**Tool Calls**: {\n", " \"calculator\": {\n", - " \"count\": 6,\n", + " \"count\": 2,\n", " \"durations\": [\n", - " 0.00011038780212402344,\n", - " 0.0001671314239501953,\n", - " 8.273124694824219e-05,\n", - " 0.00010371208190917969,\n", - " 8.702278137207031e-05,\n", - " 8.726119995117188e-05\n", + " 9.012222290039062e-05,\n", + " 8.034706115722656e-05\n", " ]\n", " }\n", "}\n", "\n", "**Summary**\n", - "Steps taken to complete the task:\n", - "1. I needed to calculate the monthly mortgage payment using the standard formula: P * (r * (1+r)^n) / ((1+r)^n - 1)\n", - " Where P = principal ($200,000), r = monthly interest rate (4.5%/12), n = number of payments (360)\n", - "\n", - "2. First, I attempted to use the calculator tool with the formula using ^ for exponentiation, but received an error as Python uses ** for exponentiation.\n", - "\n", - "3. I corrected the formula using ** for exponentiation and successfully calculated the monthly payment as $1,013.3706196517716.\n", - "\n", - "4. I attempted to round to 2 decimal places using various methods (round(), int(), math.floor()), but these functions were not available in the calculator tool.\n", - "\n", - "5. Since the built-in rounding functions weren't available, I manually rounded the result to $1,013.37 based on the calculated value.\n", + "1. I called the calculator with the standard mortgage formula, M = P·r·(1+r)^n / ((1+r)^n − 1). The inputs were P = 200000, r = 0.045/12 and n = 360. I wrapped the expression in `round(..., 2)`. The tool returned the error \"name 'round' is not defined\".\n", + "2. I ran the same expression again without `round`. It returned 1013.3706196517716.\n", + "3. I rounded that result to 2 decimal places by hand, which gives 1013.37.\n", "\n", "**Feedback**\n", - "Calculator Tool Feedback:\n", - "- Tool name: The name \"calculator\" is clear and descriptive, indicating its purpose well.\n", - "- Input parameters: The \"expression\" parameter is clear but lacks description about syntax requirements or limitations.\n", - "- Descriptions: The tool description is completely absent, which makes it difficult to understand what types of expressions are supported.\n", - "- Errors encountered: The tool doesn't support common Python functions like round(), int(), or math module functions, which limits its utility for common mathematical operations.\n", - "\n", - "Areas for improvement:\n", - "1. Add a clear description for the calculator tool explaining what syntax it supports and what libraries/functions are available.\n", - "2. Include examples of supported operations in the documentation.\n", - "3. Support common mathematical functions like round() and basic modules like math for more complex calculations.\n", - "4. Provide better error messages that explain why an operation failed and suggest alternatives.\n", - "5. Add documentation about what syntax to use for exponentiation and other special operations to avoid trial and error.\n", + "The tool name \"calculator\" is clear. The parameter description for `expression` is empty. It doesn't say which functions or syntax are supported, such as `round`, `**` or `^`. I only found out that `round` isn't supported by trying it and getting an error. Please document the supported operators and functions in the description. Adding common functions like `round`, `abs` and `sqrt` would also help, since rounding is a frequent need.\n", "\n", "---\n", "\n", @@ -674,40 +737,21 @@ "**Ground Truth Response**: `3.61e-19`\n", "**Actual Response**: `3.61e-19`\n", "**Correct**: ✅\n", - "**Duration**: 8.61s\n", + "**Duration**: 2.77s\n", "**Tool Calls**: {\n", " \"calculator\": {\n", " \"count\": 1,\n", " \"durations\": [\n", - " 8.845329284667969e-05\n", + " 7.081031799316406e-05\n", " ]\n", " }\n", "}\n", "\n", "**Summary**\n", - "To calculate the energy of a photon with wavelength 550 nanometers:\n", - "\n", - "1. I identified the formula needed: E = hc/λ, where:\n", - " - E is the energy in joules\n", - " - h is Planck's constant (6.626 × 10^-34 J·s)\n", - " - c is the speed of light (3 × 10^8 m/s)\n", - " - λ is the wavelength (550 nm = 550 × 10^-9 m)\n", - "\n", - "2. I used the calculator tool with the expression: 6.626e-34 * 3e8 / (550e-9)\n", - " - Input: The mathematical expression with scientific notation\n", - " - Output: 3.614181818181818e-19 joules\n", - "\n", - "3. The result needs to be formatted with 2 significant figures after the decimal, so 3.61e-19 J.\n", + "I used the calculator tool once. The input was the expression 6.626e-34 * 3e8 / 550e-9, which is E = hc/λ with λ = 550 nm = 550e-9 m. The output was 3.614181818181818e-19 J. Rounding to 2 digits after the decimal point gives 3.61e-19.\n", "\n", "**Feedback**\n", - "The calculator tool works well for this calculation:\n", - "\n", - "- Tool name: \"calculator\" is clear and describes its function well.\n", - "- Input parameters: The single \"expression\" parameter is intuitive, though a brief description of acceptable syntax would be helpful.\n", - "- Description: There's no actual description provided for the tool in the schema, which would be useful to explain capabilities and limitations.\n", - "- Functionality: The tool handled scientific notation correctly and performed the calculation as expected.\n", - "\n", - "Improvement suggestion: Adding a brief description of the calculator's capabilities and acceptable syntax formats would help users understand how to properly format complex expressions, especially when dealing with scientific notation.\n", + "The calculator tool worked without errors. Its name is clear. The description of the `expression` parameter is empty, so it doesn't say which syntax is supported (for example, whether scientific notation like 1e-9 is accepted). A short description with example expressions would help. The output was accurate, with full precision.\n", "\n", "---\n", "\n", @@ -717,48 +761,25 @@ "**Ground Truth Response**: `2`\n", "**Actual Response**: `2`\n", "**Correct**: ✅\n", - "**Duration**: 16.37s\n", + "**Duration**: 5.18s\n", "**Tool Calls**: {\n", " \"calculator\": {\n", - " \"count\": 4,\n", + " \"count\": 2,\n", " \"durations\": [\n", - " 0.0001506805419921875,\n", - " 9.179115295410156e-05,\n", - " 0.000102996826171875,\n", - " 9.870529174804688e-05\n", + " 7.557868957519531e-05,\n", + " 7.843971252441406e-05\n", " ]\n", " }\n", "}\n", "\n", "**Summary**\n", - "I solved the quadratic equation 3x² - 7x + 2 = 0 using the quadratic formula:\n", - "x = (-b ± √(b² - 4ac))/(2a)\n", - "\n", - "Where a = 3, b = -7, c = 2\n", - "\n", - "Steps taken:\n", - "1. First, I attempted to use the calculator with the \"sqrt\" function, but encountered an error.\n", - "2. Then I tried using the exponentiation with \"^\" which also caused an error.\n", - "3. Finally, I correctly used the \"**\" operator for exponentiation in the calculator tool.\n", - "4. I calculated both roots using the quadratic formula:\n", - " - For the larger root: (-(-7) + ((-7)**2 - 4*3*2)**0.5)/(2*3) = 2.0\n", - " - For the smaller root: (-(-7) - ((-7)**2 - 4*3*2)**0.5)/(2*3) = 0.3333333333333333\n", - "\n", - "The larger real root is 2.\n", + "I wanted to compute the larger root with the quadratic formula, x = (7 + √(49 − 24)) / 6. The discriminant is 49 − 4·3·2 = 25.\n", + "1. I called the calculator with \"(7 + sqrt(49 - 24)) / 6\". It returned the error \"name 'sqrt' is not defined\".\n", + "2. I called it again with \"(7 + (49 - 24)**0.5) / 6\". It returned 2.0.\n", + "The discriminant is a perfect square, so the roots are (7 ± 5)/6, which gives 2 and 1/3. The larger root is exactly 2. Factoring confirms this: 3x² − 7x + 2 = (3x − 1)(x − 2).\n", "\n", "**Feedback**\n", - "The calculator tool is useful but has some limitations and areas for improvement:\n", - "\n", - "1. Tool name: \"calculator\" is clear and descriptive.\n", - "2. Input parameters: The single \"expression\" parameter is straightforward, though it would be helpful to have documentation on the supported syntax.\n", - "3. Description: The tool lacks a description of what operations are supported and what syntax to use. This caused my initial errors with sqrt() and the ^ operator.\n", - "4. Syntax limitations: The calculator doesn't support common mathematical functions like \"sqrt\" directly, requiring the use of exponentiation (raising to power 0.5) instead. It also uses Python-style \"**\" for exponentiation rather than the more common \"^\" symbol.\n", - "5. Error messages: The error messages were helpful in identifying the issues with my syntax.\n", - "\n", - "Improvement suggestions:\n", - "- Add documentation explaining the supported operations and syntax\n", - "- Support common mathematical functions like sqrt(), sin(), cos(), etc.\n", - "- Consider accepting multiple syntax styles for common operations like exponentiation\n", + "The calculator tool's name is clear. The `expression` parameter has no description, so I couldn't tell which functions or syntax are supported. My first call failed because `sqrt` isn't defined, and I only found that out by trying it. The tool description should list the supported functions (for example sqrt, pow) and the expected syntax. Documenting the evaluator, such as Python-style with `**`, would also help. Supporting `sqrt` would be a useful addition.\n", "\n", "---\n", "\n" @@ -791,9 +812,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.13" + "version": "3.12.14" } }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} diff --git a/content/github/claude-cookbooks/tool_use/automatic-context-compaction.ipynb b/content/github/claude-cookbooks/tool_use/automatic-context-compaction.ipynb index 924e65570c..520fd4fdd6 100644 --- a/content/github/claude-cookbooks/tool_use/automatic-context-compaction.ipynb +++ b/content/github/claude-cookbooks/tool_use/automatic-context-compaction.ipynb @@ -9,19 +9,18 @@ "\n", "Long-running agentic tasks can often exceed context limits. Tool heavy workflows or long conversations quickly consume the token context window. In [Effective Context Engineering for AI Agents](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents), we discussed how managing context can help avoid performance degradation and context rot.\n", "\n", - "The Claude Agent Python SDK can help manage this context by automatically compressing conversation history when token usage exceeds a configurable threshold, allowing tasks to continue beyond the model's context window limit.\n", + "The Anthropic Python SDK's tool runner can help manage this context: when your loop decides the conversation has grown too large, one call to `runner.compact_before_next_turn()` has the API summarize the history server-side and the runner carries on from that summary, allowing tasks to continue beyond the model's context window limit.\n", "\n", "In this cookbook, we'll demonstrate context compaction through an **agentic customer service workflow**. Imagine you've built an AI customer service agent tasked with processing a queue of support tickets. For each ticket, you must classify the issue, search the knowledge base, set priority, route to the appropriate team, draft a response, and mark it complete. As you process ticket after ticket, the conversation history fills with classifications, knowledge base searches, and drafted responses—quickly consuming thousands of tokens.\n", "\n", "## What is Context Compaction?\n", "\n", - "When building agentic workflows with tool use, conversations can grow very large as the agent iterates on complex tasks. The `compaction_control` parameter provides automatic context management by:\n", + "When building agentic workflows with tool use, conversations can grow very large as the agent iterates on complex tasks. Runner-driven compaction manages this in four steps:\n", "\n", - "1. Monitoring token usage per turn in the conversation\n", - "2. When a threshold is exceeded, injecting a summary prompt as a user turn\n", - "3. Having the model generate a summary wrapped in `` tags. These tags aren't parsed, but are there to help guide the model.\n", - "4. Clearing the conversation history and resuming with only the summary\n", - "5. Continuing the task with the compressed context\n", + "1. Your loop monitors token usage per turn in the conversation\n", + "2. When your threshold is exceeded, you call `runner.compact_before_next_turn()`\n", + "3. Once the current turn (including its tool calls) finishes, the runner sends a compaction request. The API summarizes the conversation server-side and returns a single `compaction` block (`stop_reason == \"compaction\"`)\n", + "4. The runner replaces the conversation history with that block and continues the task with the compressed context\n", "\n", "## By the end of this cookbook, you'll be able to:\n", " \n", @@ -41,14 +40,18 @@ "\n", "- Python 3.11 or higher\n", "- Anthropic API key\n", - "- Anthropic SDK >= 0.74.1" + "- Anthropic SDK >= 2.0.0 (uses the `compact-2026-09-04` beta)" ] }, { "cell_type": "markdown", "id": "6j8bv0fnlqm", - "source": "> **Using Claude Opus 5.5 or Claude Sonnet 5.5?** We recommend using [server-side compaction](https://platform.claude.com/docs/en/build-with-claude/compaction), which handles context management automatically without any SDK-level configuration.\n>\n> This cookbook covers **SDK-based compaction**, which is useful if you're using a model without server-side compaction or want to use a different (cheaper) model for summarization.", - "metadata": {} + "metadata": {}, + "source": [ + "> **Just want compaction to happen automatically?** [Server-side compaction](https://platform.claude.com/docs/en/build-with-claude/compaction) via `context_management` compacts on its own once input tokens cross a trigger you set (50k tokens or more), with no loop logic at all.\n", + ">\n", + "> This cookbook covers **runner-driven compaction**, where your code decides *when* to compact: useful for low thresholds, natural item boundaries (compact after every N tickets), or custom summarization instructions." + ] }, { "cell_type": "markdown", @@ -196,51 +199,127 @@ "name": "stdout", "output_type": "stream", "text": [ - "Turn 1: Input= 1,537 tokens | Output= 57 tokens | Messages= 1 | Cumulative In= 1,537\n", - "Turn 2: Input= 1,760 tokens | Output= 102 tokens | Messages= 3 | Cumulative In= 3,297\n", - "Turn 3: Input= 1,905 tokens | Output= 88 tokens | Messages= 5 | Cumulative In= 5,202\n", - "Turn 4: Input= 2,237 tokens | Output= 84 tokens | Messages= 7 | Cumulative In= 7,439\n", - "Turn 5: Input= 2,385 tokens | Output= 89 tokens | Messages= 9 | Cumulative In= 9,824\n", - "Turn 6: Input= 2,537 tokens | Output= 301 tokens | Messages=11 | Cumulative In= 12,361\n", - "Turn 7: Input= 2,888 tokens | Output= 67 tokens | Messages=13 | Cumulative In= 15,249\n", - "Turn 8: Input= 3,079 tokens | Output= 56 tokens | Messages=15 | Cumulative In= 18,328\n", - "Turn 9: Input= 3,316 tokens | Output= 91 tokens | Messages=17 | Cumulative In= 21,644\n", - "Turn 10: Input= 3,450 tokens | Output= 84 tokens | Messages=19 | Cumulative In= 25,094\n", - "Turn 11: Input= 3,777 tokens | Output= 84 tokens | Messages=21 | Cumulative In= 28,871\n", - "Turn 12: Input= 3,925 tokens | Output= 89 tokens | Messages=23 | Cumulative In= 32,796\n", - "Turn 13: Input= 4,077 tokens | Output= 349 tokens | Messages=25 | Cumulative In= 36,873\n", - "Turn 14: Input= 4,476 tokens | Output= 67 tokens | Messages=27 | Cumulative In= 41,349\n", - "Turn 15: Input= 4,668 tokens | Output= 56 tokens | Messages=29 | Cumulative In= 46,017\n", - "Turn 16: Input= 4,894 tokens | Output= 91 tokens | Messages=31 | Cumulative In= 50,911\n", - "Turn 17: Input= 5,028 tokens | Output= 84 tokens | Messages=33 | Cumulative In= 55,939\n", - "Turn 18: Input= 5,333 tokens | Output= 84 tokens | Messages=35 | Cumulative In= 61,272\n", - "Turn 19: Input= 5,481 tokens | Output= 89 tokens | Messages=37 | Cumulative In= 66,753\n", - "Turn 20: Input= 5,633 tokens | Output= 334 tokens | Messages=39 | Cumulative In= 72,386\n", - "Turn 21: Input= 6,017 tokens | Output= 67 tokens | Messages=41 | Cumulative In= 78,403\n", - "Turn 22: Input= 6,209 tokens | Output= 56 tokens | Messages=43 | Cumulative In= 84,612\n", - "Turn 23: Input= 6,435 tokens | Output= 91 tokens | Messages=45 | Cumulative In= 91,047\n", - "Turn 24: Input= 6,569 tokens | Output= 84 tokens | Messages=47 | Cumulative In= 97,616\n", - "Turn 25: Input= 6,896 tokens | Output= 84 tokens | Messages=49 | Cumulative In= 104,512\n", - "Turn 26: Input= 7,044 tokens | Output= 89 tokens | Messages=51 | Cumulative In= 111,556\n", - "Turn 27: Input= 7,196 tokens | Output= 372 tokens | Messages=53 | Cumulative In= 118,752\n", - "Turn 28: Input= 7,618 tokens | Output= 67 tokens | Messages=55 | Cumulative In= 126,370\n", - "Turn 29: Input= 7,808 tokens | Output= 56 tokens | Messages=57 | Cumulative In= 134,178\n", - "Turn 30: Input= 8,040 tokens | Output= 96 tokens | Messages=59 | Cumulative In= 142,218\n", - "Turn 31: Input= 8,179 tokens | Output= 85 tokens | Messages=61 | Cumulative In= 150,397\n", - "Turn 32: Input= 8,508 tokens | Output= 84 tokens | Messages=63 | Cumulative In= 158,905\n", - "Turn 33: Input= 8,656 tokens | Output= 89 tokens | Messages=65 | Cumulative In= 167,561\n", - "Turn 34: Input= 8,808 tokens | Output= 332 tokens | Messages=67 | Cumulative In= 176,369\n", - "Turn 35: Input= 9,190 tokens | Output= 67 tokens | Messages=69 | Cumulative In= 185,559\n", - "Turn 36: Input= 9,382 tokens | Output= 60 tokens | Messages=71 | Cumulative In= 194,941\n", - "Turn 37: Input= 9,475 tokens | Output= 297 tokens | Messages=73 | Cumulative In= 204,416\n", + "Turn 1: Input= 1,732 tokens | Output= 30 tokens | Messages= 1 | Cumulative In= 1,732\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 2: Input= 1,964 tokens | Output= 318 tokens | Messages= 3 | Cumulative In= 3,696\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 3: Input= 2,881 tokens | Output= 378 tokens | Messages= 5 | Cumulative In= 6,577\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 4: Input= 3,516 tokens | Output= 30 tokens | Messages= 7 | Cumulative In= 10,093\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 5: Input= 3,744 tokens | Output= 313 tokens | Messages= 9 | Cumulative In= 13,837\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 6: Input= 4,875 tokens | Output= 409 tokens | Messages=11 | Cumulative In= 18,712\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 7: Input= 5,538 tokens | Output= 30 tokens | Messages=13 | Cumulative In= 24,250\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 8: Input= 5,758 tokens | Output= 309 tokens | Messages=15 | Cumulative In= 30,008\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 9: Input= 6,619 tokens | Output= 443 tokens | Messages=17 | Cumulative In= 36,627\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 10: Input= 7,316 tokens | Output= 30 tokens | Messages=19 | Cumulative In= 43,943\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 11: Input= 7,533 tokens | Output= 314 tokens | Messages=21 | Cumulative In= 51,476\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 12: Input= 8,404 tokens | Output= 365 tokens | Messages=23 | Cumulative In= 59,880\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 13: Input= 9,019 tokens | Output= 30 tokens | Messages=25 | Cumulative In= 68,899\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 14: Input= 9,238 tokens | Output= 342 tokens | Messages=27 | Cumulative In= 78,137\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 15: Input= 9,910 tokens | Output= 413 tokens | Messages=29 | Cumulative In= 88,047\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 16: Input= 10,580 tokens | Output= 30 tokens | Messages=31 | Cumulative In= 98,627\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 17: Input= 10,642 tokens | Output= 454 tokens | Messages=33 | Cumulative In= 109,269\n", "\n", "============================================================\n", "BASELINE RESULTS (NO COMPACTION)\n", "============================================================\n", - "Total turns: 37\n", - "Input tokens: 204,416\n", - "Output tokens: 4,422\n", - "Total tokens: 208,838\n", + "Total turns: 17\n", + "Input tokens: 109,269\n", + "Output tokens: 4,238\n", + "Total tokens: 113,507\n", "============================================================\n" ] } @@ -318,7 +397,7 @@ "source": [ "Now that we have our baseline, we have a better picture of how context grows without compaction. As you can see, each turn results in linear token growth, as every turn adds more tokens to the input. \n", "\n", - "This leads to high token consumption and potential context limits being reached quickly. By the 27th turn, we have a cumulative 150,000 input tokens just for 5 tickets.\n", + "This leads to high token consumption and potential context limits being reached quickly: the cumulative input climbs past a hundred thousand tokens for just 5 tickets.\n", "\n", "Let's review Claude's final response after processing all 5 tickets without compaction:" ] @@ -333,38 +412,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "---\n", - "\n", - "## ✅ ALL TICKETS PROCESSED SUCCESSFULLY!\n", + "I processed all 5 tickets, and the queue is now empty. Each one was classified, prioritized, routed, given a draft response and marked complete.\n", "\n", - "**Summary of Completed Work:**\n", + "| Ticket | Category | Priority | Team | Notes |\n", + "|---|---|---|---|---|\n", + "| TICKET-1 (Morgan Jones) | billing | medium | billing-team | The charge date (10-09) doesn't match the signup date (10-04), so I flagged it for billing to review. |\n", + "| TICKET-2 (Jane Smith) | technical | medium | tech-support | The subject line says upload error, but the description is about device sync. I drafted a response for the sync problem. |\n", + "| TICKET-3 (Alex Johnson) | account | high | account-services | The email in the message differs from the ticket's contact email, so the draft asks the customer to confirm their registered address. |\n", + "| TICKET-4 (Morgan Davis) | account | high | account-services | The customer lost their phone and their backup codes aren't being accepted, so they're locked out. The draft asks for identity verification. |\n", + "| TICKET-5 (Sam Williams) | shipping | medium | logistics-team | The knowledge base has no shipping category. The draft asks for photos and promises no replacement timeline or policy. |\n", "\n", - "I have successfully processed all 5 tickets from the queue. Here's what was accomplished:\n", - "\n", - "1. **TICKET-1** - Sam Smith - Payment method update error\n", - " - Category: Billing | Priority: High | Team: billing-team\n", - " \n", - "2. **TICKET-2** - Morgan Johnson - Missing delivery\n", - " - Category: Shipping | Priority: High | Team: logistics-team\n", - " \n", - "3. **TICKET-3** - Morgan Jones - Email address change request\n", - " - Category: Account | Priority: Medium | Team: account-services\n", - " \n", - "4. **TICKET-4** - Alex Johnson - Wrong item delivered\n", - " - Category: Shipping | Priority: High | Team: logistics-team\n", - " \n", - "5. **TICKET-5** - Morgan Jones - Refund request for cancelled subscription\n", - " - Category: Billing | Priority: High | Team: billing-team\n", - "\n", - "Each ticket was:\n", - "✅ Classified correctly\n", - "✅ Researched in the knowledge base\n", - "✅ Assigned appropriate priority\n", - "✅ Routed to the correct team\n", - "✅ Given a detailed, helpful customer response\n", - "✅ Marked as complete\n", - "\n", - "The queue is now empty and all tickets have been processed!\n" + "On three tickets the subject line and the description didn't match (TICKET-1, 2 and 4). I went by the description each time. You may want to check those three.\n" ] } ], @@ -405,16 +463,14 @@ "source": [ "## Enabling Automatic Context Compaction\n", "\n", - "Let's run the exact same customer service workflow, but with automatic context compaction enabled. We simply add the `compaction_control` parameter to our tool runner.\n", + "Let's run the exact same customer service workflow, but with context compaction enabled. Two changes to the tool runner loop:\n", "\n", - "The `compaction_control` parameter has one required field and several optional ones:\n", + "- Pass **`betas=[\"compact-2026-09-04\"]`** so the runner may send compaction requests\n", + "- After each turn, compare `message.usage.input_tokens` with a threshold and call **`runner.compact_before_next_turn()`** when it is exceeded. The call only *schedules* the compaction: the runner finishes the current turn's tool calls first, then requests the summary. It accepts an optional config, `{\"type\": \"summarize\", \"instructions\": \"...\"}`, to replace the server's default summarization prompt (see *Custom Summary Instructions* below)\n", "\n", - "- **`enabled`** (required): Boolean to turn compaction on/off\n", - "- **`context_token_threshold`** (optional): Token count that triggers compaction (default: 100,000)\n", - "- **`model`** (optional): Model to use for summarization (defaults to the main model)\n", - "- **`summary_prompt`** (optional): Custom prompt for generating summaries\n", + "The compaction turn is yielded by the runner like any other message, with `stop_reason == \"compaction\"` and a single `compaction` content block holding the summary. Its token usage is reported under `usage.iterations` rather than the top-level counters, which the helper below accounts for.\n", "\n", - "For this customer service workflow, we'll use a **5,000 token threshold**. This means after processing several tickets compaction will auto-trigger. This allows Claude to:\n", + "For this customer service workflow, we'll use a **5,000 token threshold**. This means after processing several tickets compaction will trigger. This allows Claude to:\n", "1. **Keep completion summaries** (tickets resolved, categories, outcomes)\n", "2. **Discard detailed tool results** (full KB articles, complete classifications, drafted response text)\n", "3. **Start fresh** when processing the next batch of tickets\n", @@ -432,173 +488,189 @@ "name": "stdout", "output_type": "stream", "text": [ - "Turn 1: Input= 1,537 tokens | Output= 57 tokens | Messages= 1 | Cumulative In= 1,537\n", - "Turn 2: Input= 1,755 tokens | Output= 108 tokens | Messages= 3 | Cumulative In= 3,292\n", - "Turn 3: Input= 1,906 tokens | Output= 88 tokens | Messages= 5 | Cumulative In= 5,198\n", - "Turn 4: Input= 2,216 tokens | Output= 84 tokens | Messages= 7 | Cumulative In= 7,414\n", - "Turn 5: Input= 2,364 tokens | Output= 89 tokens | Messages= 9 | Cumulative In= 9,778\n", - "Turn 6: Input= 2,516 tokens | Output= 332 tokens | Messages=11 | Cumulative In= 12,294\n", - "Turn 7: Input= 2,898 tokens | Output= 67 tokens | Messages=13 | Cumulative In= 15,192\n", - "Turn 8: Input= 3,090 tokens | Output= 56 tokens | Messages=15 | Cumulative In= 18,282\n", - "Turn 9: Input= 3,325 tokens | Output= 97 tokens | Messages=17 | Cumulative In= 21,607\n", - "Turn 10: Input= 3,465 tokens | Output= 90 tokens | Messages=19 | Cumulative In= 25,072\n", - "Turn 11: Input= 3,801 tokens | Output= 84 tokens | Messages=21 | Cumulative In= 28,873\n", - "Turn 12: Input= 3,949 tokens | Output= 89 tokens | Messages=23 | Cumulative In= 32,822\n", - "Turn 13: Input= 4,101 tokens | Output= 368 tokens | Messages=25 | Cumulative In= 36,923\n", - "Turn 14: Input= 4,519 tokens | Output= 67 tokens | Messages=27 | Cumulative In= 41,442\n", - "Turn 15: Input= 4,711 tokens | Output= 57 tokens | Messages=29 | Cumulative In= 46,153\n", - "Turn 16: Input= 4,934 tokens | Output= 97 tokens | Messages=31 | Cumulative In= 51,087\n", + "Turn 1: Input= 1,732 tokens | Output= 30 tokens | Messages= 1 | Cumulative In= 1,732\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 2: Input= 1,955 tokens | Output= 317 tokens | Messages= 3 | Cumulative In= 3,687\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 3: Input= 2,602 tokens | Output= 101 tokens | Messages= 5 | Cumulative In= 6,289\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 4: Input= 3,233 tokens | Output= 317 tokens | Messages= 7 | Cumulative In= 9,522\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 5: Input= 3,803 tokens | Output= 30 tokens | Messages= 9 | Cumulative In= 13,325\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 6: Input= 4,033 tokens | Output= 392 tokens | Messages=11 | Cumulative In= 17,358\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 7: Input= 5,026 tokens | Output= 321 tokens | Messages=13 | Cumulative In= 22,384\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "\n", "============================================================\n", - "🔄 Compaction occurred! Messages: 31 → 1\n", - " Summary message after compaction:\n", - "\n", - "## Support Ticket Processing Progress Summary\n", - "\n", - "### Task Overview\n", - "Processing 5 support tickets sequentially, completing all 7 steps for each ticket (fetch, classify, research, prioritize, route, draft, complete).\n", - "\n", - "### Tickets Completed (2 of 5)\n", - "\n", - "**TICKET-1 (Chris Davis) - COMPLETED**\n", - "- Issue: Account locked, unlock email link not working\n", - "- Category: account\n", - "- Priority: high\n", - "- Team: account-services\n", - "- Status: resolved\n", - "- Response: Provided guidance on checking spam folder, link expiration (1 hour), and requesting new unlock link\n", + "🔄 Compaction occurred! 15 messages condensed into one summary block\n", + " Summary after compaction:\n", + "## Progress summary\n", "\n", - "**TICKET-2 (Chris Williams) - COMPLETED**\n", - "- Issue: Unrecognized $49.99 charge on 2025-10-30\n", - "- Category: billing\n", - "- Priority: high\n", - "- Team: billing-team\n", - "- Status: resolved\n", - "- Response: Explained billing cycles, subscription possibility, and refund policy (5-7 business days, pro-rated for annual plans)\n", + "**Task**: Process 5 support tickets one at a time. For each ticket: get_next_ticket → classify_ticket → search_knowledge_base → set_priority → route_to_team → draft_response → mark_complete. Keep going until the queue is empty (the 5 tickets are expected in total).\n", "\n", - "### Current Status\n", - "**TICKET-3 (John Jones) - IN PROGRESS**\n", - "- Issue: Asking about Google Sheets integration for project management\n", - "- Category: product\n", - "- Priority: NOT YET SET\n", - "- Team: NOT YET ASSIGNED\n", - "- Steps completed: 1 (fetch), 2 (classify)\n", - "- Steps remaining: 3 (research KB), 4 (set priority), 5 (route), 6 (draft), 7 (mark complete)\n", + "**Completed so far (2 of 5):**\n", + "- **TICKET-1** (John Williams, tracking number 1Z856942470332 reported invalid): classified shipping, priority medium, routed to logistics-team. The draft response made no unsupported claims and said the logistics team would verify the number. Marked complete.\n", + "- **TICKET-2** (Alex Jones, order #ORD-66101: received Yellow Widget Lite instead of Green Device Max; the subject line said \"change delivery address\", which doesn't match the description): classified shipping, priority medium, routed to logistics-team. The draft apologized, said logistics would arrange the correct item and return instructions, and offered to pass on a new address if needed. Marked complete.\n", "\n", - "### Next Steps\n", - "1. Complete TICKET-3: Search knowledge base for product integration info\n", - "2. Set priority (likely low/medium for feature inquiry)\n", - "3. Route to product-team\n", - "4. Draft response about integrations\n", - "5. Mark complete\n", - "6. Fetch and process TICKET-4\n", - "7. Fetch and process TICKET-5\n", + "**Notes on the tools:**\n", + "- The KB only has the categories billing, technical, and account. \"shipping\" returns an error. For shipping tickets, I searched the nearest available category (billing for return/refund topics, technical for tracking). Neither had shipping-specific content, so the drafts avoided inventing policy details.\n", + "- KB content seen: the billing refund policy (refunds take 5-7 business days for valid cancellations, pro-rated for annual plans), payment methods (Visa, Mastercard, Amex, PayPal; update them in Account Settings), and the billing cycle. Technical covers common errors, system requirements (4GB RAM, Chrome 90+/Firefox 88+/Safari 14+), and troubleshooting (clear cache, incognito, enable JavaScript).\n", + "- Valid teams: billing-team, tech-support, account-services, product-success, logistics-team.\n", + "- Independent calls (classify, search, priority, route) can be made in parallel. Draft and mark_complete come after them.\n", "\n", - "### Key Knowledge Base Info Learned\n", - "- Account: Password reset links expire in 1 hour, sent from noreply@support.example.com\n", - "- Billing: Refunds take 5-7 business days, pro-rated for annual plans, billing on same date monthly/yearly\n", - "\n", - "### Remaining Work\n", - "3 tickets left to process (TICKET-3 currently in progress, then TICKET-4 and TICKET-5)\n", - "\n", + "**Next step**: Call get_next_ticket for TICKET-3, then repeat the full workflow for TICKET-3, 4, and 5. Stop when the queue returns an empty error. Then give a brief final summary of all processed tickets.\n", "\n", "============================================================\n", - "Turn 17: Input= 1,774 tokens | Output= 94 tokens | Messages= 1 | Cumulative In= 52,861\n", - "Turn 18: Input= 1,906 tokens | Output= 95 tokens | Messages= 3 | Cumulative In= 54,767\n", - "Turn 19: Input= 2,365 tokens | Output= 431 tokens | Messages= 5 | Cumulative In= 57,132\n", - "Turn 20: Input= 3,164 tokens | Output= 60 tokens | Messages= 7 | Cumulative In= 60,296\n", - "Turn 21: Input= 3,383 tokens | Output= 160 tokens | Messages= 9 | Cumulative In= 63,679\n", - "Turn 22: Input= 3,872 tokens | Output= 447 tokens | Messages=11 | Cumulative In= 67,551\n", - "Turn 23: Input= 4,687 tokens | Output= 64 tokens | Messages=13 | Cumulative In= 72,238\n", - "Turn 24: Input= 4,914 tokens | Output= 160 tokens | Messages=15 | Cumulative In= 77,152\n", + "Turn 8: Input= 5,661 tokens | Output= 758 tokens | Messages=15 | Cumulative In= 28,045\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 9: Input= 2,087 tokens | Output= 30 tokens | Messages= 1 | Cumulative In= 30,132\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 10: Input= 2,303 tokens | Output= 355 tokens | Messages= 3 | Cumulative In= 32,435\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 11: Input= 3,145 tokens | Output= 355 tokens | Messages= 5 | Cumulative In= 35,580\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 12: Input= 3,751 tokens | Output= 30 tokens | Messages= 7 | Cumulative In= 39,331\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 13: Input= 3,982 tokens | Output= 314 tokens | Messages= 9 | Cumulative In= 43,313\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 14: Input= 4,890 tokens | Output= 426 tokens | Messages=11 | Cumulative In= 48,203\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 15: Input= 5,569 tokens | Output= 30 tokens | Messages=13 | Cumulative In= 53,772\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "\n", "============================================================\n", - "🔄 Compaction occurred! Messages: 15 → 1\n", - " Summary message after compaction:\n", - "\n", - "## Support Ticket Processing Progress Summary\n", - "\n", - "### Task Overview\n", - "Processing 5 support tickets sequentially, completing all 7 steps for each ticket (fetch, classify, research, prioritize, route, draft, complete).\n", - "\n", - "### Tickets Completed (4 of 5)\n", - "\n", - "**TICKET-1 (Chris Davis) - COMPLETED**\n", - "- Issue: Account locked, unlock email link not working\n", - "- Category: account\n", - "- Priority: high\n", - "- Team: account-services\n", - "- Status: resolved\n", - "- Response: Provided guidance on checking spam folder, link expiration (1 hour), and requesting new unlock link\n", - "\n", - "**TICKET-2 (Chris Williams) - COMPLETED**\n", - "- Issue: Unrecognized $49.99 charge on 2025-10-30\n", - "- Category: billing\n", - "- Priority: high\n", - "- Team: billing-team\n", - "- Status: resolved\n", - "- Response: Explained billing cycles, subscription possibility, and refund policy (5-7 business days, pro-rated for annual plans)\n", + "🔄 Compaction occurred! 15 messages condensed into one summary block\n", + " Summary after compaction:\n", + "## Progress summary\n", "\n", - "**TICKET-3 (John Jones) - COMPLETED**\n", - "- Issue: Asking about Google Sheets integration for project management\n", - "- Category: product\n", - "- Priority: medium\n", - "- Team: product-success\n", - "- Status: resolved\n", - "- Response: Explained that Product Success team will provide details on integration options, API access, and current/planned features\n", + "**Task**: Process 5 support tickets one at a time. For each ticket: get_next_ticket → classify_ticket → search_knowledge_base → set_priority → route_to_team → draft_response → mark_complete. Keep going until the queue is empty (the 5 tickets are expected in total).\n", "\n", - "**TICKET-4 (Sam Johnson) - COMPLETED**\n", - "- Issue: Wants to know differences between Standard and Premium plans, specifically \"advanced analytics\"\n", - "- Category: product\n", - "- Priority: low\n", - "- Team: product-success\n", - "- Status: resolved\n", - "- Response: Explained that Product Success team will provide detailed plan comparison and feature breakdown\n", + "**Completed so far (4 of 5):**\n", + "- **TICKET-1** (John Williams, tracking number reported invalid): shipping, medium, logistics-team. Draft made no unsupported claims. Marked complete.\n", + "- **TICKET-2** (Alex Jones, wrong item received on order #ORD-66101; the subject line didn't match the description): shipping, medium, logistics-team. Marked complete.\n", + "- **TICKET-3** (Alex Jones, password reset emails not arriving): account, medium, account-services. The draft cited the KB (emails come from noreply@support.example.com, the link expires in 1 hour). It flagged that the ticket email (customer8695@) differs from the email in the description (customer6750@) and asked the customer to confirm which is registered. Marked complete.\n", + "- **TICKET-4** (John Smith, unrecognized $49.99 charge on 2026-10-20): billing, high, billing-team. The draft explained the billing cycle, did not claim to know what the charge was, mentioned refund policy conditionally, and asked for the last four digits only. Marked complete.\n", "\n", - "### Current Status\n", - "**TICKET-5 (Morgan Brown) - IN PROGRESS**\n", - "- Issue: Damaged package (Order #ORD-43312), broken product inside, needs replacement\n", - "- Category: shipping (classified)\n", - "- Priority: NOT YET SET\n", - "- Team: NOT YET ASSIGNED\n", - "- Steps completed: 1 (fetch), 2 (classify), 3 (research KB - no shipping info found)\n", - "- Steps remaining: 4 (set priority), 5 (route), 6 (draft), 7 (mark complete)\n", + "**Currently in progress: TICKET-5** (just fetched, no actions taken yet):\n", + "- Jane Brown, customer4919@example.com, subject \"Account locked after failed login\". She says the account was locked after too many wrong password attempts. She now remembers her password, but the unlock email link isn't working. Pre-set category: account. Created 2026-10-19.\n", + "- Plan: classify as account, search the account KB (e.g. \"account locked unlock\"), set priority (medium, or high since she is locked out), route to account-services. Then draft a response that doesn't invent unlock policy beyond what the KB returns, and mark complete. The KB has password_reset (emails from noreply@support.example.com, check spam, link expires in 1 hour), 2fa_backup, and email_change, so there may be no lockout-specific entry. If so, say the Account Services team will verify her identity and help unlock the account, and suggest requesting a new link since the old one may have expired.\n", "\n", - "### Next Steps for TICKET-5\n", - "1. Set priority (likely HIGH - damaged/broken product requiring replacement)\n", - "2. Route to appropriate team (likely fulfillment, operations, or customer-service team)\n", - "3. Draft response addressing damaged shipment, replacement process, and next steps\n", - "4. Mark complete\n", - "5. **ALL TICKETS WILL BE COMPLETE**\n", + "**Notes on the tools:**\n", + "- The KB only has the categories billing, technical, and account. \"shipping\" returns an error.\n", + "- Valid teams: billing-team, tech-support, account-services, product-success, logistics-team.\n", + "- Independent calls (classify, search, priority, route) can be made in parallel. Draft and mark_complete come after them (these two can also go in parallel).\n", "\n", - "### Key Knowledge Base Info Learned\n", - "- **Account**: Password reset links expire in 1 hour, sent from noreply@support.example.com\n", - "- **Billing**: Refunds take 5-7 business days, pro-rated for annual plans, billing on same date monthly/yearly; accepts Visa, Mastercard, Amex, PayPal\n", - "- **Technical**: Max upload 100MB, supported formats: PDF, DOCX, PNG, JPG, CSV; system requirements: 4GB RAM, modern browsers\n", - "- **Product category**: Does not exist in KB (only billing, technical, account available)\n", - "- **Shipping info**: Not found in knowledge base\n", - "\n", - "### Team Routing Patterns Observed\n", - "- account-services: Account access issues\n", - "- billing-team: Billing/payment inquiries\n", - "- product-success: Product features, integrations, plan comparisons\n", - "\n", - "### Remaining Work\n", - "1 ticket left to complete (TICKET-5 - final ticket, currently in progress at step 3 of 7)\n", - "\n", + "**Next steps**: Finish TICKET-5 with the full workflow. Then call get_next_ticket once more to confirm the queue is empty. Then give a brief final summary of all 5 processed tickets, noting the oddities flagged: the TICKET-2 subject/description mismatch, the TICKET-3 email mismatch, and the absence of a shipping KB category.\n", "\n", "============================================================\n", - "Turn 25: Input= 2,077 tokens | Output= 496 tokens | Messages= 1 | Cumulative In= 79,229\n", - "Turn 26: Input= 2,942 tokens | Output= 438 tokens | Messages= 3 | Cumulative In= 82,171\n", + "Turn 16: Input= 5,840 tokens | Output=1,027 tokens | Messages=15 | Cumulative In= 59,612\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 17: Input= 2,356 tokens | Output= 309 tokens | Messages= 1 | Cumulative In= 61,968\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 18: Input= 3,217 tokens | Output= 386 tokens | Messages= 3 | Cumulative In= 65,185\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Turn 19: Input= 3,910 tokens | Output= 460 tokens | Messages= 5 | Cumulative In= 69,095\n", "\n", "============================================================\n", "OPTIMIZED RESULTS (WITH COMPACTION)\n", "============================================================\n", - "Total turns: 26\n", + "Total turns: 19\n", "Compactions: 2\n", - "Input tokens: 82,171\n", - "Output tokens: 4,275\n", - "Total tokens: 86,446\n", + "Input tokens: 69,095\n", + "Output tokens: 5,988\n", + "Total tokens: 75,083\n", "============================================================\n" ] } @@ -607,50 +679,62 @@ "# Re-initialize queue and run with compaction\n", "initialize_ticket_queue(num_tickets)\n", "\n", + "COMPACTION_THRESHOLD = 5000 # input tokens; low on purpose for the demo\n", + "\n", + "\n", + "def turn_tokens(message) -> tuple[int, int]:\n", + " \"\"\"Input/output tokens for one runner turn.\n", + "\n", + " A compaction turn reports zero top-level tokens and lists the summarization\n", + " call under usage.iterations, so sum those instead.\n", + " \"\"\"\n", + " if message.stop_reason == \"compaction\" and message.usage.iterations:\n", + " return (\n", + " sum(it.input_tokens for it in message.usage.iterations),\n", + " sum(it.output_tokens for it in message.usage.iterations),\n", + " )\n", + " return message.usage.input_tokens, message.usage.output_tokens\n", + "\n", + "\n", "total_input_compact = 0\n", "total_output_compact = 0\n", "turn_count_compact = 0\n", "compaction_count = 0\n", - "prev_msg_count = 0\n", "\n", "runner = client.beta.messages.tool_runner(\n", " model=MODEL,\n", " max_tokens=4096,\n", " tools=tools,\n", " messages=messages,\n", - " compaction_control={\n", - " \"enabled\": True,\n", - " \"context_token_threshold\": 5000,\n", - " # Summarize with a cheaper model. This also keeps the summary turn text-only;\n", - " # the SDK's compaction step reads the first content block as text.\n", - " \"model\": \"claude-haiku-4-5\",\n", - " },\n", + " betas=[\"compact-2026-09-04\"],\n", ")\n", "\n", "for message in runner:\n", " turn_count_compact += 1\n", - " total_input_compact += message.usage.input_tokens\n", - " total_output_compact += message.usage.output_tokens\n", + " input_tokens, output_tokens = turn_tokens(message)\n", + " total_input_compact += input_tokens\n", + " total_output_compact += output_tokens\n", " messages_list = list(runner._params[\"messages\"])\n", - " curr_msg_count = len(messages_list)\n", "\n", - " if curr_msg_count < prev_msg_count:\n", - " # We can identify compaction when the message count decreases\n", + " if message.stop_reason == \"compaction\":\n", + " # Before its next request the runner replaces the whole history with this single block.\n", " compaction_count += 1\n", - "\n", + " summary = next(block.content for block in message.content if block.type == \"compaction\")\n", " print(f\"\\n{'=' * 60}\")\n", - " print(f\"🔄 Compaction occurred! Messages: {prev_msg_count} → {curr_msg_count}\")\n", - " print(\" Summary message after compaction:\")\n", - " # After compaction the SDK replaces the history with a single user message whose\n", - " # content is a list of plain dict blocks holding the summary.\n", - " summary_blocks = messages_list[-1][\"content\"]\n", - " print(\"\".join(b[\"text\"] if isinstance(b, dict) else b.text for b in summary_blocks))\n", + " print(\n", + " f\"🔄 Compaction occurred! {len(messages_list)} messages condensed into one summary block\"\n", + " )\n", + " print(\" Summary after compaction:\")\n", + " print(summary)\n", " print(f\"\\n{'=' * 60}\")\n", + " elif message.stop_reason == \"tool_use\" and input_tokens > COMPACTION_THRESHOLD:\n", + " # Schedule a compaction; it runs once this turn's tool calls are answered.\n", + " # (Only on tool_use turns: the final end_turn answer needs no compaction.)\n", + " runner.compact_before_next_turn()\n", "\n", - " prev_msg_count = curr_msg_count\n", " print(\n", - " f\"Turn {turn_count_compact:2d}: Input={message.usage.input_tokens:7,} tokens | \"\n", - " f\"Output={message.usage.output_tokens:5,} tokens | \"\n", + " f\"Turn {turn_count_compact:2d}: Input={input_tokens:7,} tokens | \"\n", + " f\"Output={output_tokens:5,} tokens | \"\n", " f\"Messages={len(messages_list):2d} | \"\n", " f\"Cumulative In={total_input_compact:8,}\"\n", " )\n", @@ -671,9 +755,9 @@ "id": "5cbbfe32", "metadata": {}, "source": [ - "With automatic context compaction enabled, we can see that our token usage per turn does not grow linearly, but is reduced after each compaction event. There were two compaction events during the processing of tickets, and the follow turn shows a reduction in total token usage.\n", + "With context compaction enabled, token usage per turn no longer grows linearly: it drops back after each compaction event, and the following turns start from the summary instead of the full history.\n", "\n", - "Compared to the baseline version, we only used 79,000 tokens. We've also printed out the summary messages generated after each compaction event, showing how Claude effectively condensed prior ticket details into summaries.\n", + "Compared to the baseline, the run uses far fewer input tokens (the comparison table below has the totals). We've also printed the summary returned by each compaction, showing how prior ticket details were condensed.\n", "\n", "Let's look at the final response after processing all 5 tickets with compaction enabled." ] @@ -688,37 +772,22 @@ "name": "stdout", "output_type": "stream", "text": [ - "Perfect! **ALL 5 TICKETS HAVE BEEN SUCCESSFULLY COMPLETED!** 🎉\n", - "\n", - "## Final Summary - All Tickets Processed\n", + "All 5 tickets are processed and the queue is empty.\n", "\n", - "### TICKET-5 (Morgan Brown) - **COMPLETED** ✓\n", - "- **Issue**: Damaged package (Order #ORD-43312), broken product inside, needs replacement\n", - "- **Category**: shipping\n", - "- **Priority**: high\n", - "- **Team**: logistics-team\n", - "- **Status**: resolved\n", - "- **Response**: Apologized for damaged shipment, escalated to Logistics Team with HIGH priority, explained they'll process immediate replacement, provide return instructions, and contact customer with tracking and timeline\n", + "| Ticket | Customer | Issue | Category | Priority | Team |\n", + "|---|---|---|---|---|---|\n", + "| TICKET-1 | John Williams | Tracking number reported invalid | shipping | medium | logistics-team |\n", + "| TICKET-2 | Alex Jones | Wrong item received on order #ORD-66101 | shipping | medium | logistics-team |\n", + "| TICKET-3 | Alex Jones | Password reset emails not arriving | account | medium | account-services |\n", + "| TICKET-4 | John Smith | Unrecognized $49.99 charge | billing | high | billing-team |\n", + "| TICKET-5 | Jane Brown | Account locked, unlock link not working | account | high | account-services |\n", "\n", - "---\n", + "Each ticket has a draft response and is marked complete.\n", "\n", - "## 🎯 ALL 5 TICKETS COMPLETED\n", - "\n", - "1. ✅ **TICKET-1** (Chris Davis) - Account locked → account-services\n", - "2. ✅ **TICKET-2** (Chris Williams) - Billing charge → billing-team \n", - "3. ✅ **TICKET-3** (John Jones) - Google Sheets integration → product-success\n", - "4. ✅ **TICKET-4** (Sam Johnson) - Plan comparison → product-success\n", - "5. ✅ **TICKET-5** (Morgan Brown) - Damaged shipment → logistics-team\n", - "\n", - "### Processing Statistics\n", - "- **Total tickets processed**: 5 of 5 (100%)\n", - "- **Steps per ticket**: 7 (fetch, classify, research, prioritize, route, draft, complete)\n", - "- **Total operations**: 35 successful operations\n", - "- **Categories used**: account, billing, product (2x), shipping\n", - "- **Teams utilized**: account-services, billing-team, product-success (2x), logistics-team\n", - "- **Priority distribution**: 2 high, 2 medium, 1 low\n", - "\n", - "All tickets have been properly classified, prioritized, routed to the appropriate teams, and have draft responses ready for team review! 🎊\n" + "Three things to check:\n", + "- **TICKET-2:** The subject line doesn't match the description. I went by the description.\n", + "- **TICKET-3:** The email on the ticket (customer8695@) differs from the one in the description (customer6750@). The draft asks the customer to confirm which one is registered.\n", + "- **Knowledge base gaps:** The knowledge base has no shipping category, so the shipping drafts make no policy claims. It also has no entry on account lockouts. The TICKET-5 draft only cites the password-reset link expiry and hands the unlock to Account Services.\n" ] } ], @@ -733,15 +802,15 @@ "source": [ "### Comparing Results\n", "\n", - "With compaction enabled, we can see a clear differece between the two runs in token savings, while preserving the quality of the workflow and final summary.\n", + "With compaction enabled, we can see a clear difference between the two runs in token savings, while preserving the quality of the workflow and final summary.\n", "\n", "Here's what changed with automatic context compaction:\n", "\n", - "1. **Context resets after several tickets** - When processing 5-7 tickets generates 5k+ tokens of tool results, the SDK automatically:\n", - " - Injects a summary prompt\n", - " - Has Claude generate a completion summary wrapped in `` tags\n", - " - Clears the conversation history and discards detailed classifications, KB searches, and responses\n", - " - Continues with only the completion summary\n", + "1. **Context resets after several tickets** - When a few tickets' worth of tool results pushes a turn past 5k input tokens, the loop calls `compact_before_next_turn()` and the runner:\n", + " - Finishes the current turn's tool calls, then sends a compaction request\n", + " - Receives a server-generated summary as a `compaction` block\n", + " - Replaces the conversation history (detailed classifications, KB searches, responses) with that block\n", + " - Continues with only the summary\n", "\n", "2. **Input tokens stay bounded** - Instead of accumulating to 100k+ as we process more tickets, input tokens reset after each compaction. When processing Ticket #5, we're NOT carrying the full tool results from Tickets #1-4.\n", "\n", @@ -775,13 +844,13 @@ "======================================================================\n", "Metric Baseline With Compaction \n", "----------------------------------------------------------------------\n", - "Input tokens: 204,416 82,171\n", - "Output tokens: 4,422 4,275\n", - "Total tokens: 208,838 86,446\n", + "Input tokens: 109,269 69,095\n", + "Output tokens: 4,238 5,988\n", + "Total tokens: 113,507 75,083\n", "Compactions: N/A 2\n", "======================================================================\n", "\n", - "💰 Token Savings: 122,392 tokens (58.6% reduction)\n" + "💰 Token Savings: 38,424 tokens (33.9% reduction)\n" ] } ], @@ -816,17 +885,13 @@ "source": [ "## How Compaction Works Under the Hood\n", "\n", - "When the `tool_runner` detects that token usage has exceeded the threshold, it automatically:\n", - "\n", - "1. **Pauses the workflow** before making the next API call\n", - "2. **Injects a summary request** as a user message asking Claude to summarize progress\n", - "3. **Generates a summary** - Claude produces a summary wrapped in `` tags containing:\n", - " - **Completed tickets**: Brief records of tickets resolved (IDs, categories, priorities, outcomes)\n", - " - **Progress status**: How many tickets processed, how many remain\n", - " - **Key patterns**: Any notable trends across tickets\n", - " - **Next steps**: What to do next (continue processing remaining tickets)\n", - "4. **Clears history** - The entire conversation history (including all tool results) is replaced with just the summary\n", - "5. **Resumes processing** - Claude continues working with the compressed context, processing the next batch of tickets" + "When you call `runner.compact_before_next_turn()`, the tool runner:\n", + "\n", + "1. **Lets the current turn finish** - pending tool calls are run and their results appended first, because the API can't compact a conversation that ends with an unanswered tool call\n", + "2. **Sends a compaction request** - the same model, system prompt, tools and messages, plus `compaction={\"type\": \"summarize\"}`. Nothing is sampled after the summary, so this request returns only the summary\n", + "3. **Receives a `compaction` block** - the API summarizes the conversation server-side (completed tickets, progress, what to do next) and returns it as a single content block with `stop_reason == \"compaction\"`\n", + "4. **Replaces history** - the runner swaps the entire message list (including all tool results) for that one block, which must be sent back first and unmodified\n", + "5. **Resumes processing** - the next request continues from the compressed context, and Claude picks up the next ticket" ] }, { @@ -836,17 +901,18 @@ "source": [ "## Customizing Compaction Configuration\n", "\n", - "You can customize how compaction works to fit your specific use case. Here are the key configuration options:\n", + "You can customize how compaction works to fit your specific use case. Here are the key knobs:\n", "\n", "### Adjusting the Threshold\n", "\n", - "The `context_token_threshold` determines when compaction triggers:\n", + "With runner-driven compaction the threshold is your own loop logic, so it can be any value or any condition (for example, \"after every third `mark_complete` call\"):\n", "\n", "```python\n", - "compaction_control={\n", - " \"enabled\": True,\n", - " \"context_token_threshold\": 5000, # Compact after processing 5-7 tickets\n", - "}\n", + "COMPACTION_THRESHOLD = 5000 # Compact after processing a few tickets\n", + "\n", + "for message in runner:\n", + " if message.stop_reason == \"tool_use\" and message.usage.input_tokens > COMPACTION_THRESHOLD:\n", + " runner.compact_before_next_turn()\n", "```\n", "\n", "The threshold should not be set too low, otherwise the summary itself could trigger a compaction. We set a threshold of 5,000 tokens for demonstration purposes, but in practice, experiment with different settings to find what works best for your workflow.\n", @@ -867,21 +933,10 @@ " - Tasks requiring substantial historical context\n", " - Less frequent compaction preserves more raw details\n", " - Higher per-call costs but fewer compactions\n", - " \n", - "- **Default (100k)**: Good balance for general long-running tasks\n", - "\n", - "**For ticket processing**: The 5k threshold works well because each ticket's workflow generates substantial tool results, but tickets are independent. After resolving Ticket A, you don't need its detailed KB searches when processing Ticket B.\n", - "\n", - "### Using a Different Model for Summarization\n", "\n", - "You can also use a faster/cheaper model for generating summaries:\n", + "If all you need is a fixed token trigger of 50k or more, you don't need loop logic at all: pass a `context_management` compaction edit and the API compacts automatically (see the [compaction docs](https://platform.claude.com/docs/en/build-with-claude/compaction)). The runner refuses to combine that edit with `compact_before_next_turn()`, so pick one approach per runner.\n", "\n", - "```python\n", - "compaction_control={\n", - " \"enabled\": True,\n", - " \"model\": \"claude-haiku-4-5\", # Use Haiku for cost-effective summaries\n", - "}\n", - "```" + "**For ticket processing**: The 5k threshold works well because each ticket's workflow generates substantial tool results, but tickets are independent. After resolving Ticket A, you don't need its detailed KB searches when processing Ticket B." ] }, { @@ -889,9 +944,9 @@ "id": "w4oyvorzkn", "metadata": {}, "source": [ - "### Custom Summary Prompts\n", + "### Custom Summary Instructions\n", "\n", - "You can provide a custom prompt to guide how summaries are generated. This is especially useful for customer service workflows where you need to preserve specific types of information.\n", + "You can pass `instructions` to replace the server's default summarization prompt. This is especially useful for customer service workflows where you need to preserve specific types of information.\n", "\n", "For example, we could define a custom prompt based on our requirements:\n", "- **Ticket summaries** for all completed tickets\n", @@ -901,9 +956,10 @@ "- **Next steps** in the workflow\n", "\n", "```python\n", - "compaction_control={\n", - " \"enabled\": True,\n", - " \"summary_prompt\": \"\"\"You are processing customer support tickets from a queue.\n", + "runner.compact_before_next_turn(\n", + " {\n", + " \"type\": \"summarize\",\n", + " \"instructions\": \"\"\"You are processing customer support tickets from a queue.\n", "\n", "Create a focused summary that preserves:\n", "\n", @@ -919,8 +975,9 @@ "\n", "3. **NEXT STEPS**: Continue processing the next ticket\n", "\n", - "Format with clear sections and wrap in tags.\"\"\"\n", - "}\n", + "Format with clear sections.\"\"\",\n", + " }\n", + ")\n", "```" ] }, @@ -933,7 +990,7 @@ "\n", "While the examples above focus on tool-heavy agentic workflows, context compaction is also valuable for **simple conversational applications** where users drive the conversation.\n", "\n", - " **Note:** The `compaction_control` parameter demonstrated above works with `tool_runner` for agentic workflows with tools. For simple chat applications without tools, you'll implement compaction manually using the same principles.\n", + "**Note:** `compact_before_next_turn()` is a tool-runner method. In a plain chat loop you can either send `compaction={\"type\": \"summarize\"}` on a `client.beta.messages.create()` call yourself and put the returned block first in `messages`, or implement the summarization manually as shown below, which works with any model and gives you full control over the summary prompt.\n", "\n", "Consider a chat application where users are having extended conversations with Claude—discussing complex topics, iterating on ideas, or working through problems. As the conversation grows, you face the same context accumulation challenges.\n", "\n", @@ -957,7 +1014,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "m6akcmnsz09", "metadata": {}, "outputs": [ @@ -971,6 +1028,116 @@ "\n", "You: Help me understand how Python decorators work\n" ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Claude: # Python Decorators\n", + "\n", + "A decorator is a function that takes another function and returns a modified or enhanced version of it, without you changing the original function's code.\n", + "\n", + "## 1. The building blocks\n", + "\n", + "Decorators rely on two Python features.\n", + "\n", + "**Functions are objects.** You can assign them to varia ...\n", + "\n", + "[Tokens: 20 in + 1497 out = 1517 total]\n", + "\n", + "You: Can you show me an example with a timing decorator?\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Claude: # Timing Decorator: Full Example\n", + "\n", + "## Basic version\n", + "\n", + "```python\n", + "import time\n", + "import functools\n", + "\n", + "def timer(func):\n", + " @functools.wraps(func)\n", + " def wrapper(*args, **kwargs):\n", + " start = time.perf_counter()\n", + " result = func(*args, **kwargs)\n", + " elapsed = time.perf_counter() - start\n", + " p ...\n", + "\n", + "[Tokens: 1536 in + 1437 out = 2973 total]\n", + "\n", + "You: How would I make a decorator that takes arguments?\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Claude: # Decorators That Take Arguments\n", + "\n", + "## The core idea\n", + "\n", + "A normal decorator is a function that takes a function. To pass arguments, add one more layer: a function that takes the arguments and **returns** a decorator.\n", + "\n", + "```\n", + "decorator_factory(args) → decorator(func) → wrapper(*args, **kwargs)\n", + "```\n", + "\n", + "## Th ...\n", + "\n", + "[Tokens: 2992 in + 1641 out = 4633 total]\n", + "\n", + "============================================================\n", + "🔄 Compacting conversation... 6 messages → " + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 message\n", + "============================================================\n", + "\n", + "Final conversation messages: \n", + "## Continuation Summary\n", + "\n", + "### 1. Task Overview\n", + "The user is learning Python decorators through a conversational Q&A. There is no fixed deliverable or file output. The goal is clear, accurate, example-driven explanations. No explicit constraints were given beyond the questions asked. The task is not \"unfinished\" in a strict sense; the conversation is open-ended and the user may ask further follow-ups.\n", + "\n", + "### 2. Current State\n", + "Three user questions have been answered, all in chat (no files created or modified):\n", + "\n", + "1. **\"Help me understand how Python decorators work\"** – Covered: functions as first-class objects, nested/returned functions, manual decoration (`greet = shout(greet)`), `@` syntax as sugar, `*args/**kwargs` wrappers, `functools.wraps`, decorators with arguments (brief), a timing example, stacking order (`@a @b def f` = `a(b(f))`), a table of common built-in decorators (`staticmethod`, `classmethod`, `property`, `lru_cache`, `dataclass`), and a mental model. Ended by offering to go deeper on class-based decorators, decorating classes, and closures.\n", + "2. **\"Can you show me an example with a timing decorator?\"** – Provided: a basic `timer` using `time.perf_counter()`, usage with args/return values, a `try/finally` version so timing prints even on exceptions, a configurable version `timer(label=None, log=False)` (requires parentheses), an `async_timer` for coroutines, a step-by-step call flow, and a note pointing to `timeit` for serious benchmarking.\n", + "3. **\"How would I make a decorator that takes arguments?\"** – Provided: the three-layer pattern (factory → decorator → wrapper), the desugaring `@repeat(3)` = `repeat(3)(func)`, closures as the reason inner layers see outer args, a `require_role` access-control example, an optional-parentheses pattern (`func=None, *, times=2`), common mistakes (missing parentheses, missing returns, omitting `wraps`), and a class-based alternative (`__init__` stores args, `__call__` takes the function).\n", + "\n", + "### 3. Important Discoveries / Decisions\n", + "- Consistent teaching approach: build from first principles, show the desugared equivalent, then give practical examples.\n", + "- Always include `@functools.wraps(func)` in examples, and explain why.\n", + "- Use `time.perf_counter()` over `time.time()` for timing.\n", + "- Use `try/finally` in timing decorators so exceptions don't skip the measurement.\n", + "- Async functions need an `async def wrapper` with `await`; a sync wrapper would only time coroutine creation.\n", + "- No errors or failed approaches have occurred.\n", + "\n", + "### 4. Next Steps\n", + "- No required actions remain. Await the user's next question.\n", + "- Likely follow-ups, already offered or naturally adjacent: class-based decorators (a class with `__call__` that wraps a function, and keeping state such as call counters), decorating classes, closures in depth, `lru_cache`/memoization, decorators on methods (handling `self`), stacking order subtleties, a retry/caching/validation decorator example, type hints for decorators (`ParamSpec`, `TypeVar`), and testing decorated functions (`__wrapped__`).\n", + "\n", + "### 5. Context to Preserve\n", + "- Style: Markdown with headers, short code blocks with printed output shown in comments or output blocks, brief explanatory prose, and a concise summary or mental model at the end. Code is runnable and minimal.\n", + "- The user appears to be a learner, so build up concepts incrementally and avoid unexplained jargon.\n", + "- Promises made: offered to go deeper on class-based decorators, decorating classes, and how closures work, if the user wants.\n", + "\n", + "\n", + "Demo complete! In a real application, this loop would continue with user input.\n" + ] } ], "source": [ @@ -1128,11 +1295,11 @@ "\n", "**Key Differences from Tool Runner**:\n", "\n", - "| Aspect | Tool Runner (Automatic) | Chat Loop (Manual) |\n", + "| Aspect | Tool Runner (`compact_before_next_turn`) | Chat Loop (Manual) |\n", "|--------|------------------------|-------------------|\n", - "| **Trigger** | Automatic when threshold reached | You implement threshold check |\n", - "| **Summary** | SDK handles summary request | You make explicit API call |\n", - "| **History Management** | SDK replaces messages | You manually replace list |\n", + "| **Trigger** | Your threshold check schedules it; runner picks the moment | You implement threshold check |\n", + "| **Summary** | Generated server-side, returned as a `compaction` block | You make explicit API call with your own prompt |\n", + "| **History Management** | Runner replaces messages | You manually replace list |\n", "| **Use Case** | Agentic workflows with tools | User-driven conversations |\n", "\n", "**Production Considerations**:\n", @@ -1142,7 +1309,7 @@ "3. **Show user indicators**: Display a message like \"Summarizing conversation...\" so users understand the pause\n", "4. **Preserve key context**: Ensure the summary prompt captures domain-specific information your users care about\n", "\n", - "This pattern gives you full control over when and how compaction happens, making it ideal for conversational applications where the SDK's automatic tool-runner compaction isn't available." + "This pattern gives you full control over when and how compaction happens, making it ideal for conversational applications where you aren't using the tool runner." ] }, { @@ -1154,18 +1321,11 @@ "\n", "While automatic context compaction is powerful, there are important limitations to understand:\n", "\n", - "### Server-Side Sampling Loops\n", - "\n", - "**Current Limitation**: Compaction does not work optimally with server-side sampling loops, such as server-side web search tools.\n", + "### Measuring the Threshold\n", "\n", - "**Why**: Cache tokens accumulate across sampling loops, which can trigger compaction prematurely based on cached content rather than actual conversation history.\n", + "**Watch what you count**: this cookbook triggers on `usage.input_tokens`. With prompt caching enabled most of the history shows up under `cache_read_input_tokens` instead, and server-side tool loops (web search, code execution) report several `usage.iterations` per turn. Sum the counters that reflect real history size in your workflow, or the trigger fires too late or too early.\n", "\n", - "This feature works best with:\n", - "- ✅ Client-side tools (like the customer service API in this cookbook)\n", - "- ✅ Standard agentic workflows with regular tool use\n", - "- ✅ File operations, database queries, API calls\n", - "- ❌ Server-side Extended Thinking\n", - "- ❌ Server-side web search tools\n", + "**Timing**: a scheduled compaction runs only after the current turn's tool calls have been answered, and it is skipped (with a warning) if the run ends on a turn with unanswered tool calls.\n", "\n", "### Information Loss\n", "\n", @@ -1188,8 +1348,7 @@ "\n", "1. **Short tasks**: If your task completes within 50k-100k tokens, compaction adds unnecessary overhead\n", "2. **Tasks requiring full audit trails**: Some tasks need access to ALL previous details\n", - "3. **Server-side sampling workflows**: As mentioned above, wait for this limitation to be addressed\n", - "4. **Highly iterative refinement**: Tasks where each step critically depends on exact details from all previous steps\n", + "3. **Highly iterative refinement**: Tasks where each step critically depends on exact details from all previous steps\n", "\n", "### When TO Use Compaction\n", "\n", @@ -1246,9 +1405,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.12" + "version": "3.12.14" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/content/mcp/extensions/client-matrix.md b/content/mcp/extensions/client-matrix.md index 8387f3e47e..baa8ecb868 100644 --- a/content/mcp/extensions/client-matrix.md +++ b/content/mcp/extensions/client-matrix.md @@ -41,6 +41,7 @@ This matrix shows which MCP clients support each [official extension](https://mo | [fast-agent](https://github.com/evalstate/fast-agent) | | | | [Partial](https://github.com/evalstate/fast-agent/blob/main/docs/docs/mcp/skills-over-mcp.md) | | | [MCP Inspector](https://github.com/modelcontextprotocol/inspector) | | | | [Partial](https://github.com/modelcontextprotocol/inspector/blob/main/clients/cli/README.md#skill-verification---verify) | | | [mcpc MCP CLI](https://github.com/apify/mcpc) | | | | | | +| [Glean](https://www.glean.com/) | | | | | | > [!NOTE] > diff --git a/content/support/10310342-how-do-i-log-out-of-all-active-sessions.md b/content/support/10310342-how-do-i-log-out-of-all-active-sessions.md index 9c95068c59..15b02eeaa6 100644 --- a/content/support/10310342-how-do-i-log-out-of-all-active-sessions.md +++ b/content/support/10310342-how-do-i-log-out-of-all-active-sessions.md @@ -46,7 +46,7 @@ Logging out of all active sessions also logs you out of Claude Code. To log out If you used your Claude account to authenticate into Claude Code, you can see and log out of those sign-ins in **Settings > Account**, where they're listed with your other sessions. If they aren't listed there, manage your authorization tokens in **Settings > Claude Code**. To remove a token and log out of Claude Code, click the trash can icon. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1608263923/b4fa7d6f6f08f2adffb4ea63bc58/image+%287%29.png?expires=1793653200&signature=73c2748fcdc308b3d977d4ad957601eb50473e647a7fc5fa5c0c0c1e29cf4d50&req=dSYnHst4nohdWvMW1HO4zVuHix%2F702S5AQofdwM8qVdkR9J4vla9R1uzEAB%2B%0Anafnf1kIDjZBA%2Bq6Mow%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1608263923/b4fa7d6f6f08f2adffb4ea63bc58/image+%287%29.png?expires=1793691900&signature=c8cd928eadbaf5de340b7fbf244a4b00bf25daac0c9e93d1eaf6798636090bf0&req=dSYnHst4nohdWvMW1HO4zVuHix%2F732ayAQofdwM8qVduTwJCm5c0TwQUFClZ%0AUoYmG1Rp11%2BKNL%2BilK8%3D%0A) ## Unable to access your account? diff --git a/content/support/10504844-manage-user-feedback-settings-on-team-and-enterprise-plans.md b/content/support/10504844-manage-user-feedback-settings-on-team-and-enterprise-plans.md index cb49a0e895..c365a40951 100644 --- a/content/support/10504844-manage-user-feedback-settings-on-team-and-enterprise-plans.md +++ b/content/support/10504844-manage-user-feedback-settings-on-team-and-enterprise-plans.md @@ -6,6 +6,6 @@ As a Primary Owner or Owner of a Team or Enterprise plan, you can manage the abi 2. Use the toggle to change the **Rate chats** setting for your organization: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2058292603/75752add0bed6a9f3ab217f01708/CleanShot%2B2026-02-12%2Bat%2B08_55_14-402x.png?expires=1793653200&signature=f044708b79856ef3a2d5c6fb3a40dfd6f00c93702e33ea08806d4c20e37b6880&req=diAiHst3n4dfWvMW1HO4zYGm8yQaFavO085gFtEpvcR9uklowezKRV4sgfXH%0A7D6iHROLxfLHq5eB8RY%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2058292603/75752add0bed6a9f3ab217f01708/CleanShot%2B2026-02-12%2Bat%2B08_55_14-402x.png?expires=1793691900&signature=d8c35efc1901b730d4e5929bd04deb8944378997ab67cf5b48fc42d61e9858e1&req=diAiHst3n4dfWvMW1HO4zYGm8yQaGanF085gFtEpvcSCZYp3rVuh5vtF8vf4%0AyzrQ5BSFKtb24zWAUNY%3D%0A) More information on how Anthropic collects, uses, and stores feedback data can be found in our Privacy Center: **[How long do you store my organization’s data?](https://privacy.claude.com/en/articles/7996866-how-long-do-you-store-my-organization-s-data)** \ No newline at end of file diff --git a/content/support/10593882-share-and-unshare-chats.md b/content/support/10593882-share-and-unshare-chats.md index 69cd50486c..e8c038b2fe 100644 --- a/content/support/10593882-share-and-unshare-chats.md +++ b/content/support/10593882-share-and-unshare-chats.md @@ -38,12 +38,12 @@ To unshare a chat: Users on Free, Pro, Max, or Ultra plans can review a log of shared chats by navigating to **[Settings > Privacy](https://claude.ai/settings/data-privacy-controls)**. Find the **Privacy settings** section and click “Manage” next to **Shared chats:** -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1921669913/7cc7be48cfc7a18f9f469d6cd83c/CleanShot+2026-01-08+at+10_20_43%402x.png?expires=1793653200&signature=8f8951b09e55e2a07591d9d399b3e7bf9e170bdef6d825184955159c7bad2d21&req=dSklF894lIheWvMW1HO4zWn5HjAbZ0Zpc9cNIYuX0GHi9Wq4B772MKyvZ4tH%0AR9IoVfC4ic0uFX5HNL0%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1921669913/7cc7be48cfc7a18f9f469d6cd83c/CleanShot+2026-01-08+at+10_20_43%402x.png?expires=1793691900&signature=f6005c611d4f7ec0cd51f39bbb6fe132bb071b508c2864efd1bedbe7461853f2&req=dSklF894lIheWvMW1HO4zWn5HjAba0Ric9cNIYuX0GFs0TsjWUWWgYg93Yf2%0A96HyBKbPBcflrvLkkTc%3D%0A) This will open a **Shared chats** modal listing the title, date shared, and link to each chat, allowing you to easily review and access all your previously-shared content. From here, you also have the option to click “Unshare” next to each listed chat to revoke access to the last snapshot you shared: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1624243810/e6fe1d262597446c7fe21dff9f10/AD_4nXdW-GhByF8uKV7fCq9lTbkVB91FglSL6TSyXAOUk_MLcTV9YsEMBMkm9rgm1oXqv0k3sJh1JhlzZP6tHVkKbDJJ71pDRRtM3aVNG64MDuKDIzgmknh-XDZdNa7biTsTdwGoPr5GRg?expires=1793653200&signature=c3ef4b505fd07c6b569d86854c4174428e4a13a8ba5e7c212e3486e77b616b0a&req=dSYlEst6noleWfMW1HO4ze44eSRnkRE8guvTv9woD7Zj7d1kE4nZgCvtceSf%0AjIsr74HGO6JHT0DOAPI%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1624243810/e6fe1d262597446c7fe21dff9f10/AD_4nXdW-GhByF8uKV7fCq9lTbkVB91FglSL6TSyXAOUk_MLcTV9YsEMBMkm9rgm1oXqv0k3sJh1JhlzZP6tHVkKbDJJ71pDRRtM3aVNG64MDuKDIzgmknh-XDZdNa7biTsTdwGoPr5GRg?expires=1793691900&signature=d0e8879240de091f88d74e3ed7405a60dc8aedf48f1ded94b9f8e8ae3e81f97c&req=dSYlEst6noleWfMW1HO4ze44eSRnnRM3guvTv9woD7YsX8V5dw5befMOUESM%0AXFyHSIIXeNnn6KXF5oE%3D%0A) If you don’t have any shared chat snapshots, the **Shared chats** modal will show “No shared content found”: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1624243808/b025db8e598f0c88fb16d83d48d5/AD_4nXeUwCKnmFzzrjMHhfr5By4zk5pJlkEn3wbJ8-aNfu13Yl99IjBywpqPx9G07QRzpH1EwRY7uG7Q9m9fib98Gql1cIV7XwUCTzEgBNu79Ey8tCOS5CEVmwveIcEOxJ4fonBhe3g9MA?expires=1793653200&signature=35d835c7606fbedd0c0a089260c4b9e1b3e336d3e88efd03f0568c772b2eec9f&req=dSYlEst6nolfUfMW1HO4zdaFnMZyhIqzDeZsm0Gz1Hsp1947XKk6xnyiOS%2BF%0AJ%2F3UKmc5KT7iUNrevbg%3D%0A) \ No newline at end of file +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1624243808/b025db8e598f0c88fb16d83d48d5/AD_4nXeUwCKnmFzzrjMHhfr5By4zk5pJlkEn3wbJ8-aNfu13Yl99IjBywpqPx9G07QRzpH1EwRY7uG7Q9m9fib98Gql1cIV7XwUCTzEgBNu79Ey8tCOS5CEVmwveIcEOxJ4fonBhe3g9MA?expires=1793691900&signature=5071b2a19518fe7cbf757242aeaf5414fda22de94fdef5ad05260d6a94ac8159&req=dSYlEst6nolfUfMW1HO4zdaFnMZyiIi4DeZsm0Gz1HurQp20Qs%2FpM4Bt%2FQiF%0AZSREbmvGpk0htLpZ44U%3D%0A) \ No newline at end of file diff --git a/content/support/10949351-getting-started-with-local-mcp-servers-on-claude-desktop.md b/content/support/10949351-getting-started-with-local-mcp-servers-on-claude-desktop.md index 989d1e078f..9b7e3f7bdc 100644 --- a/content/support/10949351-getting-started-with-local-mcp-servers-on-claude-desktop.md +++ b/content/support/10949351-getting-started-with-local-mcp-servers-on-claude-desktop.md @@ -48,7 +48,7 @@ for specific instructions. Custom desktop extensions uploads allow Team and Enterprise plans to leverage organization-specific workflows that aren’t available in the public directory. After creating a custom desktop extension, Owners and Primary Owners can navigate to **Settings > Desktop app**, select "Manage" next to **Extensions** (or **Settings > Extensions** in the older Settings layout), and click "Advanced settings" to access the **Extension Developer** section: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1681607607/ba6e379d2769d190f0970a0adaed/AD_4nXd4aZkqjJFpiXMPF28Pih7HmSJ9pPsnoWAfVgiLdFRFiTkO92YtXteIjvDHaPl7T0tjfpRTBOlyrMbQ_aciCNDgfIuEvV3szmKvt72x5O51DMSClXOYWk1JIRIzylwkj3joXqZcLw?expires=1793653200&signature=fef994a999a65118cf2755c0c108e14121a67300ea8e94ec2f2e78511e3eed4a&req=dSYvF89%2BmodfXvMW1HO4zWbPxUN5Mj4wHn9K2IaIG2JpLME5J77vvXBeHLE5%0A0T9gT49bERsinZ7yJV4%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1681607607/ba6e379d2769d190f0970a0adaed/AD_4nXd4aZkqjJFpiXMPF28Pih7HmSJ9pPsnoWAfVgiLdFRFiTkO92YtXteIjvDHaPl7T0tjfpRTBOlyrMbQ_aciCNDgfIuEvV3szmKvt72x5O51DMSClXOYWk1JIRIzylwkj3joXqZcLw?expires=1793691900&signature=fffb24a2c9f874a443267391e7be9e1751f1d346f483158883953fa089e90b17&req=dSYvF89%2BmodfXvMW1HO4zWbPxUN5Pjw7Hn9K2IaIG2KTF3FGrGwXkJ2DVbHY%0AeizqARg4e8ijO3B2TvE%3D%0A) Click “Install Extension…” and select the .mcpb file. Follow the prompts to install and configure your custom desktop extension. For more in-depth information, please refer to our [desktop extension developer documentation](https://github.com/anthropics/mcpb). diff --git a/content/support/11101966-use-voice-mode.md b/content/support/11101966-use-voice-mode.md index 299dc5890e..9eb70fa769 100644 --- a/content/support/11101966-use-voice-mode.md +++ b/content/support/11101966-use-voice-mode.md @@ -24,7 +24,7 @@ Voice mode transforms how you interact with Claude by: 2. Tap the sound wave symbol in the lower right corner of the chat window to activate voice mode: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2042358620/1bf2311353615c1c494da1312a17/124b93a8-0a9b-4c84-9d1f-ede6ca3498dd?expires=1793653200&signature=79fd22748dd7367f952a9405fa15025a9810f291ba084f6c107dc9fcf76b0e88&req=diAjFMp7lYddWfMW1HO4zZyGr810vlQSF6uXnTLMvvCu9cXd66%2B1jHKQlLHR%0AO68w%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2042358620/1bf2311353615c1c494da1312a17/124b93a8-0a9b-4c84-9d1f-ede6ca3498dd?expires=1793691900&signature=46e242bb67a69b963927d94b018676fdcb10933461651849cbae068abea67cca&req=diAjFMp7lYddWfMW1HO4zZyGr810slYZF6uXnTLMvvB97%2FOu9hxikESB31ad%0AIBPW%0A) 3. Start talking and see your prompt automatically populate in the chat input. @@ -32,7 +32,7 @@ Voice mode transforms how you interact with Claude by: 5. Claude will remain in voice mode until you click the “Stop” button in the lower right corner of the chat window: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2042352060/162f9e61f7fbeb689201dfc1cac1/6a7fafb2-31df-43be-a43f-0059d735e3c4?expires=1793653200&signature=c9cb45bf4639cca7abaeb1a7aaad14796ffa4ba5161aab75678d3a581817fd98&req=diAjFMp7n4FZWfMW1HO4zU6VRP7MTb9rxNdRzYWrfF5F7wwmc%2Bo5Jrwfu%2FBN%0AhLScJfjmvDOWS6bLrnE%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2042352060/162f9e61f7fbeb689201dfc1cac1/6a7fafb2-31df-43be-a43f-0059d735e3c4?expires=1793691900&signature=18026b55350f5076fd6de548ee49c9eea727a3fe004b62992ed000294929186c&req=diAjFMp7n4FZWfMW1HO4zU6VRP7MQb1gxNdRzYWrfF42p6UDEgEYMf1g553A%0AuvOIk0tJ1I78jaNDhGY%3D%0A) ### On mobile (iOS and Android) @@ -40,7 +40,7 @@ Voice mode transforms how you interact with Claude by: 2. Tap the voice mode icon (sound wave symbol next to the microphone icon) in the text input field: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2042359690/68879db64559ecf87991f73ce058/671ff972-9e08-4686-bc04-955dab4b2de3?expires=1793653200&signature=009aac87d559dbf0e9f4c58019e4393c07df40b76af20423af620cd7218bacae&req=diAjFMp7lIdWWfMW1HO4zQTUIPd8ldtMD%2FRXAPlQ7LaYeImGimZOnyzND0Z%2F%0AxaL2%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2042359690/68879db64559ecf87991f73ce058/671ff972-9e08-4686-bc04-955dab4b2de3?expires=1793691900&signature=03984403d1377631f04f87a71d54c2c5e2dde4174ff7d0f189625c0fcc3e88fe&req=diAjFMp7lIdWWfMW1HO4zQTUIPd8mdlHD%2FRXAPlQ7LZqPrEgRPzISSMOhp7O%0Au9Mt%0A) 3. Choose a voice to personalize your experience. @@ -78,7 +78,7 @@ To change the voice later: - **On mobile:** Click the settings button in the bottom left corner while chatting with Claude in voice mode, then tap your preferred voice and pace: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2042352063/25eca25bcfd573ecab30dd53158c/074454a6-fa5a-4c49-8b19-02d434b4ca50?expires=1793653200&signature=05d42d4bb9b5d5d6f1122218134c37a8116cbb569828d28c0fb7a817d212f850&req=diAjFMp7n4FZWvMW1HO4zZ3%2FGWmTZVMIy8OQfYsvK3wgPyY0TxeNamJA9F1M%0A9NOObvUsbi8KGD%2FUZvw%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2042352063/25eca25bcfd573ecab30dd53158c/074454a6-fa5a-4c49-8b19-02d434b4ca50?expires=1793691900&signature=0af9da47efc1d92f91f4fc8fc86991fc171f11751523112461990148fb940892&req=diAjFMp7n4FZWvMW1HO4zZ3%2FGWmTaVEDy8OQfYsvK3x2JCSeaM0itlhvxVNS%0AlnzAR51EXlZCARQTPiI%3D%0A) ## Choose a model diff --git a/content/support/11725453-set-up-the-claude-lti-in-canvas-by-instructure.md b/content/support/11725453-set-up-the-claude-lti-in-canvas-by-instructure.md index 84e07a2a49..ff53a5341a 100644 --- a/content/support/11725453-set-up-the-claude-lti-in-canvas-by-instructure.md +++ b/content/support/11725453-set-up-the-claude-lti-in-canvas-by-instructure.md @@ -44,7 +44,7 @@ This article provides information on how to enable the Claude LTI integration in 5. Click "Install" and refresh the course page. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1611422430/c8e0875feac1f2c7cb033be74fc9/AD_4nXfLU_bui3EXcCjQ0qm70HD97neqjGayKeDer_t76utlci8gZSUjYRhw6ZSOlDdqSEcwXBzd_shAh7pQEJ-8OoE0O21DM5coOgxmO_WD5hlwiuwtS2iYXcTavhIRyQT5zKFWvfn3NA?expires=1793653200&signature=020ba65e89420b457487214b1af6edf86f46a3c44434bf47a1e02715ffb3bdca&req=dSYmF818n4VcWfMW1HO4zTEDa%2BgYnvCDEv2ojHLMylbNYEA%2FWWW%2FiR8RrRMB%0AU6c98yq6ZL7gH4R579s%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1611422430/c8e0875feac1f2c7cb033be74fc9/AD_4nXfLU_bui3EXcCjQ0qm70HD97neqjGayKeDer_t76utlci8gZSUjYRhw6ZSOlDdqSEcwXBzd_shAh7pQEJ-8OoE0O21DM5coOgxmO_WD5hlwiuwtS2iYXcTavhIRyQT5zKFWvfn3NA?expires=1793691900&signature=ab1b3ca15ece5f19b01973efdb9c8fd98abd9742ddfc2158f9d8e429555a236f&req=dSYmF818n4VcWfMW1HO4zTEDa%2BgYkvKIEv2ojHLMylbatIN5qrWDP%2Bw4gy2q%0AzzFDjZqaDZ4JUrQyRrY%3D%0A) ## Turn on the Claude LTI Integration in Claude for Education organization settings diff --git a/content/support/11818288-why-am-i-being-asked-to-verify-my-payment-method.md b/content/support/11818288-why-am-i-being-asked-to-verify-my-payment-method.md index 3b8184f03e..4f8859a9d8 100644 --- a/content/support/11818288-why-am-i-being-asked-to-verify-my-payment-method.md +++ b/content/support/11818288-why-am-i-being-asked-to-verify-my-payment-method.md @@ -2,7 +2,7 @@ If you see the following pop-up when you log in to your Claude account, you’ll need to click the “Verify now” button to verify your payment method: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1631413861/42c3b13d7fc44a11a88ec2b9cd03/AD_4nXeMx8QXpeZZCkfAnVSwx8KZ9n4Vr2rvPdQddyE6ZNxch__F6ZqFs1G4ZmU52Wvb7gRlwRqquTLdw8IQv-gICDyP-MXqiQK_Oe7gX3SKsCKKt2IEpMx4qDeMeeZufMaJfv16XgOH5g?expires=1793653200&signature=98f0d2647ac785d26476813433125d51d48004966c850eb8641012c239d73f73&req=dSYkF81%2FnolZWPMW1HO4zf7%2BjUfo7YPwn6MrEicvimChy%2BCgAsbia5%2F3hSHi%0AB49RLK0x%2Bp6FomfD0lE%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1631413861/42c3b13d7fc44a11a88ec2b9cd03/AD_4nXeMx8QXpeZZCkfAnVSwx8KZ9n4Vr2rvPdQddyE6ZNxch__F6ZqFs1G4ZmU52Wvb7gRlwRqquTLdw8IQv-gICDyP-MXqiQK_Oe7gX3SKsCKKt2IEpMx4qDeMeeZufMaJfv16XgOH5g?expires=1793691900&signature=f55822ae0373228e643d3f7db17fa3435786a4c9d720e4e02432e78fa3cfb222&req=dSYkF81%2FnolZWPMW1HO4zf7%2BjUfo4YH7n6MrEicvimBHTeaWrAZL9BUoVyFz%0ACk87deG68FL%2BSWnLtrI%3D%0A) ## What happens if I click “Remind me later?” diff --git a/content/support/11869629-use-claude-with-android-apps.md b/content/support/11869629-use-claude-with-android-apps.md index f4d9ed7d2d..b3ab2d8494 100644 --- a/content/support/11869629-use-claude-with-android-apps.md +++ b/content/support/11869629-use-claude-with-android-apps.md @@ -222,7 +222,7 @@ Permission requirements vary by feature: For features requiring permissions (like location or calendar access), Claude will request permission contextually with clear explanations of why the access is needed. You’ll be prompted to approve the action with three options: Allow once, Always allow, or Don't allow. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1707351614/ccb910e4b87b1e96ad9a11bbd835/b57b2130-d8d6-4499-89f6-6c12de236fd4?expires=1793653200&signature=0d711f16b6c7cf782947f8506e338c7afb70668e7e9394dd3aa4da70f7e45468&req=dScnEcp7nIdeXfMW1HO4zQe5G1yJ3ib2S5x65TIld%2FCY0r2CFEHGAHpLtrFu%0AdyStSCeM3oi8yp4gq0c%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1707351614/ccb910e4b87b1e96ad9a11bbd835/b57b2130-d8d6-4499-89f6-6c12de236fd4?expires=1793691900&signature=682b504abccd9ce9f7e3ba10bc3e9988cf9b8c2eb07b9a2b24a1a87b8239fe91&req=dScnEcp7nIdeXfMW1HO4zQe5G1yJ0iT9S5x65TIld%2FCE9e8J0vD4JmVGmH34%0A8AwqqPwbeP95ykPRda8%3D%0A) These permissions can be managed at any time in your device settings by going to Settings > Apps > Claude > Permissions. Click into each permission listed under **Allowed** and **Not allowed** to make changes. You can toggle between “Allow only while using the app” or “Ask every time” to change Claude’s access, or remove permissions by choosing “Don’t allow.” Claude will only request permissions if needed for specific features, and you can always choose to decline while still using other capabilities. diff --git a/content/support/12005970-manage-usage-credits-for-team-and-seat-based-enterprise-plans.md b/content/support/12005970-manage-usage-credits-for-team-and-seat-based-enterprise-plans.md index e7da218400..69f0dd8674 100644 --- a/content/support/12005970-manage-usage-credits-for-team-and-seat-based-enterprise-plans.md +++ b/content/support/12005970-manage-usage-credits-for-team-and-seat-based-enterprise-plans.md @@ -70,7 +70,7 @@ After navigating to **[Organization settings > Usage](https://claude.ai/admin-se The **Usage and spend limits** section will show the current limit (if any) or **Unlimited**. Clicking on "Adjust limit" opens a modal where you can either input an amount and click "Set spend limit," or click "Set to unlimited" to remove the organization-wide monthly spend limit. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2149347604/936ac4eb025d3ef1f00c3b8a26b0/image.png?expires=1793653200&signature=a13762000443af8eb5e8fb5945ad9c78d5a726367cbd38f4ad2568c86a785b48&req=diEjH8p6modfXfMW1HO4zQHwgqLRky2k6DwhVVpk1mDhx6MxIWm86k9zuMgC%0AqJjIw9s8VqMNqxlF5Hw%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2149347604/936ac4eb025d3ef1f00c3b8a26b0/image.png?expires=1793691900&signature=e92caac9b1a997f13f5ef39b544f3fc4f0f94f28ca31e63a86f3b0caa013f4ea&req=diEjH8p6modfXfMW1HO4zQHwgqLRny%2Bv6DwhVVpk1mCJxRmJlfBPL5YJu6wX%0AwXK99ldonbjNfEY%2BWLM%3D%0A) Changes to your organization’s overall spend limit go into effect immediately. @@ -78,11 +78,11 @@ Changes to your organization’s overall spend limit go into effect immediately. Owners and Primary Owners on **seat-based Enterprise plans only** can set spend limits that apply to all users within a specific seat tier. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2149351600/c5b979c366ac2738f60ea84e85b3/CleanShot+2026-03-10+at+15_37_41%402x.png?expires=1793653200&signature=5f202a17f788fdfe6fa968469a2081e30a971069de00918b1465841c0eea677b&req=diEjH8p7nIdfWfMW1HO4zYnqMYaSJnOL0wfO62ivdG%2Fx%2BvDIS6fSV9kxuTvg%0AKtRfDtCMhJ%2FPhuHFQL0%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2149351600/c5b979c366ac2738f60ea84e85b3/CleanShot+2026-03-10+at+15_37_41%402x.png?expires=1793691900&signature=eeffc1cf631fb9662e7aecdabdfdb61acd91284c228be3a458a793088e7946a3&req=diEjH8p7nIdfWfMW1HO4zYnqMYaSKnGA0wfO62ivdG8n4gkAfVVyMMvSc2nl%0AfO4iaaKJnp2zOvY%2BIoE%3D%0A) Select the "By group" tab to see **Standard seats** and **Premium seats** groups. Click the "..." icon next to the current limit, then "Edit limit." This opens a modal where you can either select "Set dollar amount" and input an amount, or click "Unlimited" to remove the limit for that seat type. Click "Set limit" to save your changes. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2149362056/44993661ca2db771fe924d0346f6/image.png?expires=1793653200&signature=5a27157e0f8c3342236c5f2d102ba8204fed6a513327d9327ae1be75e67baf0b&req=diEjH8p4n4FaX%2FMW1HO4zRzvvYYNdU5Eq7nEDCGq9G5fSfWiOt%2FuSrfDFJss%0AElWhkXEpG8jo5lehuD0%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2149362056/44993661ca2db771fe924d0346f6/image.png?expires=1793691900&signature=a044fdc921818947d6c70ccab905000547aea561cea39ff5c94033bf8a02d4e7&req=diEjH8p4n4FaX%2FMW1HO4zRzvvYYNeUxPq7nEDCGq9G6uOWX1gaKolFWhcUXL%0AKDI%2BUwf8qEvbpcgtMBI%3D%0A) --- @@ -90,11 +90,11 @@ Select the "By group" tab to see **Standard seats** and **Premium seats** groups Owners and Primary Owners can also set individual monthly spend limits for each member by finding **Spend limits by user** and clicking the "..." button next to the user, then "Edit limit." -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2149370853/db66f5cd03683b9cc119d0dcd6b8/image.png?expires=1793653200&signature=a39e58ca99f0b29cec0484e9ec1b1d3710e5e5d79f129cfaf8ba055ab3286e4e&req=diEjH8p5nYlaWvMW1HO4zaPdGARRUCxEe9HwvwG7ubikZ%2BoqCUN5xHJ3de4n%0AOIYejAK38au%2BHfsnN80%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2149370853/db66f5cd03683b9cc119d0dcd6b8/image.png?expires=1793691900&signature=7686e57db8182923308a6927d21b30b29cc1d0b8fb1877f18c2f7141c1803aff&req=diEjH8p5nYlaWvMW1HO4zaPdGARRXC5Pe9HwvwG7ubhIHtl1UCEEuK9kWx2A%0AiAyqC1NGYBvXyqbqgx0%3D%0A) Enter the amount and click "Set limit." Alternatively, selecting "Set to unlimited" will remove that member's monthly spend limit (they will still be subject to any organization or seat-level spend limits). -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2149374028/97813fe3b515c2e839d8d92abd79/image.png?expires=1793653200&signature=ac4a129545d5c4a6f38b8310c548c16c93e7a6fc7966f0212a07f1fa85a55b55&req=diEjH8p5mYFdUfMW1HO4zevsA%2FSMNuiIw6z2wGSwkbuKqzxie80g1DBAT1a7%0Adgs%2BU%2B7iK8Lo9DCGrTo%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2149374028/97813fe3b515c2e839d8d92abd79/image.png?expires=1793691900&signature=f44be923b803a076d9096a636223a6a5141ab907b41c6b038046f579b4dcdcd3&req=diEjH8p5mYFdUfMW1HO4zevsA%2FSMOuqDw6z2wGSwkbtPTp1q%2Fvm%2FnrcDDAdC%0A3nU%2B92hFotm4BgINdvs%3D%0A) This allows owners fine control over usage credits, so you can set limits for different members based on their roles or individual needs. Once a user reaches their defined spend limit, this will automatically pause their usage credits until the end of the month. They will need to wait for their usage limits to reset before using Claude again. diff --git a/content/support/12012173-get-started-with-claude-in-chrome.md b/content/support/12012173-get-started-with-claude-in-chrome.md index 91e6a26a33..5f7d80e548 100644 --- a/content/support/12012173-get-started-with-claude-in-chrome.md +++ b/content/support/12012173-get-started-with-claude-in-chrome.md @@ -40,7 +40,7 @@ Follow these steps to connect Claude in Chrome in your desktop app: 4. Toggle the connector on, then download and install the extension if you haven’t already. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2604933811/ae37c41fc808dbdf48d135338334/6cc9ba4b-9d31-43a2-ab80-8048b5f9d791?expires=1793653200&signature=6c86a9f82f51058d5b1f95d039ec2d0abb743fff9a3d279d73273e5efe672e94&req=diYnEsB9noleWPMW1HO4zUOPbf%2FAk%2BGPnt%2F2nPMwUPif%2FQgEiOSgjiheR0Tk%0ADr0uXWl6p3pyVSCkDJE%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2604933811/ae37c41fc808dbdf48d135338334/6cc9ba4b-9d31-43a2-ab80-8048b5f9d791?expires=1793691900&signature=ccd8fa8e3143b0763a064adc8ba46c5daf09e8b10a6a7f96064cb7b275267f6f&req=diYnEsB9noleWPMW1HO4zUOPbf%2FAn%2BOEnt%2F2nPMwUPgmrHWRtXemz7hb%2BXlz%0Ahdjlx4vpY%2Fedrwu00T0%3D%0A) Completing these steps will add Claude in Chrome to the “Connectors” drop-down on your chats with Claude. This is disabled by default, so you’ll need to enable it manually for each conversation. diff --git a/content/support/12111783-create-and-edit-files-with-claude.md b/content/support/12111783-create-and-edit-files-with-claude.md index fb52cc9fae..3077657319 100644 --- a/content/support/12111783-create-and-edit-files-with-claude.md +++ b/content/support/12111783-create-and-edit-files-with-claude.md @@ -48,7 +48,7 @@ These capabilities make it easy to produce professional documents by simply chat To give Claude access to external data sources, toggle **Allow network egress** on: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2054774005/25bcfffba6c249cd128d6c3f6d52/CleanShot+2026-02-11+at+16_34_47%402x.png?expires=1793653200&signature=d08c2f1afc4c0c092e0c5681002c420491637086b682ef3e29be9ec88d29529a&req=diAiEs55mYFfXPMW1HO4zYFJyg5DCZrMPQVowIiib2nXVG8TKrYCMj8Dfshi%0ABLkLB9QPf7tmcivMk88%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2054774005/25bcfffba6c249cd128d6c3f6d52/CleanShot+2026-02-11+at+16_34_47%402x.png?expires=1793691900&signature=cdb8c7f5bab6dcdf0d075315c7a10981dd7c802de13dfba8438b40f03f38db70&req=diAiEs55mYFfXPMW1HO4zYFJyg5DBZjHPQVowIiib2lwsLiQGr90kfwC70mJ%0AZB5c%2FUl5e6z%2BodOJqwU%3D%0A) ### Enabling on Claude Mobile @@ -66,11 +66,11 @@ Team and Enterprise organization owners can control network access settings in * - **Allow network egress to package managers and specific domains:** Claude can access package managers plus additional domains you specify. Add domains individually to whitelist specific resources your organization needs: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1789945362/ad72504d5429960f369b8b91b43c/86f06c0e-6eaa-4574-a4cb-2c38b273613a?expires=1793653200&signature=96b94fc64969cfde2e0fd2713441972682b5823bb2c504d96c4594a618e45bed&req=dScvH8B6mIJZW%2FMW1HO4zXJcB25FkCpJpMW6Iph6YZf2WKgpoC2IgOR3Jyvh%0AYsb4U%2Btbpmo%2BXcQ1bZc%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1789945362/ad72504d5429960f369b8b91b43c/86f06c0e-6eaa-4574-a4cb-2c38b273613a?expires=1793691900&signature=74c04a7845386c48ab0225a55215129edc3da77de6aff6524591a8f3e7e93977&req=dScvH8B6mIJZW%2FMW1HO4zXJcB25FnChCpMW6Iph6YZfNNUM7eVLDWMnBnpa5%0Am4DahUTNryMZj1y4dbo%3D%0A) **All domains:** Claude has full internet access except for domains on Anthropic's legal blocklist. While this provides maximum flexibility for file creation and analysis tasks, it’s also the riskiest option. Please review the **[security considerations below](#h_0ee9d698a1)** before enabling “All domains”: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1789945361/e3188cb8edb9ca7c303615da6378/f1c99a7d-5956-48d5-9ec7-b7ae6c8c3d28?expires=1793653200&signature=ae617935a4cd55421e08ea2d234caf688b5880e8e6f8d61b4ed137b893bb4670&req=dScvH8B6mIJZWPMW1HO4zdnseReU6zygqgKIA6CM1tr%2FfjwrmCslSqE99ORR%0AKg%2BDk7N3Ue0l%2FloIWgM%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1789945361/e3188cb8edb9ca7c303615da6378/f1c99a7d-5956-48d5-9ec7-b7ae6c8c3d28?expires=1793691900&signature=d491d01f0944198fd0cd4d3cc3852946badbe8824b9c89005a61478f7c755522&req=dScvH8B6mIJZWPMW1HO4zdnseReU5z6rqgKIA6CM1tq%2FZYz05QzRtG7Css4Q%0AC5wpUK9NcpITxQzO2Dk%3D%0A) --- diff --git a/content/support/12157520-claude-code-usage-analytics.md b/content/support/12157520-claude-code-usage-analytics.md index ff3228db08..284ba3fd03 100644 --- a/content/support/12157520-claude-code-usage-analytics.md +++ b/content/support/12157520-claude-code-usage-analytics.md @@ -46,7 +46,7 @@ The **Usage** tab displays the following metrics for your organization. Data on - **Top commands**: The Claude Code commands used most often across your organization. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1717579277/46c512f4b3ed05c359cecd78ed5c/e0ce2c19-39e2-411f-9a1f-cb1d46439a42?expires=1793653200&signature=fce095480c5089358deed809581a65715213a9e892671d22b0be01a55cac117e&req=dScmEcx5lINYXvMW1HO4zfiEPqVWinrMCX9h5MbdDjOZPyCcvDIeMG1Un0lZ%0AgCLXHZi01bhnZF1M1OA%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1717579277/46c512f4b3ed05c359cecd78ed5c/e0ce2c19-39e2-411f-9a1f-cb1d46439a42?expires=1793691900&signature=4989d0f9850b121d4596dc7fa19e145a01de5c32ee67e33dc30e8146e08d5a99&req=dScmEcx5lINYXvMW1HO4zfiEPqVWhnjHCX9h5MbdDjPvZAGxBGSCE%2BdY5lIP%0AZm%2BlN6in%2F%2Fu7w8ZmLh4%3D%0A) ### User-level metrics diff --git a/content/support/12260368-use-incognito-chats.md b/content/support/12260368-use-incognito-chats.md index 505dbb6dba..151a43c82b 100644 --- a/content/support/12260368-use-incognito-chats.md +++ b/content/support/12260368-use-incognito-chats.md @@ -34,7 +34,7 @@ These differ from regular chats in several ways: When starting a new chat with Claude outside of a project, you'll see a ghost icon in the upper right corner of your screen: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1719768744/c7a2fa56cf284e48472f3b9c4dbf/030563f8-9f97-4891-a749-9ae95968a063?expires=1793653200&signature=8dbe3504a0c25d62eebb6f98260ea0e4ba85bd0f27a3ae8e1590abd74d0cde99&req=dScmH854lYZbXfMW1HO4zeUcugG7a%2BaJDCAt3Cx%2FSO2uxPV69Lv8b1kr6QFx%0Ansz3K7eIYjgpWF4X1d4%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1719768744/c7a2fa56cf284e48472f3b9c4dbf/030563f8-9f97-4891-a749-9ae95968a063?expires=1793691900&signature=0ece6efe0812efb7b561c402db86db4d3d270a1566a82b653685d98a6a256580&req=dScmH854lYZbXfMW1HO4zeUcugG7Z%2BSCDCAt3Cx%2FSO2em6YgwzxRizyyvdYy%0As9g9OzLq5xuUR%2BVOLt4%3D%0A) 1. Click the ghost icon to enable incognito mode. diff --git a/content/support/12293051-use-claude-in-xcode.md b/content/support/12293051-use-claude-in-xcode.md index 947432f13a..b615035724 100644 --- a/content/support/12293051-use-claude-in-xcode.md +++ b/content/support/12293051-use-claude-in-xcode.md @@ -34,7 +34,7 @@ To start using Claude in Xcode: 3. Log in with your Claude account. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1727371585/b18ca03a6357c52d12d10386f28e/dab2dcb2-f670-4173-b77d-38767a34cec1?expires=1793653200&signature=47dee797363f26bcb190fab97c5b62e801e2e8565d0cfd99263de04c0efec45f&req=dSclEcp5nIRXXPMW1HO4zUAXIs8EV6vWFalhp3bugHL2ft6kLpMkdUjig3qF%0AO6BSmlR5XhDex8f310g%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1727371585/b18ca03a6357c52d12d10386f28e/dab2dcb2-f670-4173-b77d-38767a34cec1?expires=1793691900&signature=40db781b716d4f02c2f0e2340667a4ecce55dc1959cbf5c8b0b0ae3211678140&req=dSclEcp5nIRXXPMW1HO4zUAXIs8EW6ndFalhp3bugHJmAQgDiMbXU4BiVxnm%0AiHGtJAbpOqy42QHJdUc%3D%0A) ## Usage limits diff --git a/content/support/12512180-use-skills-in-claude.md b/content/support/12512180-use-skills-in-claude.md index d5bda75770..626a596e1a 100644 --- a/content/support/12512180-use-skills-in-claude.md +++ b/content/support/12512180-use-skills-in-claude.md @@ -202,7 +202,7 @@ To remove a custom skill you've uploaded: 4. To delete the custom skill entirely, click the "..." button next to the toggle, then select "Delete": - ![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2105391273/8359cbf8be20dce0f1cd3fd40e6f/CleanShot-2B2026-02-25-2Bat-2B15_50_16.png?expires=1793653200&signature=36ef737df14123d694b6e66ba13c76885323711aac82ac171801b20e61e91425&req=diEnE8p3nINYWvMW1HO4zSOgDigux%2BWvH%2BdCnFXB0uhH36MrxBHwnzUFXcFE%0A8DAO%0A) + ![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2105391273/8359cbf8be20dce0f1cd3fd40e6f/CleanShot-2B2026-02-25-2Bat-2B15_50_16.png?expires=1793691900&signature=66440146e371de4e556f1dfea8dfd3aa1af772d370c35a2e5cd5d0ed4cff8221&req=diEnE8p3nINYWvMW1HO4zSOgDiguy%2BekH%2BdCnFXB0ujggv%2Fv5oyhdyPISwm%2B%0An7vp%0A) 5. Click "Delete" in the confirmation prompt. diff --git a/content/support/12592343-enabling-and-using-the-desktop-extension-allowlist.md b/content/support/12592343-enabling-and-using-the-desktop-extension-allowlist.md index db7fc00a17..bf808662ac 100644 --- a/content/support/12592343-enabling-and-using-the-desktop-extension-allowlist.md +++ b/content/support/12592343-enabling-and-using-the-desktop-extension-allowlist.md @@ -20,11 +20,11 @@ The desktop extension allowlist is disabled by default, so an organization Owner 4. Switch to the "Desktop" tab: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1781755172/63c92550571842577ad435860ec5/6f5cc4e1-ff7d-48de-863a-c4e6184d4605?expires=1793653200&signature=fe05a3b40f744047dcdf1cde5dbb098e0200cec55e66707d519e737c4e2b892d&req=dScvF857mIBYW%2FMW1HO4zQ9pXEkM%2BnPZ0ugSQm1MFW8BKjIarkorFjy6x5I5%0ADuGK%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1781755172/63c92550571842577ad435860ec5/6f5cc4e1-ff7d-48de-863a-c4e6184d4605?expires=1793691900&signature=8f3327bc47fea8d0fb290816c0f8e549c18f52597c859dd655b8a3bdc5f34c42&req=dScvF857mIBYW%2FMW1HO4zQ9pXEkM9nHS0ugSQm1MFW8iwzKOFBnO%2FAAFzZnD%0AN%2Faf%0A) 5. Toggle **Allowlist** on: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1781755578/a6bafff5f084dc86ae463703fd3d/6cf0ee18-4e71-4129-98e8-cc08174e3c3a?expires=1793653200&signature=549de49fef330bc2e426408a351f4cb3cc057fc8c5862649d1f5182d65bf5091&req=dScvF857mIRYUfMW1HO4zaj0BXItTKQGTAorLxpdoc%2BiYoaqfSBOBU1gf%2F2A%0AkXGE%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1781755578/a6bafff5f084dc86ae463703fd3d/6cf0ee18-4e71-4129-98e8-cc08174e3c3a?expires=1793691900&signature=595258fbace4881aefea8d6192bbfc7e7fa4937194bdfcc950261df4e15e927e&req=dScvF857mIRYUfMW1HO4zaj0BXItQKYNTAorLxpdoc%2BOzd23l12ViQeWNuA0%0A1PkU%0A) ## What happens after enabling the allowlist? @@ -42,7 +42,7 @@ Consider completing the allowlist setup during off-hours to minimize disruption **Important:** The allowlist requires Claude Desktop version 0.13.91 or higher, so users should update the desktop app by clicking “Claude”, then either “Check for updates” or “Restart to update to Claude 0.13.91”: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1781756960/ad18af50c83d35f2673656c23e00/a7ee450f-0c7d-42d6-a75f-fb1bc088cb52?expires=1793653200&signature=48c6471a9fdc65beaaef366a72a465fd5cf491b90f6a961d201137544037652a&req=dScvF857m4hZWfMW1HO4zYUJqICsDzHpCEDZ5AdBjIZmG8krYj9csbz6Hxzz%0AiAEfAhL77OWq%2B8abOss%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1781756960/ad18af50c83d35f2673656c23e00/a7ee450f-0c7d-42d6-a75f-fb1bc088cb52?expires=1793691900&signature=e380bbd28b4982a91daa0911db08f26b9488ad328c644f8a185a3011139b4712&req=dScvF857m4hZWfMW1HO4zYUJqICsAzPiCEDZ5AdBjIbKdQHZz%2B%2FpWROXDBPW%0AQ8xXwkYh9bCIeziEdfw%3D%0A) ## Managing allowed extensions @@ -60,7 +60,7 @@ After enabling the allowlist, you can choose which extensions to allow: If you want to remove an extension from the allowlist, click the “...” button and “Remove from allowlist.” -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1781751250/6558c0f59aea7976bd44b0213d76/e750f02b-cd0d-437e-a83f-9ac362cdf456?expires=1793653200&signature=76f00ff5fcefa66250a6a9895d6bf5239dc135b167e1fee85cf663ce5037eb00&req=dScvF857nINaWfMW1HO4zTrxBKsv%2BlSXqXridZhfx1Kgv%2F2gQntNA9l0cEgb%0ALS2iYhrabgWFr4QyOKg%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1781751250/6558c0f59aea7976bd44b0213d76/e750f02b-cd0d-437e-a83f-9ac362cdf456?expires=1793691900&signature=8e81464f2881541094da9c9a6316d1dd89c8a388a7b837a73a1b4c9484a59582&req=dScvF857nINaWfMW1HO4zTrxBKsv9lacqXridZhfx1K6bn9u09HP3tNvqTpq%0As5dO4bqYszpvwIQDC0o%3D%0A) ## Uploading custom extensions diff --git a/content/support/12618689-use-claude-code-in-the-cloud.md b/content/support/12618689-use-claude-code-in-the-cloud.md index aeda2dda68..b5d3868131 100644 --- a/content/support/12618689-use-claude-code-in-the-cloud.md +++ b/content/support/12618689-use-claude-code-in-the-cloud.md @@ -10,7 +10,7 @@ This feature works with repositories you may not have on your local machine. You Cloud sessions enable asynchronous development workflows. In a local session in your terminal or editor, you typically work synchronously: you make a request, wait for Claude to respond, review the changes, then make another request. Synchronous work like this gives you fine-grained control but requires your attention throughout the process. A cloud session handles this differently: you can assign a larger task, let Claude work independently, and return later to review the completed work. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1786446157/07ec74cd46317f8278083a317841/6448f3ee-c6df-4417-8a13-90d8c2ca3d55?expires=1793653200&signature=b0d6c974725187a2f29aa3f3e0b5da95a4cbf0a8055e0026bc32550801dd709b&req=dScvEM16m4BaXvMW1HO4zR8%2BAVCGR5507XrRA1YwWGsQ8CgL9Z5WBx6woLBu%0AlRnTsuPLz8oxr%2BzjnTs%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1786446157/07ec74cd46317f8278083a317841/6448f3ee-c6df-4417-8a13-90d8c2ca3d55?expires=1793691900&signature=232bcf1e76aea8353462227633c42c63bb53d07801b45e8b9f1a61b67e0f06a6&req=dScvEM16m4BaXvMW1HO4zR8%2BAVCGS5x%2F7XrRA1YwWGsI8m%2Fx4mm3zfoVktDp%0A0ng1LChnrIio6c3hh%2Bs%3D%0A) You can also run multiple tasks in parallel. Since each task runs in its own isolated environment, you can have Claude working on several different issues or repositories simultaneously. Each task proceeds independently and creates its own pull request when complete. More than one task can work on the same repository at the same time. @@ -20,13 +20,13 @@ You can also run multiple tasks in parallel. Since each task runs in its own iso When you start a cloud session, Claude Code creates an isolated virtual machine for your work. Your GitHub repository is cloned into this environment, which comes pre-configured with common development tools and language ecosystems. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1786446158/c092f1383826cb871493f74169d4/97b7cb98-5da2-438e-a920-e170b8b9790e?expires=1793653200&signature=d3cd1d648f4f57be9688d0e7a32b6c70d84d3e793d5141b1c536b03d368ebad3&req=dScvEM16m4BaUfMW1HO4zcR0rJUyiurC7DtpMiX%2FBYn4gQYdAcNbvh7L4%2FHY%0Ag3b8g98Dhv6mpHgD4JU%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1786446158/c092f1383826cb871493f74169d4/97b7cb98-5da2-438e-a920-e170b8b9790e?expires=1793691900&signature=186c3815fc8cee206a3aa4679b9cff3191da52abf533318935dd2c2e4eeccb8d&req=dScvEM16m4BaUfMW1HO4zcR0rJUyhujJ7DtpMiX%2FBYlrOM0LUQx6HTE96jAC%0AGxFW7bdDeFEsE3LosPA%3D%0A) Claude prepares the environment by running any setup commands you've defined in your repository's configuration. This includes installing dependencies, setting up databases, or running other initialization steps your project needs. If your task requires network access, maybe to install packages or fetch data, you can configure the level of internet access the environment has. Once the environment is ready, Claude begins working on your task. Claude reads your code, makes changes, writes tests, and runs commands to verify the work. You can monitor progress and provide guidance through the web interface if needed. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1786446156/83ecf0a5b98eddc9ffc9694c50f7/353589ce-b678-441d-8909-71b45fa2d065?expires=1793653200&signature=37387ab7be1b49f198533ba2e24175fb29578d51a75933a3d01e0c48ba72a9bc&req=dScvEM16m4BaX%2FMW1HO4zVbcTWCF5sfMUQl3YqgIJdbxlAJH292zUxfiO7xG%0ARXv5qB6e0y%2BWI97Rouw%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1786446156/83ecf0a5b98eddc9ffc9694c50f7/353589ce-b678-441d-8909-71b45fa2d065?expires=1793691900&signature=8d2ade13add2f1b7fbe34daccfa0ec2a90f1d7bcfbee0a4ea4e412fe22e8c361&req=dScvEM16m4BaX%2FMW1HO4zVbcTWCF6sXHUQl3YqgIJdbI9howLshodQVD%2Bgei%0AbvAYsXyCQ24%2Bjo4lfZI%3D%0A) When Claude completes the task, it pushes the changes to a new branch in your GitHub repository. You receive a notification and can review the changes, then create a pull request directly from the interface. The pull request includes all of Claude's work, ready for your review and any additional changes you want to make. diff --git a/content/support/12883420-view-usage-analytics-for-team-and-enterprise-plans.md b/content/support/12883420-view-usage-analytics-for-team-and-enterprise-plans.md index 2583bb90f3..4ba3381d60 100644 --- a/content/support/12883420-view-usage-analytics-for-team-and-enterprise-plans.md +++ b/content/support/12883420-view-usage-analytics-for-team-and-enterprise-plans.md @@ -22,7 +22,7 @@ This page includes the following analytics: - Sessions in Cowork -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515895966/9f231a620f47d49e0ee648152189/848c1787-4eaa-4809-8fd2-1dbe2722560f?expires=1793653200&signature=fae6a38ee51e8b858233af24512b11883a773b7f2b9c6286b110c008a865bcf4&req=diUmE8F3mIhZX%2FMW1HO4zZL6wKV0noZzExEG4dCAGDaSAtyuV3uhNL8Zj1OT%0Av3H4fcJRNZ6eQSUw%2Fao%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515895966/9f231a620f47d49e0ee648152189/848c1787-4eaa-4809-8fd2-1dbe2722560f?expires=1793691900&signature=08380bd418b92098bb85c6cc1eb9de1247035ab194c49be49f31940138cde824&req=diUmE8F3mIhZX%2FMW1HO4zZL6wKV0koR4ExEG4dCAGDaqMRWdO4UbgHeAP0Ig%0A4aVfyqjtd8sg8vlbuvU%3D%0A) ### Who’s using Claude? @@ -34,7 +34,7 @@ This page includes the following analytics: Use the dropdown on the **Active members and assigned seats** chart to filter by product, including Claude Design. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515896351/4d955858e6662c37489cc1470871/457cf159-8c2a-4403-ba22-cb92cb47e459?expires=1793653200&signature=4f8f62d899a882a045d706eac8079d68b4729dfde7720d008c1d04b5429f4a58&req=diUmE8F3m4JaWPMW1HO4zYEqezSvR5OtYqPRsgaNdTwfec%2Blao3ouTzssBpM%0AnpzgaxJpp6wP8xIfkbc%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515896351/4d955858e6662c37489cc1470871/457cf159-8c2a-4403-ba22-cb92cb47e459?expires=1793691900&signature=03bb6d287da2b3abaf08374c27060c2ebb1ad9acc348580e75fcccee7a08937f&req=diUmE8F3m4JaWPMW1HO4zYEqezSvS5GmYqPRsgaNdTw%2FG2RCtQVxthJgdTXz%0AjiqPRvcMLc13Um7pQPY%3D%0A) ### How are they using Claude? @@ -48,9 +48,9 @@ Use the dropdown on the **Active members and assigned seats** chart to filter by - How agentic is their work? (beta) -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2583875713/e3cb3c329f3b643cb9a3809876b3/image.png?expires=1793653200&signature=c65de2ddc622ba356df6eee99ec37be59f4511f53f70f56bfd496f41fde9638a&req=diUvFcF5mIZeWvMW1HO4zciS3Kvvn71pDFD6TO7tG4g9hikfVEX3AB7xBfqn%0Af5daD1dC%2FhKYtD%2FljsA%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2583875713/e3cb3c329f3b643cb9a3809876b3/image.png?expires=1793691900&signature=6637565616e4e36f9f454de29db1b486d95cd4a83e14c3aa410b1c140cf11a47&req=diUvFcF5mIZeWvMW1HO4zciS3Kvvk79iDFD6TO7tG4guI7zlomXAwZYBSb63%0AJWu9Z8T2GtuBwCNq%2BRg%3D%0A) -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515896563/abf008596ce5501297a609696362/fce5423c-4769-4b73-9a0a-c50f6407ebea?expires=1793653200&signature=9d8d7da5ade9fe772278068f16a7bad561d2b3de80c9315130457860f154f41e&req=diUmE8F3m4RZWvMW1HO4zR%2BID4RouPT1LS3kobW3ZgT4O9lm%2FZoz%2FwXCkWuY%0AlywwOiWkvmIczIZeKMs%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515896563/abf008596ce5501297a609696362/fce5423c-4769-4b73-9a0a-c50f6407ebea?expires=1793691900&signature=ceda368518ce9f95b33c13bc2fafc6f53f8b94b96e2c9b0ea097adcec4fc8ed5&req=diUmE8F3m4RZWvMW1HO4zR%2BID4RotPb%2BLS3kobW3ZgQFAc8dpcZRYRPia6uh%0AbanAASML%2BDC%2FpRHlXzc%3D%0A) ### What are the results? @@ -66,7 +66,7 @@ Use the dropdown on the **Active members and assigned seats** chart to filter by - Estimated time saved -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515896943/dd415f03afe56ca38308ef987f86/189e8ebc-5594-4f4b-bd84-e3c11c824d5b?expires=1793653200&signature=396361f2b5888102753adc2af4fe0e1ce8ce73c1a00831105790acd975ebab49&req=diUmE8F3m4hbWvMW1HO4zfJThSc5rN9EiovaLYNN7Rlf0ydROdkijbSHDUj1%0AfCZ9HohjHPwRe2pfWIY%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515896943/dd415f03afe56ca38308ef987f86/189e8ebc-5594-4f4b-bd84-e3c11c824d5b?expires=1793691900&signature=8ebd78cbb98e87777211f4851108c571dcef8f9b43669a6b5241cb5fba1dea94&req=diUmE8F3m4hbWvMW1HO4zfJThSc5oN1PiovaLYNN7RnhkqeqyTPq8tDccsi4%0ArL9N2jp6BvW1jE%2BBTiM%3D%0A) ### How much is Claude costing? @@ -82,9 +82,9 @@ This section includes the following analytics: - Spend by model (month-to-date, quarter-to-date, year-to-date, 1 year) -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515896942/b403f2d216fc40b5195911020b8e/446b99f1-3187-4b79-b2be-9f17b1632ff8?expires=1793653200&signature=64103592c922a7660c9df2ee2093d20e197997f463d89607b973d2573615814b&req=diUmE8F3m4hbW%2FMW1HO4zYE%2BQt0E6TLfWbBLGZ4vBJXreRPuvGdnhk%2BDBfjm%0AMeHn2s9kN6rXW1Tvyc0%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515896942/b403f2d216fc40b5195911020b8e/446b99f1-3187-4b79-b2be-9f17b1632ff8?expires=1793691900&signature=71e9b3a3bd4b3b7930068469ea5051bb68104a2ebedc9c1b25e22b7cf9298042&req=diUmE8F3m4hbW%2FMW1HO4zYE%2BQt0E5TDUWbBLGZ4vBJWZv2Fbvi4U6kS9Eafm%0ArgJbm%2FCz0IPnoXInwqw%3D%0A) -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515896941/2239ce38639df339b24d5af1cb50/f829bc2a-ee52-4135-9b13-09ef1b7d66d6?expires=1793653200&signature=b613ba2e3e082cdab0fd349d4919771e03996ad7deb099f6b29e8a231cac0db9&req=diUmE8F3m4hbWPMW1HO4zTz0N%2BkEIspSC%2BtvTPa1I7EipaDM5kRGgAu4wfIu%0AYQL5F5Ec9mF30VUClrg%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515896941/2239ce38639df339b24d5af1cb50/f829bc2a-ee52-4135-9b13-09ef1b7d66d6?expires=1793691900&signature=4039f0357f0864537c9fae25e71d919d179786943c936e983efa6be96df78a9a&req=diUmE8F3m4hbWPMW1HO4zTz0N%2BkELshZC%2BtvTPa1I7GF2GkfKtvS2AKY4STx%0A7p06y85znxYCAjqbk00%3D%0A) **Note:** For a view of how spend limits are affecting your organization, you can also check the **Blocked by a spend limit** section at the top of **[Organization settings > Usage](https://claude.ai/admin-settings/usage)**. **Blocked by a spend limit** is built for usage-based Enterprise plans. Orgs without usage-based seats only see how many members are blocked or near their limit right now. Learn more about **[monitoring usage and spend on Enterprise plans](https://support.claude.com/en/articles/11526368-how-am-i-billed-for-my-enterprise-plan#h_ae17ec8236)**. @@ -162,7 +162,7 @@ Navigate to **[Analytics > Claude Chat](https://claude.ai/analytics/usage)** to - Top members by chats -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515898793/405db0c492da11886c28a2b82731/71a55afc-1cef-4c50-b7e1-86775cb9a168?expires=1793653200&signature=ba438a49b562459bd4ede9bab0f31aebaed4138eaffb419611cac76d3a3cd48c&req=diUmE8F3lYZWWvMW1HO4zbhc8P6aZOcjTcfMEUwBBiXVEAN0VAc7jjfWnsKs%0AtUzOE0JQIBJWV%2F8glok%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515898793/405db0c492da11886c28a2b82731/71a55afc-1cef-4c50-b7e1-86775cb9a168?expires=1793691900&signature=ee737a9db628a72f5a399a97de37a8906f7cabfb0ae15e280ab0f5d21b157c17&req=diUmE8F3lYZWWvMW1HO4zbhc8P6aaOUoTcfMEUwBBiUzwKL%2BmZ%2F%2BP4BWRHdd%0A9uCJ9jJzOVIE6TRdBKM%3D%0A) ### Projects @@ -174,7 +174,7 @@ Navigate to **[Analytics > Claude Chat](https://claude.ai/analytics/usage)** to - Top members by project usage -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515899610/91d93108f0767e795fb9e488e882/71607d6d-dff1-4a13-a445-aa1d79850eed?expires=1793653200&signature=f1ea6ec5e1ae00443419d086a3c60ca39781494235692d917f2b64691eda77d5&req=diUmE8F3lIdeWfMW1HO4zWhGoD%2BfniCgExu5cYiHHN%2BRNqHXdMynxTuy1waK%0AY4bMVkL6in63e5jSAE8%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515899610/91d93108f0767e795fb9e488e882/71607d6d-dff1-4a13-a445-aa1d79850eed?expires=1793691900&signature=5217f18b89c941e8fcbe597aa21717569caba75cf0b4138f67207f3f90ecf49d&req=diUmE8F3lIdeWfMW1HO4zWhGoD%2BfkiKrExu5cYiHHN8%2FMe2cbpZHNFmuZyYu%0AGGNlRs%2BaAkG8JZO%2FK%2BE%3D%0A) ### Artifacts @@ -184,7 +184,7 @@ Navigate to **[Analytics > Claude Chat](https://claude.ai/analytics/usage)** to - Top 10 users by artifacts generated (month-to-date, quarter-to-date, year-to-date, 1 year) -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515899838/33d737f2357d6e485704669962ae/43faadc3-47da-4a93-bbb7-47a7983e7441?expires=1793653200&signature=73a45ebf45d9b573179f8dc7516adfb8711bfe5b86645081542fd4cb6a9fbb5c&req=diUmE8F3lIlcUfMW1HO4zcSk47nUe%2B3CjHDogqK0V%2BzZAYa6%2Fb2xYYnjxypa%0A5QKL3OMFF%2BbVlw3QdHg%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515899838/33d737f2357d6e485704669962ae/43faadc3-47da-4a93-bbb7-47a7983e7441?expires=1793691900&signature=9442494e8bcb34c692c5596cc455186a038cd18b51ccee3bc37f1f57d212abaf&req=diUmE8F3lIlcUfMW1HO4zcSk47nUd%2B%2FJjHDogqK0V%2BxSdPfI%2BCZxiO84Zw8f%0AxcmGXuXdgDOaQkkA5oU%3D%0A) --- @@ -280,7 +280,7 @@ Navigate to **[Analytics > Cowork](https://claude.ai/analytics/cowork)** to view - Daily, weekly, and monthly active Cowork users -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515901489/8005693d55b7fefbfe9233258d39/106c22a0-3f47-47a6-abbd-4788dd70f218?expires=1793653200&signature=3fe2ace94c4eaccaebb3f4d67ef75a069940e8f95410c1c9fe1d38a9ebc41d18&req=diUmE8B%2BnIVXUPMW1HO4zX7WE4u3WEKqFSi1Z3SzLLtw2kkqb7%2BgOnEU3IHm%0AzAQm3GCRTmdtte9hw%2Fg%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2515901489/8005693d55b7fefbfe9233258d39/106c22a0-3f47-47a6-abbd-4788dd70f218?expires=1793691900&signature=27e2aaa7b90c237d78f5d217a318c535f027b8fccdff2a93d448d142e90aab41&req=diUmE8B%2BnIVXUPMW1HO4zX7WE4u3VEChFSi1Z3SzLLvI2yKD%2FujYNa9fuySO%0A77uf7NeNyxtbPQ4U3pY%3D%0A) **Note:** Cowork analytics are available alongside Chat and Claude Code data in the **[Analytics API](https://platform.claude.com/docs/en/manage-claude/analytics-api)**. @@ -296,7 +296,7 @@ Navigate to **[Analytics > Surveys](https://claude.ai/analytics/surveys)** to as On Enterprise plans with usage-based billing, when your admin turns on individual usage analytics, any member of the organization can see their own usage broken down by product, model, and skill, along with where they stand against any spend limits set for them. Individual usage analytics are available in **[Settings > Usage](https://claude.ai/settings/usage)**. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2533906328/1f5cd0a57def40676410f8f379b4/member-usage-30d-model.png?expires=1793653200&signature=4fd077d53c3a7c619a7e15fd3dd7e5af7571a9929e05240ac28afa86c6fc84b4&req=diUkFcB%2Bm4JdUfMW1HO4zfveBqzDeejYWGUKUw6QS4%2FoVmLbcF4G8frz9qqC%0APhnyTO%2FPIWaRIznel%2Fc%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2533906328/1f5cd0a57def40676410f8f379b4/member-usage-30d-model.png?expires=1793691900&signature=2cb8e8833f99da2c67f52e5ea7e523ffdacfbd25b756bc8afe266c1ea3df7470&req=diUkFcB%2Bm4JdUfMW1HO4zfveBqzDderTWGUKUw6QS4%2BKsqlsOkVkmU8hD5dc%0Ai3pJTwA3T%2Bz3klioF5g%3D%0A) --- diff --git a/content/support/12902446-claude-in-chrome-permissions-guide.md b/content/support/12902446-claude-in-chrome-permissions-guide.md index 7b8d0381ed..48687b5a12 100644 --- a/content/support/12902446-claude-in-chrome-permissions-guide.md +++ b/content/support/12902446-claude-in-chrome-permissions-guide.md @@ -30,7 +30,7 @@ In "Manually approve," Claude checks with you before it acts. What that looks li Claude creates a plan from your prompt, which you can approve before Claude starts. The plan specifies which websites you're allowing Claude to access, as well as the approach it will follow: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1843320727/8d1c859ae9b8e0cdb536d024bf40/9bc3d239-8eb6-4bae-a032-a236f88ee606?expires=1793653200&signature=15e796a65bbbf7334bce1053841b7c19200fe61feae3f1e35484a2978f9fe7b0&req=dSgjFcp8nYZdXvMW1HO4zYqyZMFL%2BYG1gN0ADj5oqFBGiRJFWhJKsna2cP5b%0AwtDKZnrTFwrxqneXeKA%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1843320727/8d1c859ae9b8e0cdb536d024bf40/9bc3d239-8eb6-4bae-a032-a236f88ee606?expires=1793691900&signature=a18455b9e2f51ae8a88b0af5b028a1819cb0f4da337c7325237ec1b39cf830be&req=dSgjFcp8nYZdXvMW1HO4zYqyZMFL9YO%2BgN0ADj5oqFCr2WetVhZzn1gvEJU4%0AZn6es9tF5ZXqjKlLDBc%3D%0A) Note that Claude will only use the websites listed in the plan, so you’ll need to manually approve any additional access requests. @@ -64,7 +64,7 @@ When you choose "Skip all approvals," Claude doesn't pause to ask, and nothing c There are some websites on which Claude requires approval for every action. If you navigate to one of these sites, a **New permissions required** prompt will appear in the extension side panel, Claude Cowork, or Claude Code where Claude will ask for permission before accessing the page or taking any action. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2604970825/d7b961271be69e7541b406df1efd/d845324e-6b4a-4f54-83b9-0bea86ec09c6?expires=1793653200&signature=79d29ae1a1eb30cc518d658fca0f90a50bc5d3438a3c24c5c2158c9c5cde2fc2&req=diYnEsB5nYldXPMW1HO4zZ3Nq2V2jS%2Fu7A4lHPBihAXOADaMXJt%2FRTY6Jx5C%0Afx%2BBg%2FWhpOBTsXHEG0U%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2604970825/d7b961271be69e7541b406df1efd/d845324e-6b4a-4f54-83b9-0bea86ec09c6?expires=1793691900&signature=c668c400b2b1bc04ba0ba13fd1aed2d6c561d46dfdd3308fd2f51eba7862f6e8&req=diYnEsB5nYldXPMW1HO4zZ3Nq2V2gS3l7A4lHPBihAUgAjQhaQUpTN52zEAk%0AGAkV55K%2F9K%2F5YHVSPDQ%3D%0A) ### Permission options diff --git a/content/support/12997503-team-plan-billing-faqs.md b/content/support/12997503-team-plan-billing-faqs.md index 6a9560e7b2..2fdd5ba170 100644 --- a/content/support/12997503-team-plan-billing-faqs.md +++ b/content/support/12997503-team-plan-billing-faqs.md @@ -18,7 +18,7 @@ Your organization's billing address determines where your invoices are sent. You If you want to use a name other than the one tied to your payment method, an organization Owner should check the "Use a different name on invoices" box when adding or updating your payment method in **[Organization settings > Billing](https://claude.ai/admin-settings/billing)**: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1922145253/f2e3d4e0fe43a2ea07e89244764c/image.png?expires=1793653200&signature=3f7270d233a3355bbc368dcd669c9c71b2bb9c8cd71f5f1e2d99702fd1b903ac&req=dSklFMh6mINaWvMW1HO4zRZTxVnHvsjRKAqLF4ERnlVhi24ZXbNkN7EWaauT%0AGESBg1gJQFDNyGh%2FsT4%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1922145253/f2e3d4e0fe43a2ea07e89244764c/image.png?expires=1793691900&signature=2f597c3a12a2a39c520f1fabda0b777671c336ede61eb7b5d9d3b71c7bfa1edf&req=dSklFMh6mINaWvMW1HO4zRZTxVnHssraKAqLF4ERnlWjV3FsNTLisNLbJagQ%0AYOAMkuNsmPjQIyuf31g%3D%0A) ## When will I be billed? diff --git a/content/support/13132885-set-up-single-sign-on-sso.md b/content/support/13132885-set-up-single-sign-on-sso.md index b85d035962..d20e33d973 100644 --- a/content/support/13132885-set-up-single-sign-on-sso.md +++ b/content/support/13132885-set-up-single-sign-on-sso.md @@ -42,7 +42,7 @@ You can verify multiple domains for a single organization, but all domains must 3. Enter the domain(s) you want to verify in the **Update organization email domains** modal and click the “+” button: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2498843282/561d5ceb1c3a5df75bdfee8bfc3f/d2491145-362d-490b-bdcf-66a0a7656ddc?expires=1793653200&signature=cab081efb874f65055e37e1f12eef307ef0671146f3122cd2928ea2369f25155&req=diQuHsF6noNXW%2FMW1HO4zSdmH38%2F%2F8eOe3H0OpmIzWEZuXYNTbQTvHfwJ7AG%0AHZ6w%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2498843282/561d5ceb1c3a5df75bdfee8bfc3f/d2491145-362d-490b-bdcf-66a0a7656ddc?expires=1793691900&signature=52dd96409e06e577367423809b617564a4ab96d470a9f8e12f9ecddab0bc9cc0&req=diQuHsF6noNXW%2FMW1HO4zSdmH38%2F88WFe3H0OpmIzWHwUPJwgNdrvxqA0fqa%0ANwc6%0A) 4. Click “Save” when you’re finished adding domains. @@ -50,7 +50,7 @@ You can verify multiple domains for a single organization, but all domains must 6. Enter your domain in the text box and click “Continue”: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2047042630/0617a562cd28a7ff0e607d66a30b/6bd08e1d-2b65-40ab-bc79-a257153854c1?expires=1793653200&signature=a83feb77e7c51388a6ecd9adec8131ca2e4d10ed1e22493f016fe7e283d432ae&req=diAjEcl6n4dcWfMW1HO4zWHctB6RktKoyoyXAW0OlXoU8AnrNk7aWntHwntV%0ATJ9j%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2047042630/0617a562cd28a7ff0e607d66a30b/6bd08e1d-2b65-40ab-bc79-a257153854c1?expires=1793691900&signature=af116edd616cebafca17de1268765f07d95fa88744e2344b73c7607f19f8ecd7&req=diAjEcl6n4dcWfMW1HO4zWHctB6RntCjyoyXAW0OlXrn4A%2F%2BrRq59vXWAyBE%0Aw%2BjM%0A) 7. The setup screen displays a TXT record. **Copy the full Value using the copy button**—it begins with `anthropic-domain-verification-` and is longer than what's visible in the box. In your DNS provider, add a TXT record to your domain and **Value** set to the copied string. The domain must match exactly what you entered in the previous step, including any subdomains. Add it alongside any existing TXT records; don't replace them. The value is case-sensitive, so paste it exactly. Please refer to your DNS provider's documentation on this topic. @@ -76,7 +76,7 @@ Clicking "Refresh" re-checks your DNS; it won't show Verified until the publishe If the record is correct and propagated but the status still shows Pending, contact Support. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2047044496/b8df54a0331784cc9ae8f00112aa/bf9609c1-dc93-4665-a066-4cae2fe4b002?expires=1793653200&signature=d2d7e3a19289bf8e4e7644631a0150fd20ed1da2dbf9407e6e6a00d032c28dab&req=diAjEcl6mYVWX%2FMW1HO4zVjmWCoGane7PM2D8ZcdgrgLaDMG1yy9qx1IDw3Q%0AyW9LfIDiuCMbzCOHYg8%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2047044496/b8df54a0331784cc9ae8f00112aa/bf9609c1-dc93-4665-a066-4cae2fe4b002?expires=1793691900&signature=4ccb96b205ea3676147e3c34f9fd0c4edfdae3359ddea73b6defa0153c966cee&req=diAjEcl6mYVWX%2FMW1HO4zVjmWCoGZnWwPM2D8ZcdgrieD4vz57L2rQSk2wpE%0AGfVQLdTMB3mizmEYKfI%3D%0A) **Note:** Once your domain is verified, you'll see a **Restrict organization creation** toggle under **Security** on the Organization and access organization settings page. Enable this if you want to prevent users from creating new Claude or Console organizations—including personal accounts—using your verified domains. @@ -116,7 +116,7 @@ For IdP-specific setup instructions, see: You can now choose to toggle on **Require SSO for Console** and/or **Require SSO for Claude,** on the **Organization and access** page, under the **Authentication** section: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2312690200/bd2403586d4f6651ccd79e2a45af/b9f8d7ce-0def-49d9-bfb2-3a14352d7214?expires=1793653200&signature=17a4513d17d8d05a013afadaca30bba2bbd4c2c2e547d4126d7c1749de590faf&req=diMmFM93nYNfWfMW1HO4zdAICgynB38IItXtKivx6ZF7umWpH87fw7iCmZB6%0AYn4RRr%2FZ2gtscdZDdH4%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2312690200/bd2403586d4f6651ccd79e2a45af/b9f8d7ce-0def-49d9-bfb2-3a14352d7214?expires=1793691900&signature=a59ea1f923009d8f5463004fa6c27c1e7e44787b86dc384208b728758ce097a0&req=diMmFM93nYNfWfMW1HO4zdAICgynC30DItXtKivx6ZFB3LyZSHUSPadYrGw6%0AE4zqFsRSC4yYgpsmMe0%3D%0A) When SSO is required, users must use the “Continue with SSO” option to log in to their Claude/Console accounts. When SSO is not required, they will have the option to choose “Continue with SSO” or “Continue with email.” diff --git a/content/support/13133195-set-up-jit-or-scim-provisioning.md b/content/support/13133195-set-up-jit-or-scim-provisioning.md index e7bab1464e..4741c9b5b3 100644 --- a/content/support/13133195-set-up-jit-or-scim-provisioning.md +++ b/content/support/13133195-set-up-jit-or-scim-provisioning.md @@ -40,7 +40,7 @@ Use this table to help decide which provisioning mode is right for your organiza Both JIT and SCIM can be combined with **Enable group mappings** to control role or seat tier assignment based on IdP group membership. If you select either of these options for your provisioning mode, **Enable group mappings** will appear within the **User provisioning** section: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2312706099/35d5d3ec149880a96bb7acec59f6/a4cfce55-86bf-40b0-b455-c8f412d48e9e?expires=1793653200&signature=3fcdf11d94e169135f20372cf4120dd8cdf0aeedcdeeb70e55436019700696a9&req=diMmFM5%2Bm4FWUPMW1HO4zXBDQqhSCFl0xFMG%2BIEvQSd9XR7XAq8yoykwpoM4%0A4QWmTIQlbg72thtPSW8%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2312706099/35d5d3ec149880a96bb7acec59f6/a4cfce55-86bf-40b0-b455-c8f412d48e9e?expires=1793691900&signature=d92a9fa434a1e60e13dc9fea4b5c64ef4b0ab6a957c06569c41e5cc62d14f7b8&req=diMmFM5%2Bm4FWUPMW1HO4zXBDQqhSBFt%2FxFMG%2BIEvQSeOG4I9xCqERhvFR%2BOb%0Azh9FZEIEBjShdLAMwsc%3D%0A) **Important:** Group mappings set a user’s role type and seat tier only. Users with the Custom role get their permissions from groups in Claude, and those groups sync from your IdP only when your provisioning mode is SCIM directory sync. With JIT, you need to create groups and add users to them manually in **[Organization settings > Groups](https://claude.ai/admin-settings/groups)**. If you map an IdP group to the Custom role under JIT without doing this, those users have no permissions when they log in. Learn more about **[managing groups on Enterprise plans](https://support.claude.com/en/articles/13799932)**. @@ -136,7 +136,7 @@ Learn more about **[setting up role-based permissions on Enterprise plans](https 4. Toggle **Enable group mappings** on (if it’s not already): - ![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2312714635/b57870b51e6511c8293637bceee2/da1ceabc-b6bc-451b-9cda-24ff6aa90d02?expires=1793653200&signature=5ae00f513f3960d8a65b4f9a8e0b21040486ac329cdff6e6b75c3cdc8fdfe493&req=diMmFM5%2FmYdcXPMW1HO4zeBEb8bekvlKyb72rapuHpOR1f00D4iU4HoHYntS%0ATxaa%0A) + ![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2312714635/b57870b51e6511c8293637bceee2/da1ceabc-b6bc-451b-9cda-24ff6aa90d02?expires=1793691900&signature=dedc70efa72f4011dd01fcfe636c441e83b116d6a1c69a08bb427dee609a6734&req=diMmFM5%2FmYdcXPMW1HO4zeBEb8benvtByb72rapuHpMtMP9%2BPgmOWr%2BO%2Fx2j%0Ap3GJ%0A) 5. In the **Enable group mappings** section, click “Add” next to each role and select the corresponding group from your IdP in the dropdown. @@ -188,7 +188,7 @@ Verify you have enough seats purchased and available to add members to your org. 4. **For SCIM:** Click "Sync" to prompt an immediate sync, or wait for the automatic sync cycle: - ![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2312717421/c97fce49ad17d4660880a05fbaaf/59fbfa2a-1072-4662-8ca5-102970d5a795?expires=1793653200&signature=4893dd7512c42631819148aea1d9f509164e0110e99994df32304dbc2d600046&req=diMmFM5%2FmoVdWPMW1HO4zZ9Lal6rHMnA5hujYvMis4ev6SR9I42kzmCl%2Funp%0AE9da%0A) + ![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2312717421/c97fce49ad17d4660880a05fbaaf/59fbfa2a-1072-4662-8ca5-102970d5a795?expires=1793691900&signature=ed65996a77a187a08bfcb738c5acede41cd65cc1e2d2ddfe1431c3884eaaf5d1&req=diMmFM5%2FmoVdWPMW1HO4zZ9Lal6rEMvL5hujYvMis4coQnsTCkaQWL4qYyNy%0AEjWf%0A) ### Users mapped to the Custom role can't access anything after logging in diff --git a/content/support/13163631-configuring-session-security-settings.md b/content/support/13163631-configuring-session-security-settings.md index 85136a09d9..fac0bff6f2 100644 --- a/content/support/13163631-configuring-session-security-settings.md +++ b/content/support/13163631-configuring-session-security-settings.md @@ -18,7 +18,7 @@ Session duration controls allow Enterprise and Console Admins to set a maximum s 5. Confirm your selection by clicking “Enable.” -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1888469436/1725e63ea1a2615948faecf4ec73/9bd276a1-7329-414d-87a1-d04dac93fff7?expires=1793653200&signature=670109b1b49f08b6db21832ac316bb51bf47d76ea976d80c7f6c216a04a23a04&req=dSgvHs14lIVcX%2FMW1HO4zQNx6uEhRllSg%2F6XaftFnjze64yvYqxsiCmsPGOd%0AVxE9Eg3L1E7k1bSeZZg%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1888469436/1725e63ea1a2615948faecf4ec73/9bd276a1-7329-414d-87a1-d04dac93fff7?expires=1793691900&signature=91afe4b7b605bc441f02f12915d02cf12872ee791f785bc5d7504482497c9200&req=dSgvHs14lIVcX%2FMW1HO4zQNx6uEhSltZg%2F6XaftFnjz1dWRSOFkhDlUhGzVo%0Al8JqcDRdGN%2BcH8YyT0s%3D%0A) ### For Console Admins @@ -32,7 +32,7 @@ Session duration controls allow Enterprise and Console Admins to set a maximum s 5. Confirm your selection by clicking “Enable.” -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1888469435/7a766bbe02e61c7d8f05deb5b8f0/b0bda400-47c6-43dd-9907-131ebe180b36?expires=1793653200&signature=a3fa36a2493ceddbcb58e74ff24bf41e83ccc9ce760fee88fa878e3c8a823e9f&req=dSgvHs14lIVcXPMW1HO4zWzx2bowInwjXZ5D7eVpMtfVFNxO9pqc7MY4kY1o%0AVaYClgxk1GFK5EKirKg%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1888469435/7a766bbe02e61c7d8f05deb5b8f0/b0bda400-47c6-43dd-9907-131ebe180b36?expires=1793691900&signature=d9acd4ef6c2382027fd7a3dfed1c9e866415e9307ae37a0da8bfcbbf32cf163e&req=dSgvHs14lIVcXPMW1HO4zWzx2bowLn4oXZ5D7eVpMtdbIzn2gwjXB35Eeask%0AKPn7LUbPzgf61HU76pc%3D%0A) ### What happens after enabling shortened session length? @@ -50,7 +50,7 @@ You can change the session duration at any time by selecting a new value from th - Sessions scheduled to expire beyond the new duration will have their expiration shortened accordingly. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1888469437/46ac5bc55484ca01556d87a5ade7/b01a7651-ad65-4b32-93ff-16dbc9ca97c0?expires=1793653200&signature=56a0645ec8761c40bab1a66ba850b1cf6f6b46b693b1d9853f0471b1e37bc628&req=dSgvHs14lIVcXvMW1HO4zZ7mW8ud4jqhA00cbyPOLDWfhkeg%2FWHP%2FNHOBLrC%0A%2F1L3uO8yGw5UsOkpAAw%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1888469437/46ac5bc55484ca01556d87a5ade7/b01a7651-ad65-4b32-93ff-16dbc9ca97c0?expires=1793691900&signature=3322f076e75dfe004da7841f5ac5735256466cc9b061582a17f17944963c3ea0&req=dSgvHs14lIVcXvMW1HO4zZ7mW8ud7jiqA00cbyPOLDXc7YZ4dZbRuSBLWj%2BU%0AaBwmmsIBWRtD%2Fgc1tms%3D%0A) ## Disabling session length settings diff --git a/content/support/13189465-log-in-to-your-claude-account.md b/content/support/13189465-log-in-to-your-claude-account.md index 30c286105f..953bc79d8a 100644 --- a/content/support/13189465-log-in-to-your-claude-account.md +++ b/content/support/13189465-log-in-to-your-claude-account.md @@ -2,7 +2,7 @@ When you open Claude on a web browser ([claude.ai](https://claude.ai)), the desktop app, or a mobile app, you will see two different options for logging in to your Claude account. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1893216804/f2209c3ec6cf4fc2e803d13bbc9d/40520c9e-ff82-4a7c-adca-5a064fe18d8c?expires=1793653200&signature=01600acdd302a6213729ae64cefccb53466b19ab0763ad725e7ae1308d027f48&req=dSguFct%2Fm4lfXfMW1HO4zXg5B4GK5hG2zWhrqpWiTMmGGAFTfFisUhxxNgPc%0AuD%2B2LudKWy6CcmRdhnQ%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1893216804/f2209c3ec6cf4fc2e803d13bbc9d/40520c9e-ff82-4a7c-adca-5a064fe18d8c?expires=1793691900&signature=4228e75d401950a898d0f53598a207fee870b710a9f130f2da7706383fd9999b&req=dSguFct%2Fm4lfXfMW1HO4zXg5B4GK6hO9zWhrqpWiTMmuiYElk2wRzrmNIiEe%0AIMS%2BfQsTTxIBHBpqn%2Bk%3D%0A) ## Continue with Google diff --git a/content/support/13325567-account-management-faqs.md b/content/support/13325567-account-management-faqs.md index 3bf5cf7496..e3355ce198 100644 --- a/content/support/13325567-account-management-faqs.md +++ b/content/support/13325567-account-management-faqs.md @@ -44,6 +44,6 @@ The email domain that was used to create your Team or Enterprise plan organizati Owners can remove domains by opening up the same modal and clicking the trash can icon to the right of the domain: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2053873852/1cbccea3b7067e03205f2ff8546b/CleanShot+2026-02-11+at+11_16_07%402x.png?expires=1793653200&signature=4ed036a0717cfca63f6a0a1108a0e0ec3af82973429c9e5cf2dfbe08b5253082&req=diAiFcF5nolaW%2FMW1HO4zUrhF%2BiebAsYkeFUnrkrQZhrL0txBWBrGnZDrX9u%0AAwQW6wYIJ7cIMjGsOe0%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2053873852/1cbccea3b7067e03205f2ff8546b/CleanShot+2026-02-11+at+11_16_07%402x.png?expires=1793691900&signature=6aaf32e8ddca9fbfd7ea2b9e24b3425b0bab6f9a2fe7287ba5158b694172d4b2&req=diAiFcF5nolaW%2FMW1HO4zUrhF%2BieYAkTkeFUnrkrQZhWX17pB9a1ywmWWNMR%0A8plVSVSv3VU91FJUPuA%3D%0A) While the account creator must use a business email address, you can add public domains like @gmail.com, @yahoo.com, and @hotmail.com as allowed domains for other members of your organization. \ No newline at end of file diff --git a/content/support/13345190-get-started-with-claude-cowork.md b/content/support/13345190-get-started-with-claude-cowork.md index 74105fe42f..214cd5845f 100644 --- a/content/support/13345190-get-started-with-claude-cowork.md +++ b/content/support/13345190-get-started-with-claude-cowork.md @@ -178,7 +178,7 @@ To set global instructions: 3. Type your instructions in the text box and click "Save": -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2525926874/15324ac4155d7802272e8bdef04b/ec66cd09-a4db-4f1d-8f30-226c9d126333?expires=1793653200&signature=5e806129654af1489d5cdc032f7fd57b7b41704cf1169dbef4e70e278263a444&req=diUlE8B8m4lYXfMW1HO4zcDl69vqM1Ky8iWjaktE9435X%2BxPbFLcS3OnNc37%0AxYopjNA%2F8phQWTSDJwY%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2525926874/15324ac4155d7802272e8bdef04b/ec66cd09-a4db-4f1d-8f30-226c9d126333?expires=1793691900&signature=2a53a5c9aa3e2351743591c16456cadeb40cf84c4a3b6288b41c5611534d0a62&req=diUlE8B8m4lYXfMW1HO4zcDl69vqP1C58iWjaktE9420sYLqA7p6H%2FLYTrKd%0Ad6FrfapXM9im4%2B0k6D4%3D%0A) ### Folder instructions diff --git a/content/support/13371040-log-in-to-your-console-account.md b/content/support/13371040-log-in-to-your-console-account.md index e16f996500..96a901b633 100644 --- a/content/support/13371040-log-in-to-your-console-account.md +++ b/content/support/13371040-log-in-to-your-console-account.md @@ -2,7 +2,7 @@ When you navigate to the **[Claude Console](https://platform.claude.com)**, you will see two different options for logging in to your Console account. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1935026646/d90d1613a3dbe763fef5abb96e3c/image.png?expires=1793653200&signature=f9e408dcdbdc63b6cdbc29a9a8a8b8651626770abb04effbcfbf7af71c33fafc&req=dSkkE8l8m4dbX%2FMW1HO4zcrI5orqpYMP8vUNcPt4%2B73Zj%2B8bZG2rfItmrZHC%0AEI%2FUCpvjqzPFC9MT5uc%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1935026646/d90d1613a3dbe763fef5abb96e3c/image.png?expires=1793691900&signature=218cba892d6f7ac4191ae61228418ed3e1ecb02de4b523847bba81bc29929d8c&req=dSkkE8l8m4dbX%2FMW1HO4zcrI5orqqYEE8vUNcPt4%2B70yNPvhhnw4HcpvXj1E%0AYmPCYvWJnT1XnSX49Iw%3D%0A) ## Continue with Google diff --git a/content/support/13641943-visual-and-interactive-content.md b/content/support/13641943-visual-and-interactive-content.md index 305399dbb7..bebbee27e3 100644 --- a/content/support/13641943-visual-and-interactive-content.md +++ b/content/support/13641943-visual-and-interactive-content.md @@ -18,7 +18,7 @@ Claude can show current weather conditions and forecasts when you ask about the Claude automatically displays temperatures in Fahrenheit for US locations and Celsius for everywhere else. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2040544927/3a9c695b24df387ecdd766ad308c/8be9f393-dcb0-4ff8-89e8-5fa47bedaa38?expires=1793653200&signature=83e1d576b21042774dafde8430d1031972c9dff4d413979b42de60fe2b2bcbb2&req=diAjFsx6mYhdXvMW1HO4zXlB7D280BuKdgndksVD5R3uEmZkjyrb0s4Rc5nc%0AvwoaSjHS1dc7art%2FYf8%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2040544927/3a9c695b24df387ecdd766ad308c/8be9f393-dcb0-4ff8-89e8-5fa47bedaa38?expires=1793691900&signature=431a8873d8c424e1e0159d15d08244739d05557d2cd378cc9e2bc842de490456&req=diAjFsx6mYhdXvMW1HO4zXlB7D283BmBdgndksVD5R0rvRVNUM%2FxAyjRHKB1%0A1XoFsuYqIKTSgpXS%2FPI%3D%0A) Weather is powered by Google Maps (). @@ -28,7 +28,7 @@ When you ask about recipes, Claude can display formatted recipe cards that are e **Note:** Visual recipe cards are available on web and desktop only. On mobile, Claude provides recipe information as text in the conversation. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2040544929/12f4c51eda7779d65d3ea2c7ab16/d0f4a314-cff8-421a-b401-10c2bf50374e?expires=1793653200&signature=d02ec0cc69d495e1ff1f9437be5829cedefe3e385c5a6125d6c5627e11df1f43&req=diAjFsx6mYhdUPMW1HO4zUQperMT11eVrIPm%2FImZVg2vJyACe7axT%2BcNaIeI%0Ay7UXVfkdGuEalPGbLEM%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2040544929/12f4c51eda7779d65d3ea2c7ab16/d0f4a314-cff8-421a-b401-10c2bf50374e?expires=1793691900&signature=ef244550a78dda4418232ae19827f6243a100989f516b91d9e624b07c7fafd22&req=diAjFsx6mYhdUPMW1HO4zUQperMT21WerIPm%2FImZVg07O2DsxT9ROpC1dUKA%0A9ZYi%2FtthKlD7bFEW7So%3D%0A) ### Custom visuals @@ -76,7 +76,7 @@ For example, if you ask Claude to help you plan a trip, it might ask you to: This content appears at the bottom of the chat. You can still type a response if you prefer. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2040544930/9ad066e137d11e4b559b0217e12d/9bf30d2d-1715-42b3-9da5-2a9298f41f08?expires=1793653200&signature=f01f17b4599637c3f207707bee1a22df9f6e84185e148a541ab5b34cab425446&req=diAjFsx6mYhcWfMW1HO4zWmF5va4bB2gx4wz0C7CTAJ5ih5OIAnErd3EPyIJ%0ANcVYGeBEh2ketm%2BDOdI%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2040544930/9ad066e137d11e4b559b0217e12d/9bf30d2d-1715-42b3-9da5-2a9298f41f08?expires=1793691900&signature=993dea09dca577ae4d481561c3878f125542a45584e125d544d4eaa3f1e48801&req=diAjFsx6mYhcWfMW1HO4zWmF5va4YB%2Brx4wz0C7CTAKEXhA%2BcGFarIEwKZKq%0AoWhl8pnCauzxO9zXzqg%3D%0A) --- diff --git a/content/support/13837440-use-plugins-in-claude.md b/content/support/13837440-use-plugins-in-claude.md index 874544efa0..5ce6c69473 100644 --- a/content/support/13837440-use-plugins-in-claude.md +++ b/content/support/13837440-use-plugins-in-claude.md @@ -58,7 +58,7 @@ In Cowork, open the "Cowork" tab first, then open **Customize**. You can also upload a custom plugin file if you built one yourself. On Team and Enterprise plans, a colleague can share a plugin with you directly instead of sending you the file. See **[Use a plugin shared with you](https://support.claude.com/en/articles/13837440-use-plugins-in-claude#h_ef985546b4)** below. Plugins you add in Claude on the web or in Claude Desktop are saved to your account, not to your computer, so they follow you to chat, Cowork, and Claude Code. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2100409211/fc01614dde1a616fa31ffaa9cb04/47bacf5b-a810-45b5-a468-9769f1a58ef8?expires=1793653200&signature=faf36e26f8b18d6d1d57a78e02d102abd87024a454a4a5ce1b7488eddbb552d9&req=diEnFs1%2BlINeWPMW1HO4zZF3IxbbNvZXxakFVfq5WwyhrWSn%2Fi%2Fu%2F0ZjRdYM%0AdA%2Fa1IKSIS007UqonI0%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2100409211/fc01614dde1a616fa31ffaa9cb04/47bacf5b-a810-45b5-a468-9769f1a58ef8?expires=1793691900&signature=29976006469142ec66b449a95b005d37c440fc209bee0bda570ac59a739928a4&req=diEnFs1%2BlINeWPMW1HO4zZF3IxbbOvRcxakFVfq5WwzGudTwLkhtjcBsfxxX%0AamcOCKRrnnsof7rk0V0%3D%0A) If you're on the Enterprise plan and your organization has skill scanning turned on, plugins are checked for malicious content when they're installed or updated. A plugin with malicious content is blocked, and one that may carry risk shows a caution banner. Learn more about **[skill and plugin scanning](https://support.claude.com/en/articles/15927065)**. @@ -68,7 +68,7 @@ If you're on the Enterprise plan and your organization has skill scanning turned Each plugin you add brings skills and commands you can use while working with Claude. Type "/" or click the "+" button to see the available skills from your plugins, in chat and in Cowork. In Cowork, you can also run a plugin's command by typing `/plugin-name:command`. Click any skill to see its details. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2157396844/4a790e10f5b88df770783df1d7e9/image.png?expires=1793653200&signature=1b7c6f7487c9f54902dc55eabc8b731f95836a30178249b41b1e743579184097&req=diEiEcp3m4lbXfMW1HO4zf4NBfX6hkOWmKUxugP2BQuGPmtLYAC66evQW2pU%0AmMDIqVgoZ0I66mMqq%2FA%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2157396844/4a790e10f5b88df770783df1d7e9/image.png?expires=1793691900&signature=7b88c138bad96186c77e125e31f90bad2ca6e12fdf23430e797797d891ef3b06&req=diEiEcp3m4lbXfMW1HO4zf4NBfX6ikGdmKUxugP2BQtJAgCOfdKyNTDlsRlv%0ACASKXOACJA96TBO%2B0Vc%3D%0A) --- diff --git a/content/support/13947068-assign-tasks-from-anywhere-in-claude-cowork.md b/content/support/13947068-assign-tasks-from-anywhere-in-claude-cowork.md index a90af91768..55444f0873 100644 --- a/content/support/13947068-assign-tasks-from-anywhere-in-claude-cowork.md +++ b/content/support/13947068-assign-tasks-from-anywhere-in-claude-cowork.md @@ -52,11 +52,11 @@ Follow these steps to get started: 5. You’ll land on a page describing the functionality. Click “Get started”: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2169954086/419674f781edb2977b93cce062b4/93b1893c-d79a-4eb6-b2f1-2fe3e043bd90?expires=1793653200&signature=50ff6defc5e93d3f84339f48b91a464964ee01a752209c147df47a222459a1dc&req=diEhH8B7mYFXX%2FMW1HO4zSZP05GNEA39B32drIe5EDltsTXB7t5VyyhfzlHX%0AagGT%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2169954086/419674f781edb2977b93cce062b4/93b1893c-d79a-4eb6-b2f1-2fe3e043bd90?expires=1793691900&signature=2ac0a15dbf399a2d562b294bd142870624a7df5ca3a50f957bf71195d6456709&req=diEhH8B7mYFXX%2FMW1HO4zSZP05GNHA%2F2B32drIe5EDlVgQ95uI05%2F%2FcPT9Fp%0AJMAu%0A) 6. On the next screen, you can give Claude access to your files and keep your computer awake by toggling those on: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2169955082/de4053ee0eab8fcb9263584bb171/d39b77da-1a69-4682-9fdb-7ed488f236b0?expires=1793653200&signature=49ce80ac7b4f5f15b910dd4f4296de820101eb1ca5bf323d1d82c5ddcc9129f1&req=diEhH8B7mIFXW%2FMW1HO4zaZWstmeWAIcepuGRb1rD3L%2BZCkuOR%2BZy94%2Bxf4a%0Al0af%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2169955082/de4053ee0eab8fcb9263584bb171/d39b77da-1a69-4682-9fdb-7ed488f236b0?expires=1793691900&signature=cc1252edea81ea9c6c7fcefbd04834d99ce8b942a3d965606cecb6bd8a402d79&req=diEhH8B7mIFXW%2FMW1HO4zaZWstmeVAAXepuGRb1rD3In3zQQHfemhDvkwBpt%0AMjiV%0A) 7. Click “Finish setup.” diff --git a/content/support/14116274-organize-your-tasks-with-projects-in-claude-cowork.md b/content/support/14116274-organize-your-tasks-with-projects-in-claude-cowork.md index b4a3e565ce..b9fe74a389 100644 --- a/content/support/14116274-organize-your-tasks-with-projects-in-claude-cowork.md +++ b/content/support/14116274-organize-your-tasks-with-projects-in-claude-cowork.md @@ -16,23 +16,23 @@ The new Claude experience, which combines chat and Cowork, is rolling out to Pro Find **Projects** in the left navigation panel and click the “+” button to see the three different ways to create a project: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2183720240/6f6ef438913391703598d86d606c/CleanShot+2026-03-20+at+09_11_43.png?expires=1793653200&signature=9c97c7228fba1be71330aea36729aff4d53301e42b13d916c8320396c0e0e2db&req=diEvFc58nYNbWfMW1HO4zcOgiga81Ct3ZwSvwegvtgyCNNBcM8FFvHOVFMjq%0AyZxaB47%2BgwvupJ9SsUE%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2183720240/6f6ef438913391703598d86d606c/CleanShot+2026-03-20+at+09_11_43.png?expires=1793691900&signature=a3c14e050cec002fc2146ced64f729c5c2714354d3460112bc270f78c32a5908&req=diEvFc58nYNbWfMW1HO4zcOgiga82Cl8ZwSvwegvtgyOtkp6MLk0CXs0SM6R%0ABUW4vYQRl%2BsZfZBQYXM%3D%0A) ### Start from scratch Selecting “Start from scratch” allows you to set up a new folder with instructions and files: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2177090014/07832b50003cf7fd3b4e9c7c448b/3385d9b8-c3e7-42b9-ae3f-4d213baa53a7?expires=1793653200&signature=07353e4de66c102a98dfc6c16fdba46e0b61277552981cdb05376c20262eac45&req=diEgEcl3nYFeXfMW1HO4zZCoQo5DS3aUvb0suCMAnj3WcpEBCTkXwIXV9pGU%0AsWgtaST2ZGOLKTNQzt0%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2177090014/07832b50003cf7fd3b4e9c7c448b/3385d9b8-c3e7-42b9-ae3f-4d213baa53a7?expires=1793691900&signature=5ab2c50e6b41f087261e283ff344bb2573b81b3071bd2753dbd6698c7dd0ac7e&req=diEgEcl3nYFeXfMW1HO4zZCoQo5DR3Sfvb0suCMAnj08Qsz5jqYcdZRKR1%2Bm%0AX5puTO%2BiEqKs1l4aPZU%3D%0A) ### Import from a Claude project After selecting “Import from project,” you’ll see a “Search projects in Chat…” field: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2183717962/acdc11bcc825ae76a13f508365bc/CleanShot+2026-03-20+at+09_12_08.png?expires=1793653200&signature=465fee4d25c4264019d5a71e7986371d938f40a7780e09078dde01a6abdd6f91&req=diEvFc5%2FmohZW%2FMW1HO4zQQ7UWBbz5sdjggUT7FIJz%2BvBHlZISqYlLTjOMpH%0A1LSmRfu%2B5w1vq8cCj4s%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2183717962/acdc11bcc825ae76a13f508365bc/CleanShot+2026-03-20+at+09_12_08.png?expires=1793691900&signature=d60ff15edf2b4acd33c7dfc2c7f4db0869ac8a3c61228c578c9d382a5c942846&req=diEvFc5%2FmohZW%2FMW1HO4zQQ7UWBbw5kWjggUT7FIJz8S5bzlK%2BLNb%2Bkk1wh2%0A4mEy7%2BR4LVZ%2FREnp6Jo%3D%0A) Clicking into the field will display a drop-down showing your recent projects, but you can also use it to search all your projects. After you select a chat project (bulk upload is not supported), you can name the new Cowork project and choose where to save it on your computer: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2183727973/7a25430123d9e13e7c3cdd411f70/CleanShot+2026-03-20+at+09_13_41.png?expires=1793653200&signature=019170449d91566fa9360478a8a6e823cfede4b669bf088ac9d568364862fd1f&req=diEvFc58mohYWvMW1HO4zU%2FKAyBA%2BSDOI7f%2FdY0VL6hrmzAucazLU0G7szdt%0Apc6%2B9%2FLkqdfWma6FnpA%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2183727973/7a25430123d9e13e7c3cdd411f70/CleanShot+2026-03-20+at+09_13_41.png?expires=1793691900&signature=9dad1edcab6ef5b3ad2a5028dbc246e3147ee1b4507dbf5c9931560eab5d6125&req=diEvFc58mohYWvMW1HO4zU%2FKAyBA9SLFI7f%2FdY0VL6gfztc3g4Z6bcQA3%2FFM%0AlO3fJh2%2F7ctXMpGlow0%3D%0A) Clicking “Create” will transfer the files and instructions from your existing Claude project and create a new Cowork project. @@ -40,11 +40,11 @@ Clicking “Create” will transfer the files and instructions from your existin If you select “Use an existing folder,” you’ll be prompted to pick a file to use as context for the new Cowork project: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2177087935/2f0052dae601d0b7fecdc029e1c3/2e3ca9e7-23b1-436e-bbdb-edcd31c41f15?expires=1793653200&signature=7a758a55815ece3c76bed270396f7581220d670bd2922eecd3bfd5d0e6268b9e&req=diEgEcl2mohcXPMW1HO4zejrnjXQECBduv8e2Xj2xOWjzV9XYYPjOYbJfoHt%0A%2BbkVQya8VbYMd2NiTsY%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2177087935/2f0052dae601d0b7fecdc029e1c3/2e3ca9e7-23b1-436e-bbdb-edcd31c41f15?expires=1793691900&signature=6c14ee987032b0d66cab784b74c0264a90ee87fdb9788e62edd69f27ebf01654&req=diEgEcl2mohcXPMW1HO4zejrnjXQHCJWuv8e2Xj2xOUY6upEeRSsYszv37Cj%0Ajw4ahWVTt7Sdcd13k7A%3D%0A) After selecting a folder, you can name the new Cowork project, choose where to save it on your computer, add instructions, and attach any additional files. Click “Create” to start using your new project: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2177087937/f59dbe3fc28448a9597ea097cb4d/96a59acb-4054-4b4b-a208-751f9711f535?expires=1793653200&signature=d1f15931526f4e650354e69c8f89fd973b05658316cf85abc701e71a7ed6cb1a&req=diEgEcl2mohcXvMW1HO4zUq4VuCyhqE4MfnqHouW6MKz%2BeCb4pzNrGs8eTQo%0APs6cb0H9Dl9ngHTQoRk%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2177087937/f59dbe3fc28448a9597ea097cb4d/96a59acb-4054-4b4b-a208-751f9711f535?expires=1793691900&signature=19b99c9d98b789bc2cc0e864802f73499fa68346717e3a2c1bb2004c72293770&req=diEgEcl2mohcXvMW1HO4zUq4VuCyiqMzMfnqHouW6MLRW2w8Bd7Og24XkTQa%0AR9dlJmJyLvHsp0IQ%2Bik%3D%0A) --- diff --git a/content/support/14499648-how-scim-sync-works-for-enterprise-organizations.md b/content/support/14499648-how-scim-sync-works-for-enterprise-organizations.md index 4daa9ade12..c83a41c19c 100644 --- a/content/support/14499648-how-scim-sync-works-for-enterprise-organizations.md +++ b/content/support/14499648-how-scim-sync-works-for-enterprise-organizations.md @@ -50,7 +50,7 @@ You can trigger a manual sync from two places in your admin settings. 2. Click "Check for updates" under **SCIM sync**: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2312613548/44cd5970ee3c3b2c7f8dcd592d71/image+%2824%29.png?expires=1793653200&signature=647b6b676e4abc94719d307395126faa3f1429ac07ca82e5191941187ca9416c&req=diMmFM9%2FnoRbUfMW1HO4zW4gbTarMM62rgfl7PnOiumFFHVSRcRhhgUnbB7v%0AVOsX%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2312613548/44cd5970ee3c3b2c7f8dcd592d71/image+%2824%29.png?expires=1793691900&signature=b7be540f5c92312444314a5b780ed418f5a90ba9e1916e79a8b42aa78225e182&req=diMmFM9%2FnoRbUfMW1HO4zW4gbTarPMy9rgfl7PnOiulb8YR6SXG14g4KpNi7%0A8p68%0A) 3. Select whether to sync members, groups, or both. @@ -62,7 +62,7 @@ You can trigger a manual sync from two places in your admin settings. 3. Select whether to sync members, groups, or both: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2312608119/e4b0ef4f309f3c4eac8311a6ef47/image.png?expires=1793653200&signature=71d989684b815abb4b70cd18d083c333c1956c93bb7f5dd6257807a41d3ee79b&req=diMmFM9%2BlYBeUPMW1HO4zX%2F4f7n2zjgd43OpyTHzM9T6o91LklmQ2wmPh39y%0AlUrI%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2312608119/e4b0ef4f309f3c4eac8311a6ef47/image.png?expires=1793691900&signature=b0b10fbf4402dc8a2f90777132e7e7d14838e49d9d670e3db3f8432dfb78b206&req=diMmFM9%2BlYBeUPMW1HO4zX%2F4f7n2wjoW43OpyTHzM9QbHWRc0QN0uyjj0z71%0AWymf%0A) **Note:** If you trigger a manual sync while background changes are processing, your organization takes the most recent change for each member or group. If multiple changes are queued for the same member or group, you may need to resync again to make sure everything applies correctly. diff --git a/content/support/14604842-cyber-verification-program.md b/content/support/14604842-cyber-verification-program.md index dcf1c253d8..9db01be06a 100644 --- a/content/support/14604842-cyber-verification-program.md +++ b/content/support/14604842-cyber-verification-program.md @@ -10,7 +10,7 @@ Our generally available models can still be used by all users for secure code re ## Access tiers -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2716457392/33c90f9ccfbd33fee02840fd2efa/267bc7d1-baeb-4302-a1d9-4491b4110775?expires=1793653200&signature=43044d18ffa9f5a58f5d09e5017927892af9c58e3dca0b1f1033ec8d4dcfa851&req=dicmEM17moJWW%2FMW1HO4zVYZ0Nu4a8dFy1US26KtMzKmk5HO3HcHleHlb7Qz%0Aw%2FAElPZnUPdEEi29eX0%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2716457392/33c90f9ccfbd33fee02840fd2efa/267bc7d1-baeb-4302-a1d9-4491b4110775?expires=1793793600&signature=493a844fd386eb75f1deaf44eec5c91ff6e919f45808634787300bd974b29d9f&req=dicmEM17moJWW%2FMW3nq%2BgVW5JBO7g33Lv53g72lEz5xpldbpX1vUL3fmDOPi%0AklhFvpxeXpEGVh%2BOf9%2BLwIiUSBY%3D%0A) ## How to apply @@ -26,17 +26,17 @@ What you'll need: - An attestation to the security controls applicable to your desired tier -| **How you access Claude** | **Availability** | -| ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **How you access Claude** | **Availability** | +| ---------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Anthropic first-party** -(Claude.ai, Claude Code, the Anthropic API)
| Sign in to the **[Verification Portal](https://portal.anthropic.com/programs)** with your Anthropic account.
Open **Programs**, choose "Cyber Verification Program" and select "Apply." | +(Claude.ai, Claude Code, the Anthropic API)
| Sign in to the **[Verification Portal](https://portal.anthropic.com/programs)** with your Anthropic account.
Open **Programs**, choose "Cyber Verification Program" and select "Apply." | | **Amazon Bedrock**
*Available only to customers with Enterprise Frontier Safeguards.* ​
**OR** -​
**Claude Platform on AWS** | Sign in to the **[Verification Portal](https://portal.anthropic.com/programs)**. If you don't have an Anthropic account, create one. It's free and doesn’t require billing information.
Open **[Linked accounts](https://portal.anthropic.com/linked-accounts)**, select "Link account" and choose "Amazon Web Services." Enter your 12-digit AWS account ID, create the verification role in that account using the portal's launch link or command, select "I've granted access," then "Verify." Link your Claude Platform on AWS account IDs before linking your Bedrock Account IDs.
Open **Programs**, choose "Cyber Verification Program" and select "Apply."
If you’ve created a new Anthropic account, you’ll need to link to your AWS account before applying for the program. | -| **Claude on Google Cloud** | Sign in to the **[Verification Portal](https://portal.anthropic.com/programs)**. If you don't have an Anthropic account, create one. It's free and doesn’t require billing information.
Open **[Linked accounts](https://portal.anthropic.com/linked-accounts)**, select "Link account" and choose "Google Cloud." Enter your project ID (not the project number), run the gcloud command shown, select "I've granted access," then "Verify."
Open **Programs**, choose "Cyber Verification Program" and select "Apply."
If you’ve created a new Anthropic account, you’ll need to link to your GCP account before applying for the program. | -| **Microsoft Foundry** | Before you start, deploy a Claude model in Foundry.
Sign in to the **[Verification Portal](https://portal.anthropic.com/programs)**. If you don't have an Anthropic account, create one. It's free and doesn’t require billing information.
Open **[Linked accounts](https://portal.anthropic.com/linked-accounts)**, select "Link account" and choose "Azure." Enter your subscription ID and directory (tenant) ID, run the commands shown, select "I've granted access," then "Verify."
Open **Programs**, choose "Cyber Verification Program" and select "Apply."
If you’ve created a new Anthropic account, you’ll need to link to your Azure account before applying for the program.
| +​
**Claude Platform on AWS** | Sign in to the **[Verification Portal](https://portal.anthropic.com/link?account_source=aws&program=cvp)**. If you don't have an Anthropic account, create one. It's free and doesn’t require billing information.
Open **[Linked accounts](https://portal.anthropic.com/linked-accounts)**, select "Link account" and choose "Amazon Web Services." Enter your 12-digit AWS account ID, create the verification role in that account using the portal's launch link or command, select "I've granted access," then "Verify." Link your Claude Platform on AWS account IDs before linking your Bedrock Account IDs.
Open **Programs**, choose "Cyber Verification Program" and select "Apply."
If you’ve created a new Anthropic account, you’ll need to link to your AWS account before applying for the program. | +| **Claude on Google Cloud** | Sign in to the **[Verification Portal](https://portal.anthropic.com/link?account_source=gcp&program=cvp)**. If you don't have an Anthropic account, create one. It's free and doesn’t require billing information.
Open **[Linked accounts](https://portal.anthropic.com/linked-accounts)**, select "Link account" and choose "Google Cloud." Enter your project ID (not the project number), run the gcloud command shown, select "I've granted access," then "Verify."
Open **Programs**, choose "Cyber Verification Program" and select "Apply."
If you’ve created a new Anthropic account, you’ll need to link to your GCP account before applying for the program. | +| **Microsoft Foundry** | Before you start, deploy a Claude model in Foundry.
Sign in to the **[Verification Portal](https://portal.anthropic.com/programs)**. If you don't have an Anthropic account, create one. It's free and doesn’t require billing information.
Open **[Linked accounts](https://portal.anthropic.com/linked-accounts)**, select "Link account" and choose "Azure." Enter your subscription ID and directory (tenant) ID, run the commands shown, select "I've granted access," then "Verify."
Open **Programs**, choose "Cyber Verification Program" and select "Apply."
If you’ve created a new Anthropic account, you’ll need to link to your Azure account before applying for the program.
| | **Third-party platform** -(coding tools and other apps powered by Claude) | Ask your platform for an Anthropic enrollment link. This works only on platforms that support the Cyber Verification Program.
Open the link and sign in to the **[Verification Portal](https://portal.anthropic.com/programs)** with your Anthropic account. If you don't have one, create one. It's free and doesn’t require billing information. Then select "Link profile." Links expire quickly, and you can't link a platform from the Linked accounts page.
Open **Programs**, choose "Cyber Verification Program" and select "Apply."
Defense Access and Red Team Access only. Specialized Access is not available through third-party platforms. | +(coding tools and other apps powered by Claude) | Ask your platform for an Anthropic enrollment link. This works only on platforms that support the Cyber Verification Program.
Open the link and sign in to the **[Verification Portal](https://portal.anthropic.com/programs)** with your Anthropic account. If you don't have one, create one. It's free and doesn’t require billing information. Then select "Link profile." Links expire quickly, and you can't link a platform from the Linked accounts page.
Open **Programs**, choose "Cyber Verification Program" and select "Apply."
Defense Access and Red Team Access only. Specialized Access is not available through third-party platforms. | ## Once you're approved @@ -102,19 +102,19 @@ Each access level has its own security requirements. The security requirements f After your application has been approved, the steps to provision access to your Grants vary depending on how you access Claude. -| **How you access Claude** | **Action required by Organization Owner** | -| -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Claude Console / API Organizations | **[Assign a program to workspaces](https://support.claude.com/en/articles/16764810-assign-a-program-to-workspaces-in-claude-console)** | -| Claude Enterprise | **[Assign a program to a custom role](https://support.claude.com/en/articles/17118092)** | -| Claude Team / Max / Pro | No action required (the Program attaches at the Organization level) | -| Amazon Bedrock
**Available only to customers with Enterprise Frontier Safeguards.** | If you have not already, sign in to the Verification Portal, open **[Linked accounts](https://portal.anthropic.com/linked-accounts)** and link your AWS account. Then open the **Cyber Verification Program** page and, under **Access** on linked accounts, turn on your approved access level for that account. Changes can take some time to reach the account.
If you have a committed contract with Anthropic, your account team will send a short form to link this AWS account to your contract. Complete the form, then accept the private offer in the AWS Marketplace so your contracted discount applies. Mythos access is provisioned once both steps are done.
Access to Mythos will trail application approval by approximately five business days. | -| Claude Platform on AWS | If you have not already, sign in to the Verification Portal, open **[Linked accounts](https://portal.anthropic.com/linked-accounts)** and link your AWS account. No further action: your approved access applies to every workspace.
If you have a committed contract with Anthropic, your account team will send a short form to link this AWS account to your contract. Complete the form, then accept the private offer in the AWS Marketplace so your contracted discount applies. Mythos access is provisioned once both steps are done.
Access to Mythos will trail application approval by approximately five business days. | -| Claude Platform on Google Cloud | If you have not already, sign in to the Verification Portal, open **[Linked accounts](https://portal.anthropic.com/linked-accounts)** and link your Google Cloud project. No further action: your approved access applies to every workspace.
If your organization has a committed contract with Anthropic, your account team will send you a short form to link this Google Cloud billing account to your contract. Complete the form, then accept the private offer in Google Cloud Marketplace so your contracted discount applies. Mythos access is provisioned once both steps are done.
Access to Mythos will trail application approval by approximately five business days. | -| Google Cloud Agent Platform | To access the Cyber Verification Program through Claude on Google Cloud, you must link your project in the **Verification Portal** under **Linked accounts**, and consent to and configure data retention with Google. You’ll need to complete this process for each project you want to link (up to 10).
**Enable data retention on Claude on Google Cloud:**
Link your Google Cloud project in the Verification Portal. Someone with IAM access on the project runs the one command the portal shows.

Sign in to the **Verification Portal**.
Open **Linked accounts** and follow the steps to link your Google Cloud project. +| **How you access Claude** | **Action required by Organization Owner** | +| -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Claude Console / API Organizations | **[Assign a program to workspaces](https://support.claude.com/en/articles/16764810-assign-a-program-to-workspaces-in-claude-console)**
**[Sign in to the Console](https://platform.claude.com/)** as an organization Admin.
Go to the **Workspaces** page (platform.claude.com/settings/workspaces).
Click "Create workspace" (you cannot use the default workspace for accessing the model). The **Create workspace** page opens.
Enter a name for your new Workspace, and select a color. The color helps you identify your workspace in the Claude Console.
Click "Create workspace."
Add the approved users to the new Workspace. | +| Claude Enterprise | **[Assign a program to a custom role](https://support.claude.com/en/articles/17118092)** | +| Claude Team / Max / Pro | No action required (the Program attaches at the Organization level) | +| Amazon Bedrock
**Available only to customers with Enterprise Frontier Safeguards.** | If you have not already, sign in to the Verification Portal, open **[Linked accounts](https://portal.anthropic.com/link?account_source=aws&program=cvp)** and link your AWS account. Then open the **Cyber Verification Program** page and, under **Access** on linked accounts, turn on your approved access level for that account. Changes can take some time to reach the account.
If you have a committed contract with Anthropic, your account team will send a short form to link this AWS account to your contract. Complete the form, then accept the private offer in the AWS Marketplace so your contracted discount applies. Mythos access is provisioned once both steps are done.
Access to Mythos will trail application approval by approximately five business days. | +| Claude Platform on AWS | If you have not already, sign in to the Verification Portal, open **[Linked accounts](https://portal.anthropic.com/link?account_source=aws&program=cvp)** and link your AWS account. No further action: your approved access applies to every workspace.
If you have a committed contract with Anthropic, your account team will send a short form to link this AWS account to your contract. Complete the form, then accept the private offer in the AWS Marketplace so your contracted discount applies. Mythos access is provisioned once both steps are done.
Access to Mythos will trail application approval by approximately five business days. | +| Claude Platform on Google Cloud | If you have not already, sign in to the Verification Portal, open **[Linked accounts](https://portal.anthropic.com/link?account_source=gcp&program=cvp)** and link your Google Cloud project. No further action: your approved access applies to every workspace.
If your organization has a committed contract with Anthropic, your account team will send you a short form to link this Google Cloud billing account to your contract. Complete the form, then accept the private offer in Google Cloud Marketplace so your contracted discount applies. Mythos access is provisioned once both steps are done.
Access to Mythos will trail application approval by approximately five business days. | +| Google Cloud Agent Platform | To access the Cyber Verification Program through Claude on Google Cloud, you must link your project in the **[Verification Portal](https://portal.anthropic.com/programs)** under **[Linked accounts](https://portal.anthropic.com/link?account_source=gcp&program=cvp)**, and consent to and configure data retention with Google. You’ll need to complete this process for each project you want to link (up to 10).
**Enable data retention on Claude on Google Cloud:**
Link your Google Cloud project in the Verification Portal. Someone with IAM access on the project runs the one command the portal shows.

Sign in to the **Verification Portal**.
Open **Linked accounts** and follow the steps to link your Google Cloud project.
After the project is linked, you’ll be taken to the linked account’s page. Find **Programs** and turn on your approved CVP access level for that project.
In Model Garden, open the Claude model and accept the Advanced AI Safety Addendum (once per project).
Turn on **data sharing** with Anthropic for each model and location (for example, `global`, `eu`, or `us`) you use. Set `dataSharingEnabledProvider` to `ANTHROPIC` with Google’s `setPublisherModelConfig` API.
If your organization has a committed contract with Anthropic, your account team will send you a short form to link this Google Cloud billing account to your contract. Complete the form, then accept the private offer in Google Cloud Marketplace so your contracted discount applies. Mythos access is provisioned once both steps are done.
Access to Mythos will trail application approval by approximately five business days. | -| Microsoft Foundry | For Microsoft Foundry, deploy a Claude model first.
If you have not already, sign in to the Verification Portal, open **[Linked accounts](https://portal.anthropic.com/linked-accounts)** and link your Azure subscription (you'll need the subscription ID and directory (tenant) ID). No further action: your approved access applies to every workspace.
If your organization has a committed contract with Anthropic, your account team will send you a short form to link this Azure account to your contract. Complete the form, then accept the private offer in Azure Marketplace so your contracted discount applies. Mythos access is provisioned once both steps are done.
Access to Mythos will trail application approval by approximately five business days. | -| Third-party platform | Open the **Cyber Verification Program page** and, under **Access** on **[Linked accounts](https://portal.anthropic.com/linked-accounts)**, turn on your approved access level for that platform profile. | +| Microsoft Foundry | For Microsoft Foundry, deploy a Claude model first.
If you have not already, sign in to the Verification Portal, open **[Linked accounts](https://portal.anthropic.com/linked-accounts)** and link your Azure subscription (you'll need the subscription ID and directory (tenant) ID). No further action: your approved access applies to every workspace.
If your organization has a committed contract with Anthropic, your account team will send you a short form to link this Azure account to your contract. Complete the form, then accept the private offer in Azure Marketplace so your contracted discount applies. Mythos access is provisioned once both steps are done.
Access to Mythos will trail application approval by approximately five business days. | +| Third-party platform | Open the **Cyber Verification Program page** and, under **Access** on **[Linked accounts](https://portal.anthropic.com/linked-accounts)**, turn on your approved access level for that platform profile. | ## Existing members diff --git a/content/support/15330088-set-a-default-model-for-your-organization.md b/content/support/15330088-set-a-default-model-for-your-organization.md index af189caf5e..bf548a347d 100644 --- a/content/support/15330088-set-a-default-model-for-your-organization.md +++ b/content/support/15330088-set-a-default-model-for-your-organization.md @@ -50,7 +50,7 @@ The organization default applies to every member. To set it: 4. Click “Save changes.” -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2514722139/d05c94072a41ea9090ecf386c53e/c32ee31d-954a-4551-a2da-91677fbd0b6f?expires=1793653200&signature=ca167b3ceb4ce785dfc62c008c9ab6188231f1c523fe47447747f53d36ce3a1d&req=diUmEs58n4BcUPMW1HO4zelOdjFGKEtFfdGVZ664dGFVJyvB0F5uqJnwlekN%0A6x2EFD9fTrJZ0t9%2B614%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2514722139/d05c94072a41ea9090ecf386c53e/c32ee31d-954a-4551-a2da-91677fbd0b6f?expires=1793691900&signature=94f17775a0e3131149e1ed1a5756b8c42050c24dca61c1cb848d74cdf7fd9cd5&req=diUmEs58n4BcUPMW1HO4zelOdjFGJElOfdGVZ664dGFzU15st97HnqqhhjFx%0AQiJfZIRleYRUWvbW1ZQ%3D%0A) --- diff --git a/content/support/15694740-manage-model-access-for-your-organization.md b/content/support/15694740-manage-model-access-for-your-organization.md index 03b72676c0..55ad16446a 100644 --- a/content/support/15694740-manage-model-access-for-your-organization.md +++ b/content/support/15694740-manage-model-access-for-your-organization.md @@ -42,9 +42,9 @@ The organization setting is the ceiling. A role can't grant access to a model th If any custom role uses the model you’re disabling as its default, you’ll be prompted to change that role’s default before the change can be saved. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2514693921/02ea72756f5163f14e5d158516dc/69102088-cd86-498e-97aa-c8a6e0004419?expires=1793653200&signature=30c4f3db67876358c84d8bbaab56e7900a15d28e05ed4f69c418ff58e93484f0&req=diUmEs93nohdWPMW1HO4zXlxE%2BS%2FUtJVQf5Pb7M2Q0vzIQY9uf5rCAYi%2Fum%2B%0AW1wzIRbzaTq6yjIg60s%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2514693921/02ea72756f5163f14e5d158516dc/69102088-cd86-498e-97aa-c8a6e0004419?expires=1793691900&signature=91dffac333d1b83f86710cef9590aaeeffad4359198cd88cf809e30069fd71d2&req=diUmEs93nohdWPMW1HO4zXlxE%2BS%2FXtBeQf5Pb7M2Q0v6wDAigj9kDX%2FnrkMS%0AwJJ%2BKjgHmvylPiODmYU%3D%0A) -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2514693922/bfc5de6626eb19dca1d7caf818ca/c3cd8bb6-f86c-4d01-92da-6ae4ca966662?expires=1793653200&signature=f2a4e16161d160ded1496956081053a65066ce5893c290218b4891430a85f84a&req=diUmEs93nohdW%2FMW1HO4zTqNsIrDQ1tVAod9uc510lwQq2X1rwuPAI%2ByVsyi%0AXQsp6%2BN2NOdbvi7mq20%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2514693922/bfc5de6626eb19dca1d7caf818ca/c3cd8bb6-f86c-4d01-92da-6ae4ca966662?expires=1793691900&signature=785b192cac3578f0ada2e99f04bb1f85f7e1b8b059f4fcccb676deb725d453aa&req=diUmEs93nohdW%2FMW1HO4zTqNsIrDT1leAod9uc510ly%2F%2Bfa1g%2BNn9woH1For%0A9QAJRCOaEjni85kLj9k%3D%0A) --- @@ -78,7 +78,7 @@ If any custom role has an effort cap higher than the new organization cap for th Only models the role grants access to can be selected as that role’s default model. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2514693923/880665a87dbd4776cf19d6063a37/29d30c6d-f9fc-408c-8c72-4320c6d88d14?expires=1793653200&signature=f4ca9a032b0777b3187f1d5ae2fd485dadf441dced2b11f56f700bd76cb80354&req=diUmEs93nohdWvMW1HO4zYj9SPYF6IK%2FXsqpNqvyFRI7zDTdQYhX2nv94Sum%0A1smerVQf4knbBntYHow%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2514693923/880665a87dbd4776cf19d6063a37/29d30c6d-f9fc-408c-8c72-4320c6d88d14?expires=1793691900&signature=768b09b1fc723e2648f18721f4640417bd776ba06da4248142eb01376e1845c1&req=diUmEs93nohdWvMW1HO4zYj9SPYF5IC0XsqpNqvyFRJ0btjYP1cApYq2Rltt%0AUwA7NCDrnl0A0cW2XFE%3D%0A) --- @@ -96,7 +96,7 @@ Effort limits determine how much computation members on a role can apply per res 5. Click "Save" to save your changes. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2514693927/7a25673b3b075d72adb3cdc371e3/d2d7cd8d-a713-4e91-a706-f589ac46a9fe?expires=1793653200&signature=376dd18864c18301f797e1b48af23f025b18f48df532cb3c7dd5d186ee07af60&req=diUmEs93nohdXvMW1HO4ze1xBzC6drobDeA1RkowXUFEEFkla505Wd8g51i5%0AE%2BhziXaL7JmaMDVcD%2B4%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2514693927/7a25673b3b075d72adb3cdc371e3/d2d7cd8d-a713-4e91-a706-f589ac46a9fe?expires=1793691900&signature=92bb97283cf2778c995348dbc5109df1eb03c6b32e399cfeac1b64d7ec8351e4&req=diUmEs93nohdXvMW1HO4ze1xBzC6ergQDeA1RkowXUG7yeIZCDwIKZDhlyDG%0AB6nXpwNpQP3%2FVb7Qof8%3D%0A) Members on the role see only effort levels at or below the cap in their model menu. Note that available effort levels differ depending on the model, and some models don’t support effort level settings at all. For an explanation of each level, see **[Change the model, effort, and thinking settings](https://support.claude.com/en/articles/8664678)**. diff --git a/content/support/15707726-using-claude-for-legal-work-privilege-confidentiality-and-how-to-think-about-configuration.md b/content/support/15707726-using-claude-for-legal-work-privilege-confidentiality-and-how-to-think-about-configuration.md index 49c4fd8f12..e8d9727bac 100644 --- a/content/support/15707726-using-claude-for-legal-work-privilege-confidentiality-and-how-to-think-about-configuration.md +++ b/content/support/15707726-using-claude-for-legal-work-privilege-confidentiality-and-how-to-think-about-configuration.md @@ -24,9 +24,9 @@ There are two questions worth separating: *what does Anthropic see*, and *what p On the first—our **[Trust Center](https://trust.anthropic.com/)** and our **[data retention practices article](https://support.claude.com/en/articles/15425996)** cover the details, but in short: -- **We do not train on your content by default.** Under our commercial terms, **[by default](https://privacy.claude.com/en/articles/7996868-is-my-data-used-for-model-training)**, customer content from Claude for Work, the Claude Platform, and the API is not used to train our models. +- **We do not train on your content by default.** Under our commercial terms, **[by default](https://privacy.claude.com/en/articles/7996868-is-my-data-used-for-model-training)**, customer content from Team and Enterprise plans, the Claude Platform, and the API is not used to train our models. -- **Retention is configurable.** **[Claude for Work](https://support.claude.com/en/articles/10440198-configure-custom-data-retention-controls-for-enterprise-plans)** administrators can set an organization-wide retention period. **[API](https://privacy.claude.com/en/articles/7996866-how-long-do-you-store-my-organization-s-data)** customers can use our standard 30-day retention or, on eligible endpoints and models, **[Zero Data Retention](https://privacy.claude.com/en/articles/8956058-i-have-a-zero-data-retention-agreement-with-anthropic-what-products-does-it-apply-to)**. For our most **[capable models](https://support.claude.com/en/articles/15425996-data-retention-practices-for-mythos-class-models)**, where safety monitoring requires it, we retain prompts and outputs for 30 days in a governed store that is automatically deleted, with the serving path itself stateless. +- **Retention is configurable.** **[Enterprise plan](https://support.claude.com/en/articles/10440198-configure-custom-data-retention-controls-for-enterprise-plans)** Primary Owners and Owners can set an organization-wide retention period. **[API](https://privacy.claude.com/en/articles/7996866-how-long-do-you-store-my-organization-s-data)** customers can use our standard 30-day retention or, on eligible endpoints and models, **[Zero Data Retention](https://privacy.claude.com/en/articles/8956058-i-have-a-zero-data-retention-agreement-with-anthropic-what-products-does-it-apply-to)**. For our most **[capable models](https://support.claude.com/en/articles/15425996-data-retention-practices-for-mythos-class-models)**, where safety monitoring requires it, we retain prompts and outputs for 30 days in a governed store that is automatically deleted, with the serving path itself stateless. - **Human review is a very narrow exception.** Retained data is processed by automated safety systems for potential harm only. Only content flagged by the automated safety system can be reached by a human reviewer. When content is flagged for potential serious harm, review is performed by a small, designated set of safeguards personnel under contractual confidentiality, with need-to-know scoping and two-person approval for regulated data categories. diff --git a/content/support/15936181-get-started-with-1password-for-claude.md b/content/support/15936181-get-started-with-1password-for-claude.md index 7d771a8d8e..33f20070ca 100644 --- a/content/support/15936181-get-started-with-1password-for-claude.md +++ b/content/support/15936181-get-started-with-1password-for-claude.md @@ -52,7 +52,7 @@ Once the requirements are in place, you can set up 1Password from a few places i 4. Toggle on **Password managers**: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2546126596/ba71ca47e2df21cec62c243831f8/5b1c67e1-607d-4c73-8f61-d1ceb081082a?expires=1793653200&signature=93682298b8b43df253d109a339d23c5fef9320d8821b481f017ed8a582e97c04&req=diUjEMh8m4RWX%2FMW1HO4zU5ln2hoqMZhGkiu4hEpcPVpyOlf%2F9gct4GFOpLu%0A4eTZc%2FjVk9ZkFvGz6EM%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2546126596/ba71ca47e2df21cec62c243831f8/5b1c67e1-607d-4c73-8f61-d1ceb081082a?expires=1793691900&signature=806920283e7c07f2df3e8158159b6ae6e83dbad7188ad2a16415eeae8273a352&req=diUjEMh8m4RWX%2FMW1HO4zU5ln2hopMRqGkiu4hEpcPUgbeca4KJLgmMySY7F%0ANLoR24nR1ovrYUwyrwI%3D%0A) Once enabled, eligible users will see the discovery options above. Users still need to install and set up the required apps and extensions themselves. diff --git a/content/support/16607638-understanding-your-pro-max-or-ultra-plan-invoices.md b/content/support/16607638-understanding-your-pro-max-or-ultra-plan-invoices.md index 554cb43301..ab0de2f22f 100644 --- a/content/support/16607638-understanding-your-pro-max-or-ultra-plan-invoices.md +++ b/content/support/16607638-understanding-your-pro-max-or-ultra-plan-invoices.md @@ -40,7 +40,7 @@ You can also open any invoice from your account: **Amount due.** The invoice total minus any applied balance. This is what your payment method was charged. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2629072970/c514f489b65072ccad08e803864f/e8c7a7de-905f-4a40-815f-c9c66edcdbf6?expires=1793653200&signature=63fac4e0b9b4f17f401e81715f7a9e65eedb8636ea4bfa51ab874f3d4a3075eb&req=diYlH8l5n4hYWfMW1HO4zdWraRI561ccPZYKVlMiWEW%2BDmbEs8x96kaEnq19%0Acl%2BskiZMPOgQiF1aCLM%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2629072970/c514f489b65072ccad08e803864f/e8c7a7de-905f-4a40-815f-c9c66edcdbf6?expires=1793691900&signature=f4d468ff4c5d948032ffd7549b20b55e9fca4df92ba386cd6acf3bfc37b120f6&req=diYlH8l5n4hYWfMW1HO4zdWraRI551UXPZYKVlMiWEXSERDBP5X1eJaV%2BZe8%0AofbH3KQCvMsPDd3gGAQ%3D%0A) ## Billing details on your invoice diff --git a/content/support/16893491-get-started-with-smart-reports.md b/content/support/16893491-get-started-with-smart-reports.md index 072710fc5b..958af8176c 100644 --- a/content/support/16893491-get-started-with-smart-reports.md +++ b/content/support/16893491-get-started-with-smart-reports.md @@ -28,13 +28,13 @@ Each report includes the following sections: Workstreams shows what the group used Claude for most, by sessions and by spend, side by side. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2671030907/7b62b605189fe8e9474a20c1eaf2/image.png?expires=1793653200&signature=5c979446ac2f78875f6db5b87259c796f48f2374b4dcea726bcf057fefbb966d&req=diYgF8l9nYhfXvMW1HO4zZse%2BmGaTgsOVa%2FWhnGS4Gk91SfID%2BuG2jRO26nJ%0AOwDQiyPfXiMNgNXiz5Y%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2671030907/7b62b605189fe8e9474a20c1eaf2/image.png?expires=1793691900&signature=8671016f1f73ed638e8ca59bfa04565ff4c74cf05f574b9b0cf508b08e451975&req=diYgF8l9nYhfXvMW1HO4zZse%2BmGaQgkFVa%2FWhnGS4GlznuU5bQ7gaQ5hfs9%2F%0APyvttI8l6%2BVmDAjbDs0%3D%0A) ### Deliverables produced Deliverables produced groups sessions by the type of output that was produced. For example, analysis, documentation, content drafts, and code. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2671035220/2a582bc047a6ba46e7dbd6f05d9f/e17881ac-874c-4747-94ca-8679e0301455?expires=1793653200&signature=a9ca3058ac230b5cbc7422afc35c984a648da56a08301ccd09efbf9bd4df3e20&req=diYgF8l9mINdWfMW1HO4zelj06Rdlt7wYDEFlKbF9Y%2FUme1%2B9gc3BgwRHLCf%0AK9kq9785RNsG0Mkn%2BKQ%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2671035220/2a582bc047a6ba46e7dbd6f05d9f/e17881ac-874c-4747-94ca-8679e0301455?expires=1793691900&signature=3655cddebe01082428bf3ce677b8abefba1513e9b984ab113614d1a9e4bb23bf&req=diYgF8l9mINdWfMW1HO4zelj06Rdmtz7YDEFlKbF9Y8p0kkv9cRmKcMSDENb%0A%2FxoUSCHrFhGd8pJcPyw%3D%0A) ### Cost per session by type of output @@ -48,23 +48,23 @@ Task outcomes shows what each session produced. Most common pain points shows what got in the way, by category. For example, a connector that wasn’t set up, output that didn’t match the ask, approval or sign-in gating, tool failures, or rework loops. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2671052365/b69f22b75729e5587563e7ab6830/b1647659-a7ea-403b-89fc-0b150ee97675?expires=1793653200&signature=1bb8e1d4178b64d4c73ead194d77fdc957ad937a542ac56784ce512d24d30b4e&req=diYgF8l7n4JZXPMW1HO4zdDitrkzUd5TjFK5P3Uf7RhMAQmfZxYey2cC%2Fb8r%0AhqSgcNPcQ6xP7U8PVXE%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2671052365/b69f22b75729e5587563e7ab6830/b1647659-a7ea-403b-89fc-0b150ee97675?expires=1793691900&signature=9533e585243df63ffd179c5f6163c1786a70fafe99880464158d48ae314f86c5&req=diYgF8l7n4JZXPMW1HO4zdDitrkzXdxYjFK5P3Uf7RgBMLnuQCT3ooCHvTjA%0A7WBfKseltarJiWrDoFw%3D%0A) Click into a category to see more information: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2671053199/b68936dd5d590c5fbcbbc092b332/5ec247b2-cd67-4f3f-97b5-23479b87a5c6?expires=1793653200&signature=e8598d322e709372ce5e6abae3b52b48361a8636bb2409874e10319cef1d232e&req=diYgF8l7noBWUPMW1HO4zbuGO4guI7oeodOVMLl17PWdI8Yk1anhGGBVOJrF%0ARAWJCdIEnlbw2iqiNeo%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2671053199/b68936dd5d590c5fbcbbc092b332/5ec247b2-cd67-4f3f-97b5-23479b87a5c6?expires=1793691900&signature=f5affb66ee945d7bb37d1c761738b485c4fd19c952f8f201a7e74450f020cbd2&req=diYgF8l7noBWUPMW1HO4zbuGO4guL7gVodOVMLl17PXcqCPW9epwS%2Fjt%2BiNa%0AXLym6I3MchHClfhEFW8%3D%0A) ### Inefficiencies Inefficiencies counts sessions that produced nothing usable and sessions that were personal or off-topic, with their cost (shown only as an aggregate count and cost, with no summaries or drilldown). -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2671036122/90dc848a7adf371a872bd89a2f5e/de86945b-ccfe-4e0f-892d-abacc475c5c4?expires=1793653200&signature=68a4b11912ff7243773d32331cb062c2d7750851771bb7bacf966887aeb390a8&req=diYgF8l9m4BdW%2FMW1HO4zcYfhgyQCPcYBas8rgXn%2Fb1NoECsmVZR8VcpQDnw%0A7GANv%2FXBWJY2WGY2yCA%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2671036122/90dc848a7adf371a872bd89a2f5e/de86945b-ccfe-4e0f-892d-abacc475c5c4?expires=1793691900&signature=1fb9ff041246c7cc2d7832561c0d0a2ee48dd1d2e9c08dc0c55def8a4d575832&req=diYgF8l9m4BdW%2FMW1HO4zcYfhgyQBPUTBas8rgXn%2Fb2LI7tjNMeP5ruaxhBG%0APz9Owy7EPH%2Bh%2FLJezSg%3D%0A) ### Complex, autonomous work Complex, autonomous work shows sessions scoring highest on task complexity, time saved, how long Claude worked on its own, and the expertise required. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2771304819/746adaaa5ae3196304f0af43cbdd/image.png?expires=1793653200&signature=736da3e0c622c62e74d064c8f6a0bd73a9cd94bfa02a04887bad492eddf38c96&req=dicgF8p%2BmYleUPMW1HO4zRKi0HWFiE1khdMrWDTaChVWkhlYrUNUuioBG9Bx%0Ap3LwSGevSnrupTvX5bk%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2771304819/746adaaa5ae3196304f0af43cbdd/image.png?expires=1793691900&signature=ae087391ba1784cf4e4be461ad64d93a1c85d1a2681e164e41a04144b8d25209&req=dicgF8p%2BmYleUPMW1HO4zRKi0HWFhE9vhdMrWDTaChUcJ1C7Yw2tZOpqdhLp%0ARuT9rI%2FCk2Z2psSA73Q%3D%0A) ### New to the organization @@ -78,7 +78,7 @@ This section shows work that people have automated for themselves. Most expensive sessions lists where spend concentrates. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2671032083/2b075387a4a3473f884a8ba26436/image.png?expires=1793653200&signature=9697456587f423c1a57f7154b08cd38d5b08e035e67f6b54904166a57d527b35&req=diYgF8l9n4FXWvMW1HO4zdLkImyj70UrnUoxuhUXEhg0ViONpS6Pc%2FtAEMUf%0AGr0D4W%2Fw5IGgepsmDnc%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2671032083/2b075387a4a3473f884a8ba26436/image.png?expires=1793691900&signature=0950af4b95716b75829b268c02b110b7cd4d3a15d37f24bdc3989e3e46f85eb5&req=diYgF8l9n4FXWvMW1HO4zdLkImyj40cgnUoxuhUXEhj%2BtwJVVyN4E6cyBYLY%0A8aLCqIVyn1DbLAVs%2Bmo%3D%0A) ### Answers to custom questions diff --git a/content/support/16951679-use-claude-in-google-docs-sheets-and-slides.md b/content/support/16951679-use-claude-in-google-docs-sheets-and-slides.md index f7dbfe2ab4..65e12a7012 100644 --- a/content/support/16951679-use-claude-in-google-docs-sheets-and-slides.md +++ b/content/support/16951679-use-claude-in-google-docs-sheets-and-slides.md @@ -28,11 +28,11 @@ If your organization already allows Marketplace apps, this takes about two minut 2. Open a Google Docs, Sheets, or Slides file and go to Extensions > Claude > “Open Claude": -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2707281468/abc0497defca04936c9a4b97d147/8b17d05f-3fb1-4e49-8d1f-65364ac3f496?expires=1793653200&signature=2792a73755e3ddc1ff765f4886beee923b86d1f079008b833d38d4db67c79f34&req=dicnEct2nIVZUfMW1HO4zRwmJT9qUedNaAKM49NdBLM3vmT34UdXzy4GMOa6%0Aqecb%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2707281468/abc0497defca04936c9a4b97d147/8b17d05f-3fb1-4e49-8d1f-65364ac3f496?expires=1793691900&signature=293e42afc499f23b8cbe606dcaa58cfee0e38a4f833143bfdb735c7a514a2283&req=dicnEct2nIVZUfMW1HO4zRwmJT9qXeVGaAKM49NdBLPft34deNfuUcmhIDPV%0ANe3A%0A) 3. The first time, Google asks you to allow two permissions. Review them and click "Allow": - ![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2707282342/f583a396098ff16e3cbd156d4a2a/112c6459-79c6-4fbb-9bc0-748fda6f592f?expires=1793653200&signature=7a66381745fcabd143e64967b60a553fededef601aa5dce0cc1b0d2d3ca021fc&req=dicnEct2n4JbW%2FMW1HO4zeKY3p8AhQ3yeBfHlrCfDWcnID3CIoGqSbpJrghG%0AxGNZ%0A) + ![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2707282342/f583a396098ff16e3cbd156d4a2a/112c6459-79c6-4fbb-9bc0-748fda6f592f?expires=1793691900&signature=e291ca77b74a74af61719e7ec5c2c3fffb30509498e55ff7ba8a85106fada188&req=dicnEct2n4JbW%2FMW1HO4zeKY3p8AiQ%2F5eBfHlrCfDWcJ3ER%2F39KVeuhPBYBX%0Akg09%0A) 4. Sign in with your Claude account in the sidebar, and optionally enable your connectors. diff --git a/content/support/17005973-manage-pooled-group-budgets-on-enterprise-plans.md b/content/support/17005973-manage-pooled-group-budgets-on-enterprise-plans.md index bfed38eeba..64920c2366 100644 --- a/content/support/17005973-manage-pooled-group-budgets-on-enterprise-plans.md +++ b/content/support/17005973-manage-pooled-group-budgets-on-enterprise-plans.md @@ -80,7 +80,7 @@ If a user belongs to more than one group with a pooled budget, the largest poole With a custom order, the first pooled budget in your list with budget remaining pays. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2719736736/a4ec8e92af4975a87891357e5dbd/6f58b496-432d-4069-ba18-72a6390ab2ea?expires=1793653200&signature=2ab24020d4d657ff0072767d0fe2204a925ccd2be15d852c15db372a6e77efee&req=dicmH859m4ZcX%2FMW1HO4zU9wBwceVIsxTLR6JppsyjT8hqxDkiTDTUbz%2Bld2%0A8iTVb3qQUVphfw2vIiA%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2719736736/a4ec8e92af4975a87891357e5dbd/6f58b496-432d-4069-ba18-72a6390ab2ea?expires=1793691900&signature=aca815244f2e3729e5a1f8d45ee52811d4e2aded4b76b8c4a16389cb2c05fa02&req=dicmH859m4ZcX%2FMW1HO4zU9wBwceWIk6TLR6JppsyjSU7YSUxHnggcbTovXT%0AP2HiOFhl%2FcyFkxH1C5I%3D%0A) **Note:** Budget priority only decides the order in which pooled budgets pay. To choose which group's member monthly limit applies to a user in more than one group, use the **Member limit from groups** setting under **Spending defaults**. diff --git a/content/support/17203415-set-up-claude-for-intune.md b/content/support/17203415-set-up-claude-for-intune.md index a1561d7846..3f0cac974e 100644 --- a/content/support/17203415-set-up-claude-for-intune.md +++ b/content/support/17203415-set-up-claude-for-intune.md @@ -70,25 +70,25 @@ To add Claude for Intune for enrolled company-owned devices: 1. In the Microsoft Intune admin center, select "Apps" from the left side navigation panel: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700192269/ce2bf95a18aba11042da50f4c1ad/dda0f9a2-d585-4b09-ae4f-a1ff70b1e010?expires=1793653200&signature=1c9ed2151b0928f5a98b1a899c17c9c7305aa6a98f3c7d9d8a314d54ec9e45cb&req=dicnFsh3n4NZUPMW1HO4ze7khjLX52hiAMLV2Uu0R4UhaiZ9uCMDnHwpWz69%0ABbeh%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700192269/ce2bf95a18aba11042da50f4c1ad/dda0f9a2-d585-4b09-ae4f-a1ff70b1e010?expires=1793691900&signature=23dcda05267e8689def8ad7b907bf43961d5cf570657ff030fa6fe6fb85f7439&req=dicnFsh3n4NZUPMW1HO4ze7khjLX62ppAMLV2Uu0R4WFWLvRJNH0W8XchoPs%0Arpay%0A) 2. Under Platforms, select "iOS/iPadOS": -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700195036/b70c6c0bdeff5f2b72568ef4943b/67cc834c-5e91-42da-9d3b-1f32c8dd8c05?expires=1793653200&signature=48f1c0bb8385645218e2d97cba005a02917c3c38ca6ceaf12b55032919d2af2c&req=dicnFsh3mIFcX%2FMW1HO4zeH1oU7htHCWQ7hR7Wh%2Bi73yZVuUJKd4NyGCwBOr%0AF8o1%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700195036/b70c6c0bdeff5f2b72568ef4943b/67cc834c-5e91-42da-9d3b-1f32c8dd8c05?expires=1793691900&signature=cb635a02c866886d163504f20ae77479287eae1b3f77d6632097eed5ea033f81&req=dicnFsh3mIFcX%2FMW1HO4zeH1oU7huHKdQ7hR7Wh%2Bi73KtVi51LA9mI7oN%2FIr%0AHH%2FE%0A) 3. Click "+ Create." For the App type, select the "iOS store app," and click the "Select" button on the bottom: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700195791/9a01290b4189e6a39c473af0a448/cfed06da-f35a-4b22-b687-286ea48864c1?expires=1793653200&signature=1d3dce7f33273fae58d4c48bec2fc05093e35c2f92acd7fd7c25c90bf60e0943&req=dicnFsh3mIZWWPMW1HO4zTni3cUvZ50u2SRx6amjj9HMKjLuNFGQHhNsbEcD%0AbOay%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700195791/9a01290b4189e6a39c473af0a448/cfed06da-f35a-4b22-b687-286ea48864c1?expires=1793691900&signature=fa169a63f18c39743794a76479edef1b1506aa26bb87fb452b20a3e906aef23e&req=dicnFsh3mIZWWPMW1HO4zTni3cUva58l2SRx6amjj9FbsNpEeTdUnlIqQSiW%0AJbzf%0A) 4. Search "Claude for Intune" and click the "Select" button on the bottom. 5. In **App Information**, set **Minimum operating system** to iOS 18, then click the "Next" button: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700196458/588327ab209e9524c45111a244a1/258697c2-2f82-471b-9104-2bccb1b01614?expires=1793653200&signature=cd6830eb2260c327158e72870afcb86ae8f5890c4e909cef4248c1fb35c1e29c&req=dicnFsh3m4VaUfMW1HO4zbxl5YtRcjEsDNNSLAHCCFqLi4asXWaPY9PqQU2R%0Aedmy%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700196458/588327ab209e9524c45111a244a1/258697c2-2f82-471b-9104-2bccb1b01614?expires=1793691900&signature=4bdd27a3a7eaa85aeafdb13ce17aaf79df322b1c22957133117ba6a261efcc69&req=dicnFsh3m4VaUfMW1HO4zbxl5YtRfjMnDNNSLAHCCFqAg4Pjg2cqfxQpwmwx%0A%2FaBq%0A) 6. For **Assignments**, add the groups that should get the app: under Required to install it automatically, or under Available for enrolled devices so employees can install it from Company Portal. You can use user groups or device groups. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2741107114/8f15b0d179a54c2ca4effaad8577/55bed25a-4b20-47b0-9e89-7f8adc86c04f?expires=1793653200&signature=311690698ede5fd733d2e5d382b55f1fb8122aa92b9559e73b7dac423d6a10f0&req=dicjF8h%2BmoBeXfMW1HO4zYaZMeu6fPCcmN%2B6UXepdg8SBNFmPKRBIKvH3Rl8%0AXyfV%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2741107114/8f15b0d179a54c2ca4effaad8577/55bed25a-4b20-47b0-9e89-7f8adc86c04f?expires=1793691900&signature=102025d55cfdb789cf8caa3812942813ec7a278e246324ae998d8fc7854cfb41&req=dicjF8h%2BmoBeXfMW1HO4zYaZMeu6cPKXmN%2B6UXepdg%2FEpuLkF4mBv09378IM%0Ay1CP%0A) 7. Click "Next," review and create. @@ -98,27 +98,27 @@ To add Claude for Intune for enrolled company-owned devices: 1. In the Microsoft Intune admin center, select "Apps" from the left side navigation panel: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700190760/9f6412fe68632cffee29826f7d30/42fdeb30-64af-4089-a976-5094bb6b8292?expires=1793653200&signature=97ecc9583a990da8e69cb3ba3b9237500c54a7ab6ec5c914d3e59000a25f1688&req=dicnFsh3nYZZWfMW1HO4zQwrZIkEVtE%2BLtTCoSp4D6r6zBrSYfijmeZfUJUp%0At0NO%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700190760/9f6412fe68632cffee29826f7d30/42fdeb30-64af-4089-a976-5094bb6b8292?expires=1793691900&signature=fa31a3bc80a03363195b6433e5efde798a9f8c1ba20da596695e0ab3ae9a6541&req=dicnFsh3nYZZWfMW1HO4zQwrZIkEWtM1LtTCoSp4D6r8lWhmdwzBZ8GfhGGl%0AAHYp%0A) 2. Under **Manage apps**, select "Protection": -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700200858/a7ddd4265aeb6d61a7a096297cd5/fc9a1fe2-3d0e-4038-9b2c-f96bd19e4020?expires=1793653200&signature=dfb8361c41b78706ebb7bec00683225cbc1f06e8536dc180e9902e6afd10320e&req=dicnFst%2BnYlaUfMW1HO4zeBHXBw78P7vnJWY0xu8hzI3%2FcokjQsbhiJvMt0d%0Ab4EK%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700200858/a7ddd4265aeb6d61a7a096297cd5/fc9a1fe2-3d0e-4038-9b2c-f96bd19e4020?expires=1793691900&signature=15ad02afce6acdb3607d86405b04818babd67d3c8e8e8b675755c19a94b60548&req=dicnFst%2BnYlaUfMW1HO4zeBHXBw7%2FPzknJWY0xu8hzLKrjAuxKD%2BMvbJMH%2Bf%0A7gBG%0A) 3. Click "+ Create" and then select "iOS/iPadOS": -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700201382/6240e257b2b498b5fa5ac1111561/11ef4f59-aba1-4d2b-ac58-9aec1dd60a4d?expires=1793653200&signature=6f81613573d6caf57286bcca93128af3e34d693871b79a9afa324acc13a52b28&req=dicnFst%2BnIJXW%2FMW1HO4zc89y0hQB3lMV2VWh%2B9zzEomM%2BVrY%2FLaJm49ExAg%0AIyrv%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700201382/6240e257b2b498b5fa5ac1111561/11ef4f59-aba1-4d2b-ac58-9aec1dd60a4d?expires=1793691900&signature=9bcdfbb16edc2a5caa9757861220d47c35b1286c94290f7bb5961a75431fafb4&req=dicnFst%2BnIJXW%2FMW1HO4zc89y0hQC3tHV2VWh%2B9zzEqrHn4c9N%2FVK0r1gRZt%0AL8Fn%0A) 4. Enter Name in the **Basics** tab, then click "Next" to **Apps**. Set **Target policy to** "Selected apps." Click "+ Select custom apps": -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700201929/2edf45cedc0bc03204f86d01a49e/4d96c12d-962b-43f6-8b3f-668e3247d4c1?expires=1793653200&signature=e4dcf9f879618f3fa022b4648ce3cb52a7a548cb6cca56badf068495013b3095&req=dicnFst%2BnIhdUPMW1HO4zVmMRJISVj4KKETwku7gMsuvVXse63GNk91Nk0I%2F%0A8O6g%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700201929/2edf45cedc0bc03204f86d01a49e/4d96c12d-962b-43f6-8b3f-668e3247d4c1?expires=1793691900&signature=758286f86a5b48fc31a57a800e717e279de4a50efa880b431e97ca61c2465333&req=dicnFst%2BnIhdUPMW1HO4zVmMRJISWjwBKETwku7gMssgtAPz2RZSNEaTAQwh%0AKhDN%0A) 5. Type in the bundle ID `com.anthropic.claudeforintune`. Select it so it appears under **Selected Apps** before clicking "Select": -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700202816/3565aea2d1b9c22a5f8d105825c5/3de6d241-6259-463e-a503-a6ca9f2095e0?expires=1793653200&signature=646bf8b8faf16f7ffaa1442b651371c08ff2e729ab0a0d5612cad02e3e878e42&req=dicnFst%2Bn4leX%2FMW1HO4zf6tYiAuzal112LT9vQL0W5eeRfbIXolchKeDWh8%0AyHqH%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700202816/3565aea2d1b9c22a5f8d105825c5/3de6d241-6259-463e-a503-a6ca9f2095e0?expires=1793691900&signature=3e592a04aeb465be4065c1f9c7ab2a9d515ed26154127ca106a1cf9c4285377d&req=dicnFst%2Bn4leX%2FMW1HO4zf6tYiAuwat%2B12LT9vQL0W4lo2kZrTZxbMLb6rk%2F%0AjLY7%0A) 6. In Apps, confirm the bundle ID now appears under **Custom apps** before clicking "Next": -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700203780/24ed354ef0de87bf0a0c1bc129a1/46eed662-f488-48ee-a4d1-8a9a76079884?expires=1793653200&signature=17f961884fbe0c65eea24fd92f04e113e9346ffc96b01a5847b5a78ff6c6a02a&req=dicnFst%2BnoZXWfMW1HO4zQd95NaM3svd8F6Cfy2R7u%2F5%2BDXHvzz2qSus8vRH%0Avy2N%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2700203780/24ed354ef0de87bf0a0c1bc129a1/46eed662-f488-48ee-a4d1-8a9a76079884?expires=1793691900&signature=a8baf3ec462bc32195382305aa512ad0f504b0d073c1fca5adf099745c3c0cce&req=dicnFst%2BnoZXWfMW1HO4zQd95NaM0snW8F6Cfy2R7u9eLwMrL3BlDxBHs4fW%0AqWXb%0A) 7. Configure the Data protection, Access requirements, and Conditional launch settings as needed. diff --git a/content/support/8114491-get-started-with-claude.md b/content/support/8114491-get-started-with-claude.md index 2b18ff06f5..f3df44d313 100644 --- a/content/support/8114491-get-started-with-claude.md +++ b/content/support/8114491-get-started-with-claude.md @@ -36,7 +36,7 @@ You use **prompts** to communicate with Claude. The best approach is to speak to Type your prompt into the chat interface and click the submit button to start a conversation with Claude. You can click the "+" button in the lower left or type "/" to view additional options and commands: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1916208578/2cf2ea52f1f884084b57983a8805/image.png?expires=1793653200&signature=46a4c596da8b4a26fc27cd5237a1cbe7a7dec21111029e13f8349fbc8d71fd47&req=dSkmEMt%2BlYRYUfMW1HO4zV2J7CzMsYSD9crMELaMZPzHZ0h9FYT4oFyYxxCT%0AjUZTADUQFlOR0EPSRuc%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1916208578/2cf2ea52f1f884084b57983a8805/image.png?expires=1793691900&signature=f30490a30e68b0050b30c0a4fcf85ee29f1a9bc8ae4c58e2a8aa9527ebe73df2&req=dSkmEMt%2BlYRYUfMW1HO4zV2J7CzMvYaI9crMELaMZPw5NDRVbbgsAj7hdmEw%0Ae5Ex5WVQIJCJLb4NUBo%3D%0A) --- diff --git a/content/support/8230524-delete-or-rename-a-conversation.md b/content/support/8230524-delete-or-rename-a-conversation.md index 69fb7a7d85..312556e1a4 100644 --- a/content/support/8230524-delete-or-rename-a-conversation.md +++ b/content/support/8230524-delete-or-rename-a-conversation.md @@ -44,15 +44,15 @@ These steps apply to Claude for iOS, listed on the App Store as Claude by Anthro 4. If deleting, tap "Delete" again in the confirmation prompt. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2599501318/75c28edc693efbe8befd21e4da64/d18a921a-df4b-4788-833c-12c966a32527?expires=1793653200&signature=f9404a905ea97a8d6eabf24a29239d113f6183e34d45975d8b82ebd28ea67cfc&req=diUuH8x%2BnIJeUfMW1HO4zSc12K1cjWOp1DBI29QsIlE4utxoFP3RgJ0iJR%2BM%0Ab0IltLdvm8lCF1dztBg%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2599501318/75c28edc693efbe8befd21e4da64/d18a921a-df4b-4788-833c-12c966a32527?expires=1793691900&signature=d7d0e7edb6ce3ad2f865a71ffb848c6deda4de12f5841cdbad5dfe9e85189bf5&req=diUuH8x%2BnIJeUfMW1HO4zSc12K1cgWGi1DBI29QsIlEOxxavXJiYkrxmhJTi%0A%2BYDQJr8reZY6rxVMDYc%3D%0A) -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2599493852/2e58b92d18f307bb79ae30650f26/1bbe52f3-202b-4d5d-9f9a-eeda4d6952c3?expires=1793653200&signature=792379712b3aaaab9aa496ea515d80246a20590227b0c1a2a567310f51d40721&req=diUuH813nolaW%2FMW1HO4zTjXM%2BSKK8Pnj7blKEDtUI1YeiSerySgu27CwLC7%0Aq4DGA%2B6rFpS1dem%2B%2B4o%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2599493852/2e58b92d18f307bb79ae30650f26/1bbe52f3-202b-4d5d-9f9a-eeda4d6952c3?expires=1793691900&signature=5e86297a67834437d5a350fb60d2791ef63e286ad324a8b8a22da56624a60575&req=diUuH813nolaW%2FMW1HO4zTjXM%2BSKJ8Hsj7blKEDtUI1NDfo1nAhh3k59UYnr%0AdItFy2vcwouxcM2ULVE%3D%0A) You can also delete the conversation you have open: tap the "⋯" button in the top right corner, tap "Delete," then confirm. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2599493848/997184c386d0e6fb0bd2d7c1f2b6/5d2bc394-25fc-4814-8c2a-2f54d004f83f?expires=1793653200&signature=2c19dc8fce008efe5649baa1b9ae2bd168b4958ac58acae9e4de99339d80d84e&req=diUuH813nolbUfMW1HO4zVCIq5nJzt9EzQl%2BKgU984x28NkN6w2m6ftfSYml%0AqJ%2B3Dbw2k7cn9wGzbjM%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2599493848/997184c386d0e6fb0bd2d7c1f2b6/5d2bc394-25fc-4814-8c2a-2f54d004f83f?expires=1793691900&signature=7ca449f5db431f6c899878323f32c8eef9bf72a856951681a915d3eb4a68388b&req=diUuH813nolbUfMW1HO4zVCIq5nJwt1PzQl%2BKgU984xK46n7Rv4CPwSSNGDr%0AQljcxEoHlnqK96MWCJM%3D%0A) -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2599493856/799041da9fa918e90068c5ebf5bd/2e8d5cee-c45a-41d7-a14b-486e50a37f88?expires=1793653200&signature=17344debb802ce9c3f6cd950eabbacbba9d3807399dbc97f5b6575cfbf63a637&req=diUuH813nolaX%2FMW1HO4zVCl4Qv01GZPEDIU8RT6jk04UxrJ%2FcZXvNB%2FhtYv%0AFLuGM6IfL1jcBbMmQUI%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2599493856/799041da9fa918e90068c5ebf5bd/2e8d5cee-c45a-41d7-a14b-486e50a37f88?expires=1793691900&signature=9dae672bcd013b5ed7f93db99e7b0f4b31087fc457bfedf95d45d4484b031a6f&req=diUuH813nolaX%2FMW1HO4zVCl4Qv02GREEDIU8RT6jk0EXIeOhbqAxW0n5xOk%0AK%2B%2BsOaUxpOoQIzkKDC4%3D%0A) ## Delete or rename a conversation on Claude for Android @@ -66,9 +66,9 @@ These steps apply to the Claude for Android, listed on Google Play as Claude by 3. If deleting, tap "Delete" again in the confirmation prompt. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2599493850/a64e6561222d535f2f5bd03e71f0/5de429c2-d8ed-4e8a-89e8-a13ccaa49767?expires=1793653200&signature=a9b6e786e4b42dbafeee9bec35fab7c8d95e57f7488535834d980cc72d39eb21&req=diUuH813nolaWfMW1HO4zVTddtEqx1N3rqtc0YNNUtKN7g3jIY7JRrwYlsfE%0AP53%2Br71flnyLt%2B%2Fj9HQ%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2599493850/a64e6561222d535f2f5bd03e71f0/5de429c2-d8ed-4e8a-89e8-a13ccaa49767?expires=1793691900&signature=db73c5997fdda5bdab7a0a1a1f5b1271e58ae91d521b866f611947d21646771b&req=diUuH813nolaWfMW1HO4zVTddtEqy1F8rqtc0YNNUtIAKVXj%2FeCgn0xCLvQE%0ANR6CwF5RzAz5clXr27s%3D%0A) -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2599493851/f21b39c60e88050d4b0745325f0d/0a8c0d08-dc53-4ef1-8d9f-2b995242c1f9?expires=1793653200&signature=4bb6e034bf35a41653563f45faf2babbb4ab19f92ec486a72f07bc79f316fa85&req=diUuH813nolaWPMW1HO4zUYvwlYNpz1e%2FjekULCQNzXSF94jdq7yphwrTLX8%0AxJLIOawpH2wArp%2B2jEw%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2599493851/f21b39c60e88050d4b0745325f0d/0a8c0d08-dc53-4ef1-8d9f-2b995242c1f9?expires=1793691900&signature=c97d2d2e1c0e53523dc5ff0c38d4e2596cbdf96c17bb7571f57a11a6a37f5941&req=diUuH813nolaWPMW1HO4zUYvwlYNqz9V%2FjekULCQNzWc%2BAoEqgPxpRbSbAbf%0AubMd9v3xsoIEeRSkCF4%3D%0A) **To delete multiple conversations at once:** @@ -78,9 +78,9 @@ These steps apply to the Claude for Android, listed on Google Play as Claude by 3. Tap the trash icon, then tap "Delete" in the confirmation prompt. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2599493849/3013a0ab921337b4544f7ffeffa6/e828ec14-fb52-4205-a840-707b6f2a848d?expires=1793653200&signature=4e69b542a4e0010bf8382da22bc653ac0cbfbdc31c48d1eddb289767f0f81c66&req=diUuH813nolbUPMW1HO4zWGamcRyf47d4AqhTnZa84UQBECG9%2Bt3FaeyXoDr%0AwGvswSZakK55KNcZxnw%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2599493849/3013a0ab921337b4544f7ffeffa6/e828ec14-fb52-4205-a840-707b6f2a848d?expires=1793691900&signature=f075b6f64aa14052d55c5d9c8afb5034ea5b6662e745fdc2db27bf8d5192bfee&req=diUuH813nolbUPMW1HO4zWGamcRyc4zW4AqhTnZa84Uiho65bjCIRU5sli6T%0A3nvy6w9esrrLxRhZnFU%3D%0A) -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2599493853/e2507f53cce8a26776a22a457b1a/bd79bb8a-b078-420f-a4e1-75590367aa80?expires=1793653200&signature=13c301c2beec43b286db596ec84586543f7c1f3bb89475da541564e0cfb03b4a&req=diUuH813nolaWvMW1HO4zQTtEhb3wUM6SBGfF3I2bRiVIJa5dnY0BGGgRs4f%0AcpeaO%2Fc6fVOCOaZn6kI%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2599493853/e2507f53cce8a26776a22a457b1a/bd79bb8a-b078-420f-a4e1-75590367aa80?expires=1793691900&signature=8c815d23ff6713eb87d13d68fd0a7414df2a1856bd3421db988031ee9357c519&req=diUuH813nolaWvMW1HO4zQTtEhb3zUExSBGfF3I2bRi5fZ6GAvOqdKjdS7oi%0A1w7SyrXu2evO%2BeDgzy4%3D%0A) ## What happens when you delete a conversation diff --git a/content/support/8325618-paid-plan-billing-faqs.md b/content/support/8325618-paid-plan-billing-faqs.md index 3d7360996b..c4b12ecd68 100644 --- a/content/support/8325618-paid-plan-billing-faqs.md +++ b/content/support/8325618-paid-plan-billing-faqs.md @@ -22,7 +22,7 @@ Additionally, all invoices are automatically emailed to your billing email addre 2. Navigate to **[Settings > Billing](https://claude.ai/settings/billing)**. -3. Click the "Update" button next to your payment method. +3. Click the "Update" button next to your default payment method. 4. Enter your new billing details in the payment update form. @@ -36,21 +36,25 @@ To change the card on your Pro, Max, or Ultra subscription: 1. Navigate to **[Settings > Billing](https://claude.ai/settings/billing)**. -2. Click the “Update” button next to your payment method. +2. Click the “Update” button next to your default payment method. 3. Enter your new card details. 4. Click “Update” to save your changes. -The new card becomes your default payment method, and all future subscription renewals are charged to it. Your previous card is no longer billed. +The new card becomes your default payment method and is charged for future renewals. Your previous card stays saved and usually still appears in your list of payment methods in **Settings > Billing** until you remove it. Depending on your account, a saved card may be charged if your default card is declined, so remove any card you don't want used. -There's no separate option to remove a card, and updating to a new card replaces the old one for billing purposes. The billing page only shows your current default card. Previously used cards are no longer charged, but they may remain stored with our payment processor. If you need a previous card fully removed from your account, please contact **[our support team](https://support.claude.com/en/articles/9015913-how-to-get-support)**. +You can also click "Add payment method" there to save another card, or open the three-dot menu (More actions) next to a saved card and choose "Set as default" to make it your default. + +To remove a saved card, open the three-dot menu (More actions) next to it, then choose "Remove". Your default payment method can't be removed, so you need to make another card the default first. You also can't remove a card while your subscription or an unpaid invoice is still using it. + +A removed card isn't used for future renewals or auto-reload unless you add it back. Some cards you used in the past may not appear in the list but can remain stored with our payment processor. If you need one of those removed, or need to remove your only card, please contact **[our support team](https://support.claude.com/en/articles/9015913-how-to-get-support)**. ## How can I use a different name on my invoices? If you want to use a name other than the one tied to your payment method, check the "Use a different name on invoices" box when adding or updating your payment method in **[Settings > Billing](https://claude.ai/settings/billing)**. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1922141785/666191101c11030b05f03a668a74/image.png?expires=1793653200&signature=61a9f0308b708935ebae3ab1e19321040438a2364b365eee6348a8e998a8fb6a&req=dSklFMh6nIZXXPMW1HO4zVXW8W6tbjDOQoNvNFTb5cf8KXGgbkUybnaCI0DC%0A5ATtx3ApOMYHNaRIOGI%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1922141785/666191101c11030b05f03a668a74/image.png?expires=1793793600&signature=3c2f06116130f5f785da259b976721a2514772d5d69b193f44ef7fdd4309957e&req=dSklFMh6nIZXXPMW3nq%2BgWIvYv5NddvgbZWMNUDbBxNrPaxDc1fCzcCB%2BuI4%0A3PDoI8woeabtYEET%2FT8Jk6qxHdo%3D%0A) ## How can I edit a paid invoice? diff --git a/content/support/8887527-customizing-your-appearance-settings.md b/content/support/8887527-customizing-your-appearance-settings.md index 686027527d..cb93b5b56d 100644 --- a/content/support/8887527-customizing-your-appearance-settings.md +++ b/content/support/8887527-customizing-your-appearance-settings.md @@ -8,7 +8,7 @@ 3. Select from Light, Match System, and Dark under **Color mode**. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1648260417/d478c757c7115ad58a12026d4caf/AD_4nXc__Qop4X9hknWGfGj_y_DCpLutLruhxIclJIfir0ilsgNMg7X8ksIVnqk1Oce5FKlGIOYu9CKbVsu8DqD7iIY2aC0ZfXMyFTeAdNq-Cao2mXcj_WUpNF0kM2HoYR_dEx6N_cuJow?expires=1793653200&signature=250f882051790f7682c1ff9f597e2307f490708e243d569d75b0569d563fe0a5&req=dSYjHst4nYVeXvMW1HO4zc2jJqE7hYjmSBkgeTglJrpDg2eiM8AtLNIpzJkl%0AsY5xi386%2FFNI7cjAOss%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1648260417/d478c757c7115ad58a12026d4caf/AD_4nXc__Qop4X9hknWGfGj_y_DCpLutLruhxIclJIfir0ilsgNMg7X8ksIVnqk1Oce5FKlGIOYu9CKbVsu8DqD7iIY2aC0ZfXMyFTeAdNq-Cao2mXcj_WUpNF0kM2HoYR_dEx6N_cuJow?expires=1793691900&signature=0dea7ae57717f353d4ce4b53386452b622ae252febe7e9aba50af09dcc8e7177&req=dSYjHst4nYVeXvMW1HO4zc2jJqE7iYrtSBkgeTglJrqA8VHWYL1X5njy8yE1%0Aw%2F1L1bz7wvp6zGd5ho4%3D%0A) ## How to change your font @@ -16,10 +16,10 @@ 2. Select from Default, Match System, and Dyslexic Friendly. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1648260416/7fc0803d44d8de40f8e6636b2eb6/AD_4nXf0UEDa1i2QmqlQtoB5BgpQ-FfZVzss_7wMVQdvkmEDSfoTxixnG0GSxC6qrOs21HdkXH-I2Yn_GHDAf8yjd6FJtoh9FadALozvIErFp9r8LychDGLPb7OpN1CN4PRcgVAYNCre?expires=1793653200&signature=f974ab2eb40f71c7c48c7b6c25b2852eb21da4b80a255f3ed755ab92a5b26526&req=dSYjHst4nYVeX%2FMW1HO4zc896mPjWHI%2BQtNFlF5%2FHEe8bMl5H2T2JZdSRatt%0AFffq9cQlkUeZiM9yreg%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1648260416/7fc0803d44d8de40f8e6636b2eb6/AD_4nXf0UEDa1i2QmqlQtoB5BgpQ-FfZVzss_7wMVQdvkmEDSfoTxixnG0GSxC6qrOs21HdkXH-I2Yn_GHDAf8yjd6FJtoh9FadALozvIErFp9r8LychDGLPb7OpN1CN4PRcgVAYNCre?expires=1793691900&signature=139f123363308626c34f9695ab4ef4cece6337a37e0a16be384b0a4b6f67cd18&req=dSYjHst4nYVeX%2FMW1HO4zc896mPjVHA1QtNFlF5%2FHEeuflqfWjYTqxtKHqmL%0AgiLi01jdSuyjzeLrYQc%3D%0A) ## Can I disable the sidebar? It's not currently possible to completely disable the sidebar. You can click the button on the top right of the sidebar to open or close it. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1941108004/5217903737ddd9bb62fe5d7a904c/CleanShot+2026-01-14+at+09_12_58.png?expires=1793653200&signature=166439e2b4980cbbff919d8a35bcf1317de43cff4c92b6633e7811eff8f666af&req=dSkjF8h%2BlYFfXfMW1HO4zUS%2BBlzwXHjtylfYa7uDb9nwwvglXyAviyuRjleu%0AhDm0%2BWhPBn%2F9lCNa87I%3D%0A) \ No newline at end of file +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1941108004/5217903737ddd9bb62fe5d7a904c/CleanShot+2026-01-14+at+09_12_58.png?expires=1793691900&signature=547a1724ca070a04f53ecbf782b192d5e60687ac1008726ec7ec6c55f033f448&req=dSkjF8h%2BlYFfXfMW1HO4zUS%2BBlzwUHrmylfYa7uDb9ktrzFiw5xzsnxzPLox%0AOWd6vlcQ3o19TDF%2B1hc%3D%0A) \ No newline at end of file diff --git a/content/support/9267400-move-your-personal-claude-account-to-a-team-or-enterprise-organization.md b/content/support/9267400-move-your-personal-claude-account-to-a-team-or-enterprise-organization.md index ea0ae89069..2192befdf4 100644 --- a/content/support/9267400-move-your-personal-claude-account-to-a-team-or-enterprise-organization.md +++ b/content/support/9267400-move-your-personal-claude-account-to-a-team-or-enterprise-organization.md @@ -132,7 +132,7 @@ For the full walkthrough of your options, deadlines, and what happens to your su You may have both a personal account and an organization account tied to the same email address. You can switch between them by clicking your initials or name in the lower left corner of the screen. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2312193347/712f763fc290b2488c103849f20c/0c135a6f-3442-4ee1-9ab7-98673f03ef6e?expires=1793653200&signature=042ac6cfeda0c0325fd2d5e944bd7e716933d7c8defeb305c145ca5bd9ac89ed&req=diMmFMh3noJbXvMW1HO4zXhPnNMwzRxjufhmlOXMdYaR29eRFILmYHoW9nfL%0A7KY%2B9drQhszHvH9cjRg%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/2312193347/712f763fc290b2488c103849f20c/0c135a6f-3442-4ee1-9ab7-98673f03ef6e?expires=1793691900&signature=905e005569aa326fefb627204a27d1004767ac416e73f6c7773bb1168f4b1d8d&req=diMmFMh3noJbXvMW1HO4zXhPnNMwwR5oufhmlOXMdYaQSftM8qDwv9kPE9ni%0AoHjiOwmqBfP1pj3lHgs%3D%0A) A blue checkmark shows which account you're currently using. Click the other account to switch to it and access its separate conversations and projects. diff --git a/content/support/9519177-how-can-i-create-and-manage-projects.md b/content/support/9519177-how-can-i-create-and-manage-projects.md index b9c9930b2c..9822165c29 100644 --- a/content/support/9519177-how-can-i-create-and-manage-projects.md +++ b/content/support/9519177-how-can-i-create-and-manage-projects.md @@ -104,15 +104,15 @@ Starring a project allows for quick access from your projects and chats list, vi You can move a standalone chat into a project by clicking on the dropdown arrow next to the chat name, then “Add to project”: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1784190248/0f19c8de18b494a27be252fdfaff/d4e7a5c5-25f5-4623-862b-c593d2dc0b39?expires=1793653200&signature=992dd7a4fb6253003bc694ba6940538b7128b10a0a01b1cea8d4617802e92128&req=dScvEsh3nYNbUfMW1HO4zQABaGJqT6MXBSXNVFXQ%2FVEjv0EXEN5fI7kbh5nV%0A2x6MMlRq8GyxNNC8dAI%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1784190248/0f19c8de18b494a27be252fdfaff/d4e7a5c5-25f5-4623-862b-c593d2dc0b39?expires=1793691900&signature=6d0e7c1eb6468e481b850c9286bc2436792a83e29bc49c14f5e4e4024ac2fdce&req=dScvEsh3nYNbUfMW1HO4zQABaGJqQ6EcBSXNVFXQ%2FVFvRQSjcZZc%2FS1NBz61%0Acysz%2FIix1a7AWxZvxrE%3D%0A) Browse or search for the correct project in the **Move chat** modal that appears, then click on it to move the chat. -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1784190951/34dc256ccd4c0cf74976f31062e6/55365cf2-059d-41b2-ac95-4b00c4389a76?expires=1793653200&signature=8897e562c6ab8968005a5b1c6864b55d2677faa7051eb7dfc42098ccbd7e62b2&req=dScvEsh3nYhaWPMW1HO4zSMECyO2zgoDgYbpTjViBxC68uqsg4xCialaV7Tn%0Aq8AeppV%2F%2Fhz1%2BOuqAHA%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1784190951/34dc256ccd4c0cf74976f31062e6/55365cf2-059d-41b2-ac95-4b00c4389a76?expires=1793691900&signature=9f3f4da06c1be766aa29e627b7eebdf3be762e0bd020aff29f8c9f3f115bb546&req=dScvEsh3nYhaWPMW1HO4zSMECyO2wggIgYbpTjViBxC4W49ylDbzQXr26rxd%0Amp6ZK313n49OGJjDqks%3D%0A) You can also remove chats from projects, or move them between projects, using the same dropdown menu within the chat: -![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1784185682/8625eac15b9fa452f148a6c47250/c53a1bc4-a991-4684-a789-5447ed789d35?expires=1793653200&signature=330162ff14725d43db316f82c7546965268b5d05fe5471bf531249189e3475f0&req=dScvEsh2mIdXW%2FMW1HO4zb6DufQqC0YIS2r1%2FGRlqORcwzEpxNGaTJfL7wG8%0AyJg4K6NVYvmaQElLPA8%3D%0A) +![](https://downloads.intercomcdn.com/i/o/lupk8zyo/1784185682/8625eac15b9fa452f148a6c47250/c53a1bc4-a991-4684-a789-5447ed789d35?expires=1793691900&signature=79dfa610ddf3475eee6d5e44957fa74842bc2eba898d4c6f25024038b9e657b4&req=dScvEsh2mIdXW%2FMW1HO4zb6DufQqB0QDS2r1%2FGRlqORk%2F1%2BSWXuws46bicCl%0ASP4t71JUV1wX6SyPfKQ%3D%0A) --- diff --git a/discovery.json b/discovery.json index a74592f3a3..f0439cb43d 100644 --- a/discovery.json +++ b/discovery.json @@ -1,7 +1,7 @@ { "version": 1, "note": "What the last full run could see outside sources.json. Written by the fetcher so a new source arrives as a diff a human reviews, not as a line in an Actions log nobody reads. Stable facts only: a change here is always news. `review` is the actionable list \u2014 domains we could archive today and do not.", - "updated": "2026-11-02", + "updated": "2026-11-03", "domains": { "anthropic.com": { "status": "frozen", @@ -73,6 +73,7 @@ ], "not_fetched": [ "anthropics/ClaudeForFoundationModels", + "anthropics/FlashProve", "anthropics/OpenROAD-flow-scripts", "anthropics/agent-sdk-workshop", "anthropics/amulet2", diff --git a/tombstones.json b/tombstones.json index c95ba66702..88721d58bb 100644 --- a/tombstones.json +++ b/tombstones.json @@ -1,7 +1,7 @@ { "version": 1, "note": "URLs confirmed gone upstream. Kept so a page that died once does not report as a fresh failure on every later run, which would bury the failure that is actually new. An entry clears itself if the URL answers again -- but only while something still probes it. Entries whose local file was removed are no longer fetched, so they stay as a record of the restructure rather than a live check.", - "updated": "2026-11-02", + "updated": "2026-11-03", "urls": { "https://claude.com/docs/claude-science/annotations": { "since": "2026-09-01",