({
messages,
totalTokens,
contextWindow,
maxTokens,
apiHandler,
autoCondenseContext,
autoCondenseContextPercent,
systemPrompt,
taskId,
customCondensingPrompt,
profileThresholds,
currentProfileId,
metadata,
environmentDetails,
filesReadByRoo,
cwd,
rooIgnoreController,
useAvailableInputForContextPercent,
}: ContextManagementOptions)
| 289 | * @returns {Promise<ApiMessage[]>} The original, condensed, or truncated conversation messages. |
| 290 | */ |
| 291 | export async function manageContext({ |
| 292 | messages, |
| 293 | totalTokens, |
| 294 | contextWindow, |
| 295 | maxTokens, |
| 296 | apiHandler, |
| 297 | autoCondenseContext, |
| 298 | autoCondenseContextPercent, |
| 299 | systemPrompt, |
| 300 | taskId, |
| 301 | customCondensingPrompt, |
| 302 | profileThresholds, |
| 303 | currentProfileId, |
| 304 | metadata, |
| 305 | environmentDetails, |
| 306 | filesReadByRoo, |
| 307 | cwd, |
| 308 | rooIgnoreController, |
| 309 | useAvailableInputForContextPercent, |
| 310 | }: ContextManagementOptions): Promise<ContextManagementResult> { |
| 311 | let error: string | undefined |
| 312 | let errorDetails: string | undefined |
| 313 | let cost = 0 |
| 314 | // Calculate the maximum tokens reserved for response |
| 315 | // vscode-lm reports maxTokens: -1 (unlimited); a negative reserve must not distort the window math. |
| 316 | const reservedTokens = maxTokens && maxTokens > 0 ? maxTokens : ANTHROPIC_DEFAULT_MAX_TOKENS |
| 317 | |
| 318 | // Estimate tokens for the last message (which is always a user message) |
| 319 | const lastMessage = messages[messages.length - 1] |
| 320 | const lastMessageContent = lastMessage.content |
| 321 | const lastMessageTokens = Array.isArray(lastMessageContent) |
| 322 | ? await estimateTokenCount(lastMessageContent, apiHandler) |
| 323 | : await estimateTokenCount([{ type: "text", text: lastMessageContent as string }], apiHandler) |
| 324 | |
| 325 | // Calculate total effective tokens (totalTokens never includes the last message) |
| 326 | const prevContextTokens = totalTokens + lastMessageTokens |
| 327 | |
| 328 | // Calculate available tokens for conversation history |
| 329 | // Truncate if we're within TOKEN_BUFFER_PERCENTAGE of the context window |
| 330 | const allowedTokens = contextWindow * (1 - TOKEN_BUFFER_PERCENTAGE) - reservedTokens |
| 331 | |
| 332 | // Determine the effective threshold to use |
| 333 | let effectiveThreshold = autoCondenseContextPercent |
| 334 | const profileThreshold = profileThresholds[currentProfileId] |
| 335 | if (profileThreshold !== undefined) { |
| 336 | if (profileThreshold === -1) { |
| 337 | // Special case: -1 means inherit from global setting |
| 338 | effectiveThreshold = autoCondenseContextPercent |
| 339 | } else if (profileThreshold >= MIN_CONDENSE_THRESHOLD && profileThreshold <= MAX_CONDENSE_THRESHOLD) { |
| 340 | // Valid custom threshold |
| 341 | effectiveThreshold = profileThreshold |
| 342 | } else { |
| 343 | // Invalid threshold value, fall back to global setting |
| 344 | console.warn( |
| 345 | `Invalid profile threshold ${profileThreshold} for profile "${currentProfileId}". Using global default of ${autoCondenseContextPercent}%`, |
| 346 | ) |
| 347 | effectiveThreshold = autoCondenseContextPercent |
| 348 | } |
no test coverage detected