Path: blob/main/extensions/copilot/src/platform/networking/common/anthropic.ts
13401 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { ConfigKey, IConfigurationService } from '../../configuration/common/configurationService';6import { modelSupportsContextEditing } from '../../endpoint/common/chatModelCapabilities';7import { IExperimentationService } from '../../telemetry/common/nullExperimentationService';8import { IChatEndpoint } from './networking';910/**11* Types for Anthropic Messages API12* Based on https://platform.claude.com/docs/en/api/messages13*14* This interface supports both regular tools and server tools (web search, tool search):15* - Regular tools: require name, description, and input_schema16* - Tool search tools: require only type and name17*/18export interface AnthropicMessagesTool {19name: string;20type?: string;21description?: string;22input_schema?: {23type: 'object';24properties?: Record<string, unknown>;25required?: string[];26};27defer_loading?: boolean;28cache_control?: { type: 'ephemeral' };29}3031/** Name for the custom client-side embeddings-based tool search tool. Must not use copilot_/vscode_ prefix — those are reserved for static package.json declarations and will be rejected by vscode.lm.registerToolDefinition. */32export const CUSTOM_TOOL_SEARCH_NAME = 'tool_search';3334/**35* Context management types for Anthropic Messages API36* Based on https://platform.claude.com/docs/en/build-with-claude/context-editing37*/38export type ContextManagementTrigger =39| { type: 'input_tokens'; value: number }40| { type: 'tool_uses'; value: number };4142export type ContextManagementKeep =43| { type: 'tool_uses'; value: number }44| { type: 'thinking_turns'; value: number }45| 'all';4647export type ContextManagementClearAtLeast = {48type: 'input_tokens';49value: number;50};5152export interface ClearToolUsesEdit {53type: 'clear_tool_uses_20250919';54trigger?: ContextManagementTrigger;55keep?: ContextManagementKeep;56clear_at_least?: ContextManagementClearAtLeast;57exclude_tools?: string[];58clear_tool_inputs?: boolean;59}6061export interface ClearThinkingEdit {62type: 'clear_thinking_20251015';63keep?: ContextManagementKeep;64}6566export type ContextManagementEdit = ClearToolUsesEdit | ClearThinkingEdit;6768export interface ContextManagement {69edits: ContextManagementEdit[];70}7172export interface AppliedContextEdit {73type: 'clear_thinking_20251015' | 'clear_tool_uses_20250919';74cleared_thinking_turns?: number;75cleared_tool_uses?: number;76cleared_input_tokens?: number;77}7879export interface ContextManagementResponse {80applied_edits: AppliedContextEdit[];81}8283/**84* Interleaved thinking is supported by:85* - Claude Sonnet 4.5 (claude-sonnet-4-5-* or claude-sonnet-4.5-*)86* - Claude Sonnet 4 (claude-sonnet-4-*)87* - Claude Haiku 4.5 (claude-haiku-4-5-* or claude-haiku-4.5-*)88* - Claude Opus 4.5 (claude-opus-4-5-* or claude-opus-4.5-*)89* @param modelId The model ID to check90* @returns true if the model supports interleaved thinking91*/92export function modelSupportsInterleavedThinking(modelId: string): boolean {93// Normalize: lowercase and replace dots with dashes so "4.5" matches "4-5"94const normalized = modelId.toLowerCase().replace(/\./g, '-');95return normalized.startsWith('claude-sonnet-4-5') ||96normalized.startsWith('claude-sonnet-4') ||97normalized.startsWith('claude-haiku-4-5') ||98normalized.startsWith('claude-opus-4-5');99}100101/**102* Memory is supported by:103* - Claude Haiku 4.5 (claude-haiku-4-5-* or claude-haiku-4.5-*)104* - Claude Sonnet 4.6 (claude-sonnet-4-6-* or claude-sonnet-4.6-*)105* - Claude Sonnet 4.5 (claude-sonnet-4-5-* or claude-sonnet-4.5-*)106* - Claude Sonnet 4 (claude-sonnet-4-*)107* - Claude Opus 4.6 (claude-opus-4-6-* or claude-opus-4.6-*)108* - Claude Opus 4.5 (claude-opus-4-5-* or claude-opus-4.5-*)109* - Claude Opus 4.1 (claude-opus-4-1-* or claude-opus-4.1-*)110* - Claude Opus 4 (claude-opus-4-*)111* @param modelId The model ID to check112* @returns true if the model supports memory113*/114export function modelSupportsMemory(modelId: string): boolean {115const normalized = modelId.toLowerCase().replace(/\./g, '-');116return normalized.startsWith('claude-haiku-4-5') ||117normalized.startsWith('claude-sonnet-4-6') ||118normalized.startsWith('claude-sonnet-4-5') ||119normalized.startsWith('claude-sonnet-4') ||120normalized.startsWith('claude-opus-4-6') ||121normalized.startsWith('claude-opus-4-5') ||122normalized.startsWith('claude-opus-4-1') ||123normalized.startsWith('claude-opus-4');124}125126export function isAnthropicContextEditingEnabled(127endpoint: IChatEndpoint | string,128configurationService: IConfigurationService,129experimentationService: IExperimentationService,130): boolean {131const supportsIt = typeof endpoint === 'string'132? modelSupportsContextEditing(endpoint)133: endpoint.supportsContextEditing ?? modelSupportsContextEditing(endpoint.model);134if (!supportsIt) {135return false;136}137const mode = configurationService.getExperimentBasedConfig(ConfigKey.AnthropicContextEditingMode, experimentationService);138return mode !== 'off';139}140141export function isAnthropicMemoryToolEnabled(142endpoint: IChatEndpoint | string,143configurationService: IConfigurationService,144experimentationService: IExperimentationService,145): boolean {146const effectiveModelId = typeof endpoint === 'string' ? endpoint : endpoint.model;147if (!modelSupportsMemory(effectiveModelId)) {148return false;149}150return configurationService.getExperimentBasedConfig(ConfigKey.MemoryToolEnabled, experimentationService);151}152153export type ContextEditingMode = 'off' | 'clear-thinking' | 'clear-tooluse' | 'clear-both';154155/**156* Builds the context_management configuration object for the Messages API request.157* @param mode The context editing mode158* @param thinkingEnabled Whether extended thinking is enabled159* @returns The context_management object to include in the request, or undefined if off or no edits160*/161export function buildContextManagement(162mode: ContextEditingMode,163thinkingEnabled: boolean164): ContextManagement | undefined {165if (mode === 'off') {166return undefined;167}168169const edits: ContextManagementEdit[] = [];170171// Add thinking block clearing for clear-thinking and clear-both modes172if ((mode === 'clear-thinking' || mode === 'clear-both') && thinkingEnabled) {173edits.push({174type: 'clear_thinking_20251015',175keep: { type: 'thinking_turns', value: 1 },176});177}178179// Add tool result clearing for clear-tooluse and clear-both modes180if (mode === 'clear-tooluse' || mode === 'clear-both') {181edits.push({182type: 'clear_tool_uses_20250919',183trigger: { type: 'input_tokens', value: 100000 },184keep: { type: 'tool_uses', value: 3 },185});186}187188return edits.length > 0 ? { edits } : undefined;189}190191/**192* Reads context editing mode from settings and builds the context_management object.193* @param configurationService The configuration service to read settings from194* @param experimentationService The experimentation service195* @param thinkingEnabled Whether extended thinking is enabled196* @returns The context_management object to include in the request, or undefined if disabled197*/198export function getContextManagementFromConfig(199configurationService: IConfigurationService,200experimentationService: IExperimentationService,201thinkingEnabled: boolean,202): ContextManagement | undefined {203const mode = configurationService.getExperimentBasedConfig(ConfigKey.AnthropicContextEditingMode, experimentationService);204return buildContextManagement(mode, thinkingEnabled);205}206207208